mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
bug 588 (text justification) for Robert O'Callahan <roc+moz@cs.cmu.edu>
r=buster bug 18545 ([FLOAT] Problem Centering <TABLE> with <DIV> tag) r=troy bugs 18827, 19579, 22327 24782, 26512, 30124, 31849, 32846 (floater behavior wrong) The primary change here is to determine if a block is impacted by a floater, and if so mark the block's lines dirty when appropriate. r=troy no bug number. performance work. reduced the size of some reflow data structures by collapsing multiple fields into a single bit field. r=troy
This commit is contained in:
parent
ee58499ab3
commit
f40b76249a
@ -3874,6 +3874,9 @@ FindTopFrame(nsIFrame* aRoot)
|
||||
PRBool
|
||||
PresShell::VerifyIncrementalReflow()
|
||||
{
|
||||
if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
|
||||
printf("Building Verification Tree...\n");
|
||||
}
|
||||
// All the stuff we are creating that needs releasing
|
||||
nsIPresContext* cx;
|
||||
nsIViewManager* vm;
|
||||
@ -3976,6 +3979,9 @@ PresShell::VerifyIncrementalReflow()
|
||||
vm->SetViewObserver((nsIViewObserver *)((PresShell*)sh));
|
||||
sh->InitialReflow(r.width, r.height);
|
||||
sh->SetVerifyReflowEnable(PR_TRUE); // turn on verify reflow again now that we're done reflowing the test frame tree
|
||||
if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
|
||||
printf("Verification Tree built, comparing...\n");
|
||||
}
|
||||
|
||||
// Now that the document has been reflowed, use its frame tree to
|
||||
// compare against our frame tree.
|
||||
@ -3999,15 +4005,15 @@ PresShell::VerifyIncrementalReflow()
|
||||
}
|
||||
}
|
||||
|
||||
// printf("Incremental reflow doomed view tree:\n");
|
||||
// view->List(stdout, 1);
|
||||
// view->SetVisibility(nsViewVisibility_kHide);
|
||||
cx->Stop();
|
||||
cx->SetContainer(nsnull);
|
||||
NS_RELEASE(cx);
|
||||
sh->EndObservingDocument();
|
||||
NS_RELEASE(sh);
|
||||
NS_RELEASE(vm);
|
||||
if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
|
||||
printf("Finished Verifying Reflow...\n");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -81,6 +81,10 @@ nsBlockBandData::GetAvailableSpace(nscoord aY, nsRect& aResult)
|
||||
// between any left and right floaters.
|
||||
ComputeAvailSpaceRect();
|
||||
aResult = mAvailSpace;
|
||||
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
|
||||
printf("nsBBD %p GetAvailableSpace(%d) returing (%d, %d, %d, %d)\n",
|
||||
this, aY, aResult.x, aResult.y, aResult.width, aResult.height);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -134,7 +138,7 @@ void
|
||||
nsBlockBandData::ComputeAvailSpaceRect()
|
||||
{
|
||||
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
|
||||
printf("nsBlockBandData::ComputeAvailSpaceRect %p \n", this);
|
||||
printf("nsBlockBandData::ComputeAvailSpaceRect %p with count %d\n", this, mCount);
|
||||
#endif
|
||||
if (0 == mCount) {
|
||||
mAvailSpace.x = 0;
|
||||
@ -248,6 +252,11 @@ nsBlockBandData::ComputeAvailSpaceRect()
|
||||
if (NS_UNCONSTRAINEDSIZE == mSpace.width) {
|
||||
mAvailSpace.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
|
||||
printf(" ComputeAvailSpaceRect settting state mAvailSpace (%d,%d,%d,%d)\n",
|
||||
mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -471,3 +480,15 @@ nsBlockBandData::GetMaxElementSize(nsIPresContext* aPresContext,
|
||||
*aWidthResult = maxWidth;
|
||||
*aHeightResult = maxHeight;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void nsBlockBandData::List()
|
||||
{
|
||||
printf("nsBlockBandData %p sm=%p, sm coord = (%d,%d), mSpace = (%d,%d)\n",
|
||||
this, mSpaceManager, mSpaceManagerX, mSpaceManagerY,
|
||||
mSpace.width, mSpace.height);
|
||||
printf(" availSpace=(%d, %d, %d, %d), floaters l=%d r=%d\n",
|
||||
mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height,
|
||||
mLeftFloaters, mRightFloaters);
|
||||
}
|
||||
#endif
|
||||
|
@ -89,6 +89,10 @@ public:
|
||||
nsIFrame* aFrame,
|
||||
nsSize* aResult);
|
||||
|
||||
#ifdef DEBUG
|
||||
void List();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
/** utility method to calculate the band data at aY.
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
@ -61,6 +63,8 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
//#define NOISY_BLOCK_INVALIDATE // DO NOT CHECK THIS IN TURNED ON!
|
||||
|
||||
static PRBool gLamePaintMetrics;
|
||||
static PRBool gLameReflowMetrics;
|
||||
static PRBool gNoisy;
|
||||
@ -451,12 +455,6 @@ public:
|
||||
|
||||
nscoord mBottomEdge;
|
||||
|
||||
PRPackedBool mUnconstrainedWidth;
|
||||
PRPackedBool mUnconstrainedHeight;
|
||||
PRPackedBool mShrinkWrapWidth;
|
||||
PRPackedBool mNeedResizeReflow;
|
||||
PRPackedBool mIsInlineIncrReflow;
|
||||
|
||||
// The content area to reflow child frames within. The x/y
|
||||
// coordinates are known to be mBorderPadding.left and
|
||||
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
||||
@ -464,15 +462,6 @@ public:
|
||||
// unconstrained area.
|
||||
nsSize mContentArea;
|
||||
|
||||
// Our wrapping behavior
|
||||
PRPackedBool mNoWrap;
|
||||
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRPackedBool mIsTopMarginRoot, mIsBottomMarginRoot;
|
||||
|
||||
// See ShouldApplyTopMargin
|
||||
PRPackedBool mApplyTopMargin;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
@ -541,15 +530,48 @@ public:
|
||||
// being N^2.
|
||||
nsFloaterCacheFreeList mBelowCurrentLineFloaters;
|
||||
|
||||
PRPackedBool mComputeMaxElementSize;
|
||||
PRPackedBool mComputeMaximumWidth;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
nscoord mMaximumWidth;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
|
||||
// block reflow state flags
|
||||
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
||||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
@ -574,29 +596,25 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
mNeedResizeReflow(PR_FALSE),
|
||||
mIsInlineIncrReflow(PR_FALSE),
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
mLineNumber(0),
|
||||
mFlags(0)
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (mIsTopMarginRoot) {
|
||||
mApplyTopMargin = PR_TRUE;
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
}
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
@ -617,21 +635,19 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Compute content area width (the content area is inside the border
|
||||
// and padding)
|
||||
mUnconstrainedWidth = PR_FALSE;
|
||||
mShrinkWrapWidth = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
||||
mContentArea.width = aReflowState.mComputedWidth;
|
||||
}
|
||||
else {
|
||||
if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
|
||||
mContentArea.width = NS_UNCONSTRAINEDSIZE;
|
||||
mUnconstrainedWidth = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
}
|
||||
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
||||
// Choose a width based on the content (shrink wrap width) up
|
||||
// to the maximum width
|
||||
mContentArea.width = aReflowState.mComputedMaxWidth;
|
||||
mShrinkWrapWidth = PR_TRUE;
|
||||
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
|
||||
}
|
||||
else {
|
||||
nscoord lr = borderPadding.left + borderPadding.right;
|
||||
@ -646,7 +662,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
// specified style height then we may end up limiting our height if
|
||||
// the availableHeight is constrained (this situation occurs when we
|
||||
// are paginated).
|
||||
mUnconstrainedHeight = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
||||
// We are in a paginated situation. The bottom edge is just inside
|
||||
// the bottom border and padding. The content area height doesn't
|
||||
@ -657,7 +672,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
else {
|
||||
// When we are not in a paginated situation then we always use
|
||||
// an constrained height.
|
||||
mUnconstrainedHeight = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
|
||||
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
|
||||
@ -674,16 +689,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
switch (styleText->mWhiteSpace) {
|
||||
case NS_STYLE_WHITESPACE_PRE:
|
||||
case NS_STYLE_WHITESPACE_NOWRAP:
|
||||
mNoWrap = PR_TRUE;
|
||||
SetFlag(BRS_NOWRAP, PR_TRUE);
|
||||
break;
|
||||
default:
|
||||
mNoWrap = PR_FALSE;
|
||||
SetFlag(BRS_NOWRAP, PR_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
mComputeMaximumWidth = NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH);
|
||||
SetFlag(BRS_COMPUTEMAXWIDTH,
|
||||
(NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
|
||||
mMaximumWidth = 0;
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
@ -729,8 +745,12 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
|
||||
mBand.List();
|
||||
#endif
|
||||
aResult.y = mY;
|
||||
aResult.height = mUnconstrainedHeight
|
||||
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mBottomEdge - mY;
|
||||
|
||||
@ -749,7 +769,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// The child block will flow around the floater. Therefore
|
||||
// give it all of the available space.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
break;
|
||||
@ -776,7 +796,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
// determine width
|
||||
if (mUnconstrainedWidth) {
|
||||
if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aResult.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -810,7 +830,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// doesn't matter therefore give the block element all of the
|
||||
// available space since it will flow around the floater itself.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
}
|
||||
@ -957,12 +977,12 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
|
||||
#endif
|
||||
mKidXMost = xmost;
|
||||
}
|
||||
if (mComputeMaxElementSize) {
|
||||
if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
||||
}
|
||||
|
||||
// If computing the maximum width, then update mMaximumWidth
|
||||
if (mComputeMaximumWidth) {
|
||||
if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
}
|
||||
|
||||
@ -1454,6 +1474,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
||||
NS_BLOCK_MARGIN_ROOT & mState);
|
||||
PRInt32 sizeofBRS = sizeof nsBlockReflowState;
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
RenumberLists(aPresContext);
|
||||
@ -1462,7 +1483,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
PRBool isStyleChange = PR_FALSE;
|
||||
state.mIsInlineIncrReflow = PR_FALSE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_FALSE);
|
||||
nsIFrame* target;
|
||||
switch (aReflowState.reason) {
|
||||
case eReflowReason_Initial:
|
||||
@ -1535,7 +1556,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// reflow the line containing the target of the incr. reflow
|
||||
// first mark the line dirty and set up the state object
|
||||
rv = PrepareChildIncrementalReflow(state);
|
||||
state.mIsInlineIncrReflow = PR_TRUE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
state.mPrevLine = prevLine;
|
||||
state.mCurrentLine = line;
|
||||
state.mNextRCFrame = state.mNextRCFrame;
|
||||
@ -1681,6 +1702,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
if (isStyleChange) {
|
||||
// Lots of things could have changed so damage our entire
|
||||
// bounds
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 1 (%d, %d, %d, %d)\n",
|
||||
this, 0, 0, mRect.width, mRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height));
|
||||
|
||||
} else {
|
||||
@ -1707,6 +1732,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = 0;
|
||||
damageRect.height = mRect.height;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 2 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
|
||||
@ -1730,6 +1759,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = mRect.height - border.bottom;
|
||||
damageRect.height = border.bottom;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 3 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -1868,7 +1901,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
||||
aState.mY, aState.mIsBottomMarginRoot ? "yes" : "no",
|
||||
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
||||
aState.mPrevBottomMargin,
|
||||
borderPadding.top, borderPadding.bottom);
|
||||
#endif
|
||||
@ -1946,7 +1979,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// contents or we fluff out to the maximum block width. Note:
|
||||
// We always shrink wrap when given an unconstrained width.
|
||||
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
|
||||
!aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
|
||||
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && !aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
||||
!compact) {
|
||||
// Set our width to the max width if we aren't already that
|
||||
// wide. Note that the max-width has nothing to do with our
|
||||
@ -1956,9 +1989,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// See if we should compute our max element size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Adjust the computedWidth
|
||||
if (aState.mNoWrap) {
|
||||
if (aState.GetFlag(BRS_NOWRAP)) {
|
||||
// When no-wrap is true the max-element-size.width is the
|
||||
// width of the widest line plus the right border. Note that
|
||||
// aState.mKidXMost already has the left border factored in
|
||||
@ -1996,7 +2029,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// need to do horizontal alignment of the inline lines and make sure
|
||||
// blocks are correctly sized and positioned. Any lines that need
|
||||
// final adjustment will have been marked as dirty
|
||||
if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
|
||||
// If the parent reflow state is also shrink wrap width, then
|
||||
// we don't need to do this, because it will reflow us after it
|
||||
// calculates the final width
|
||||
@ -2025,7 +2058,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
}
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
||||
if (aReflowState.parentReflowState) {
|
||||
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
||||
@ -2047,7 +2080,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// Don't carry out a bottom margin when our height is fixed
|
||||
// unless the bottom of the last line adjoins the bottom of our
|
||||
// content area.
|
||||
if (!aState.mIsBottomMarginRoot) {
|
||||
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
|
||||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
@ -2057,7 +2090,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
@ -2082,7 +2115,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
aMetrics.height = autoHeight;
|
||||
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxHeight = aState.mMaxElementSize.height +
|
||||
borderPadding.top + borderPadding.bottom;
|
||||
}
|
||||
@ -2090,7 +2123,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
aMetrics.descent = 0;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Store away the final value
|
||||
aMetrics.maxElementSize->width = maxWidth;
|
||||
aMetrics.maxElementSize->height = maxHeight;
|
||||
@ -2098,14 +2131,14 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
||||
}
|
||||
if (aState.mComputeMaxElementSize &&
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
||||
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
||||
@ -2115,7 +2148,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
#endif
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
printf("PASS1 ");
|
||||
@ -2130,7 +2163,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// If we're requested to update our maximum width, then compute it
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We need to add in for the right border/padding
|
||||
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
||||
}
|
||||
@ -2337,8 +2370,13 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
// See if we can try and avoid marking all the lines as dirty
|
||||
PRBool tryAndSkipLines = PR_FALSE;
|
||||
|
||||
// See if this is this a constrained resize reflow
|
||||
if ((aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
// we need to calculate if any part of then block itself
|
||||
// is impacted by a floater (bug 19579)
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
// See if this is this a constrained resize reflow that is not impacted by floaters
|
||||
if ((PR_FALSE==aState.IsImpactedByFloater()) &&
|
||||
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
||||
|
||||
// If the text is left-aligned, then we try and avoid reflowing the lines
|
||||
@ -2389,7 +2427,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool notWrapping = aState.mNoWrap;
|
||||
PRBool notWrapping = aState.GetFlag(BRS_NOWRAP);
|
||||
while (nsnull != line) {
|
||||
|
||||
if (line->IsBlock()) {
|
||||
@ -2402,8 +2440,6 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
||||
line, line->IsImpactedByFloater() ? "" : "not ");
|
||||
#endif
|
||||
|
||||
|
||||
if (notWrapping) {
|
||||
// When no-wrap is set then the only line-breaking that
|
||||
// occurs for inline lines is triggered by BR elements or by
|
||||
@ -2430,7 +2466,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
||||
line, line->mNext,
|
||||
line->IsBlock() ? "block" : "inline",
|
||||
aState.mNoWrap ? "no-wrap" : "wrapping",
|
||||
aState.GetFlag(BRS_NOWRAP) ? "no-wrap" : "wrapping",
|
||||
line->HasBreak() ? "has-break " : "",
|
||||
line->HasFloaters() ? "has-floaters " : "",
|
||||
line->IsImpactedByFloater() ? "impacted " : "",
|
||||
@ -2628,7 +2664,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.mIsInlineIncrReflow ? "true" : "false");
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
@ -2651,7 +2687,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// Reflow the lines that are already ours
|
||||
aState.mPrevLine = nsnull;
|
||||
nsLineBox* line = mLines;
|
||||
if (aState.mIsInlineIncrReflow && aState.mNextRCFrame)
|
||||
if (aState.GetFlag(BRS_ISINLINEINCRREFLOW) && aState.mNextRCFrame)
|
||||
{
|
||||
const nsLineBox* incrTargetLine = aState.mCurrentLine;
|
||||
aState.mCurrentLine = line;
|
||||
@ -2662,6 +2698,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 4 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
aState.mPrevLine = line;
|
||||
@ -2689,7 +2729,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// If we're supposed to update our maximum width, then we'll also need to
|
||||
// reflow this line if it's line wrapped and any of the continuing lines
|
||||
// are dirty
|
||||
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
|
||||
if (line->IsDirty() || (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line))) {
|
||||
// Compute the dirty lines "before" YMost, after factoring in
|
||||
// the running deltaY value - the running value is implicit in
|
||||
// aState.mY.
|
||||
@ -2729,6 +2769,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 5 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -2902,6 +2946,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// XXX We need to improve on this...
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
|
||||
} else {
|
||||
@ -2918,6 +2966,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.x;
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
||||
lineCombinedArea.height);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
if (oldCombinedArea.height != lineCombinedArea.height) {
|
||||
@ -2933,6 +2985,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
||||
lineCombinedArea.YMost()) -
|
||||
dirtyRect.y;
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -2951,21 +3007,21 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// we'll either need to recover the floater state that applies to the
|
||||
// unconstrained reflow or keep it around in a separate space manager...
|
||||
PRBool isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
|
||||
if (aState.mComputeMaximumWidth && isBeginningLine) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||
nscoord oldY = aState.mY;
|
||||
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
|
||||
PRBool oldUnconstrainedWidth = aState.mUnconstrainedWidth;
|
||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||
|
||||
// First reflow the line with an unconstrained width. When doing this
|
||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
||||
// associated floater we don't end up resetting the line's right edge and
|
||||
// have it think the width is unconstrained...
|
||||
aState.mUnconstrainedWidth = PR_TRUE;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
|
||||
aState.mY = oldY;
|
||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||
aState.mUnconstrainedWidth = oldUnconstrainedWidth;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||
|
||||
// Update the line's maximum width
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
@ -2980,14 +3036,14 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// Note: we need to reset both member variables, because the inline
|
||||
// code examines mComputeMaxElementSize and if there is a placeholder
|
||||
// on this line the code to reflow the floater looks at both...
|
||||
nscoord oldComputeMaxElementSize = aState.mComputeMaxElementSize;
|
||||
nscoord oldComputeMaximumWidth = aState.mComputeMaximumWidth;
|
||||
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
||||
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
||||
|
||||
aState.mComputeMaxElementSize = PR_FALSE;
|
||||
aState.mComputeMaximumWidth = PR_FALSE;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
aState.mComputeMaxElementSize = oldComputeMaxElementSize;
|
||||
aState.mComputeMaximumWidth = oldComputeMaximumWidth;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
||||
|
||||
} else {
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
@ -3001,6 +3057,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 9 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -3368,7 +3428,7 @@ PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -3377,7 +3437,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -3387,13 +3447,13 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (line->HasFloaters()) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
@ -3486,8 +3546,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
@ -3611,14 +3671,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, combinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line as block so once we known the final shrink wrap width
|
||||
// we can reflow the block to the correct size
|
||||
// XXX We don't always need to do this...
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
if (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Add the right margin to the line's bounnds. That way it will be taken into
|
||||
// account when we compute our shrink wrap size
|
||||
nscoord marginRight = brc.GetMargin().right;
|
||||
@ -3709,7 +3769,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(0, 0);
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxElementSize = brc.GetMaxElementSize();
|
||||
if (aState.IsImpactedByFloater() &&
|
||||
(NS_FRAME_SPLITTABLE_NON_RECTANGULAR != splitType)) {
|
||||
@ -3721,7 +3781,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
}
|
||||
// If we asked the block to update its maximum width, then record the
|
||||
// updated value in the line, and update the current maximum width
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
||||
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
|
||||
@ -3849,7 +3909,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -3872,7 +3932,7 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineLayout lineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
@ -3910,7 +3970,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -4359,7 +4419,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsSize maxElementSize;
|
||||
aLineLayout.VerticalAlignFrames(aLine, maxElementSize);
|
||||
// See if we're shrink wrapping the width
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// When determining the line's width we also need to include any
|
||||
// right floaters that impact us. This represents the shrink wrap
|
||||
// width of the line
|
||||
@ -4388,25 +4448,20 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// Only block frames horizontally align their children because
|
||||
// inline frames "shrink-wrap" around their children (therefore
|
||||
// there is no extra horizontal space).
|
||||
#if XXX_fix_me
|
||||
PRBool allowJustify = PR_TRUE;
|
||||
if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) {
|
||||
allowJustify = ShouldJustifyLine(aState, aLine);
|
||||
}
|
||||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PRBool successful;
|
||||
nsRect combinedArea;
|
||||
successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.mShrinkWrapWidth);
|
||||
const nsStyleText* styleText = (const nsStyleText*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Text);
|
||||
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
||||
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
||||
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
||||
if (!successful) {
|
||||
// Mark the line dirty and then later once we've determined the width
|
||||
// we can do the horizontal alignment
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
|
||||
nsRect combinedArea;
|
||||
aLineLayout.RelativePositionFrames(combinedArea);
|
||||
aLine->SetCombinedArea(combinedArea);
|
||||
if (addedBullet) {
|
||||
@ -4454,7 +4509,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
aState.mY = newY;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
@ -4478,7 +4533,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// we don't want updated...
|
||||
if (aUpdateMaximumWidth) {
|
||||
// However, we do need to update the max-element-size if requested
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(maxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4519,7 +4574,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mHaveRightFloaters &&
|
||||
(aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
|
||||
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// We are reflowing in an unconstrained situation or shrink wrapping and
|
||||
// have some right floaters. They were placed at the infinite right edge
|
||||
// which will cause the combined area to be unusable.
|
||||
@ -4540,11 +4595,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
|
||||
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line dirty so we come back and re-place the floater once
|
||||
// the shrink wrap width is determined
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
}
|
||||
aLine->SetCombinedArea(lineCombinedArea);
|
||||
@ -4629,7 +4684,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
// Update max-element-size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(aMaxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4639,7 +4694,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
// If this is an unconstrained reflow, then cache the line width in the
|
||||
// line. We'll need this during incremental reflow if we're asked to
|
||||
// calculate the maximum width
|
||||
if (aState.mUnconstrainedWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
}
|
||||
|
||||
@ -4653,7 +4708,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
#endif
|
||||
// If we're shrink wrapping our width and the line was wrapped,
|
||||
// then make sure we take up all of the available width
|
||||
if (aState.mShrinkWrapWidth && aLine->IsLineWrapped()) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
|
||||
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
|
||||
|
||||
}
|
||||
@ -5187,6 +5242,10 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||
// cases...
|
||||
nsRect lineCombinedArea;
|
||||
line->GetCombinedArea(&lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
||||
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, lineCombinedArea);
|
||||
line->Destroy(presShell);
|
||||
line = next;
|
||||
@ -5282,8 +5341,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
|
||||
// Setup block reflow state to reflow the floater
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// Reflow the floater
|
||||
@ -5324,7 +5383,7 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
floater->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
// If we computed it, then stash away the max-element-size for later
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.StoreMaxElementSize(floater, brc.GetMaxElementSize());
|
||||
}
|
||||
|
||||
@ -5389,7 +5448,7 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
@ -5615,7 +5674,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
}
|
||||
else {
|
||||
isLeftFloater = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
else {
|
||||
okToAddRectRegion = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.x;
|
||||
}
|
||||
}
|
||||
*aIsLeftFloater = isLeftFloater;
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
@ -5682,7 +5746,8 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
nsRect combinedArea = aFloaterCache->mCombinedArea;
|
||||
combinedArea.x += x;
|
||||
combinedArea.y += y;
|
||||
if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
|
||||
if (!isLeftFloater &&
|
||||
(GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// When we are placing a right floater in an unconstrained situation or
|
||||
// when shrink wrapping, we don't apply it to the floater combined area
|
||||
// immediately. Otherwise we end up with an infinitely wide combined
|
||||
|
@ -197,10 +197,12 @@ nsBlockReflowContext::AlignBlockHorizontally(nscoord aWidth,
|
||||
// compatability cases.
|
||||
switch (styleText->mTextAlign) {
|
||||
case NS_STYLE_TEXT_ALIGN_MOZ_RIGHT:
|
||||
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
||||
aAlign.mXOffset += remainingSpace;
|
||||
doCSS = PR_FALSE;
|
||||
break;
|
||||
case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
|
||||
case NS_STYLE_TEXT_ALIGN_CENTER:
|
||||
aAlign.mXOffset += remainingSpace / 2;
|
||||
doCSS = PR_FALSE;
|
||||
break;
|
||||
@ -359,7 +361,11 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
|
||||
reflowState.mComputedBorderPadding.right;
|
||||
}
|
||||
|
||||
x = aSpace.XMost() - mMargin.right - frameWidth;
|
||||
// if this is an unconstrained width reflow, then just place the floater at the left margin
|
||||
if (NS_UNCONSTRAINEDSIZE == aSpace.width)
|
||||
x = aSpace.x;
|
||||
else
|
||||
x = aSpace.XMost() - mMargin.right - frameWidth;
|
||||
|
||||
} else {
|
||||
x = aSpace.x + mMargin.left;
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
@ -61,6 +63,8 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
//#define NOISY_BLOCK_INVALIDATE // DO NOT CHECK THIS IN TURNED ON!
|
||||
|
||||
static PRBool gLamePaintMetrics;
|
||||
static PRBool gLameReflowMetrics;
|
||||
static PRBool gNoisy;
|
||||
@ -451,12 +455,6 @@ public:
|
||||
|
||||
nscoord mBottomEdge;
|
||||
|
||||
PRPackedBool mUnconstrainedWidth;
|
||||
PRPackedBool mUnconstrainedHeight;
|
||||
PRPackedBool mShrinkWrapWidth;
|
||||
PRPackedBool mNeedResizeReflow;
|
||||
PRPackedBool mIsInlineIncrReflow;
|
||||
|
||||
// The content area to reflow child frames within. The x/y
|
||||
// coordinates are known to be mBorderPadding.left and
|
||||
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
||||
@ -464,15 +462,6 @@ public:
|
||||
// unconstrained area.
|
||||
nsSize mContentArea;
|
||||
|
||||
// Our wrapping behavior
|
||||
PRPackedBool mNoWrap;
|
||||
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRPackedBool mIsTopMarginRoot, mIsBottomMarginRoot;
|
||||
|
||||
// See ShouldApplyTopMargin
|
||||
PRPackedBool mApplyTopMargin;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
@ -541,15 +530,48 @@ public:
|
||||
// being N^2.
|
||||
nsFloaterCacheFreeList mBelowCurrentLineFloaters;
|
||||
|
||||
PRPackedBool mComputeMaxElementSize;
|
||||
PRPackedBool mComputeMaximumWidth;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
nscoord mMaximumWidth;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
|
||||
// block reflow state flags
|
||||
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
||||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
@ -574,29 +596,25 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
mNeedResizeReflow(PR_FALSE),
|
||||
mIsInlineIncrReflow(PR_FALSE),
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
mLineNumber(0),
|
||||
mFlags(0)
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (mIsTopMarginRoot) {
|
||||
mApplyTopMargin = PR_TRUE;
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
}
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
@ -617,21 +635,19 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Compute content area width (the content area is inside the border
|
||||
// and padding)
|
||||
mUnconstrainedWidth = PR_FALSE;
|
||||
mShrinkWrapWidth = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
||||
mContentArea.width = aReflowState.mComputedWidth;
|
||||
}
|
||||
else {
|
||||
if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
|
||||
mContentArea.width = NS_UNCONSTRAINEDSIZE;
|
||||
mUnconstrainedWidth = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
}
|
||||
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
||||
// Choose a width based on the content (shrink wrap width) up
|
||||
// to the maximum width
|
||||
mContentArea.width = aReflowState.mComputedMaxWidth;
|
||||
mShrinkWrapWidth = PR_TRUE;
|
||||
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
|
||||
}
|
||||
else {
|
||||
nscoord lr = borderPadding.left + borderPadding.right;
|
||||
@ -646,7 +662,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
// specified style height then we may end up limiting our height if
|
||||
// the availableHeight is constrained (this situation occurs when we
|
||||
// are paginated).
|
||||
mUnconstrainedHeight = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
||||
// We are in a paginated situation. The bottom edge is just inside
|
||||
// the bottom border and padding. The content area height doesn't
|
||||
@ -657,7 +672,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
else {
|
||||
// When we are not in a paginated situation then we always use
|
||||
// an constrained height.
|
||||
mUnconstrainedHeight = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
|
||||
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
|
||||
@ -674,16 +689,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
switch (styleText->mWhiteSpace) {
|
||||
case NS_STYLE_WHITESPACE_PRE:
|
||||
case NS_STYLE_WHITESPACE_NOWRAP:
|
||||
mNoWrap = PR_TRUE;
|
||||
SetFlag(BRS_NOWRAP, PR_TRUE);
|
||||
break;
|
||||
default:
|
||||
mNoWrap = PR_FALSE;
|
||||
SetFlag(BRS_NOWRAP, PR_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
mComputeMaximumWidth = NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH);
|
||||
SetFlag(BRS_COMPUTEMAXWIDTH,
|
||||
(NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
|
||||
mMaximumWidth = 0;
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
@ -729,8 +745,12 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
|
||||
mBand.List();
|
||||
#endif
|
||||
aResult.y = mY;
|
||||
aResult.height = mUnconstrainedHeight
|
||||
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mBottomEdge - mY;
|
||||
|
||||
@ -749,7 +769,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// The child block will flow around the floater. Therefore
|
||||
// give it all of the available space.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
break;
|
||||
@ -776,7 +796,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
// determine width
|
||||
if (mUnconstrainedWidth) {
|
||||
if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aResult.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -810,7 +830,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// doesn't matter therefore give the block element all of the
|
||||
// available space since it will flow around the floater itself.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
}
|
||||
@ -957,12 +977,12 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
|
||||
#endif
|
||||
mKidXMost = xmost;
|
||||
}
|
||||
if (mComputeMaxElementSize) {
|
||||
if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
||||
}
|
||||
|
||||
// If computing the maximum width, then update mMaximumWidth
|
||||
if (mComputeMaximumWidth) {
|
||||
if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
}
|
||||
|
||||
@ -1454,6 +1474,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
||||
NS_BLOCK_MARGIN_ROOT & mState);
|
||||
PRInt32 sizeofBRS = sizeof nsBlockReflowState;
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
RenumberLists(aPresContext);
|
||||
@ -1462,7 +1483,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
PRBool isStyleChange = PR_FALSE;
|
||||
state.mIsInlineIncrReflow = PR_FALSE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_FALSE);
|
||||
nsIFrame* target;
|
||||
switch (aReflowState.reason) {
|
||||
case eReflowReason_Initial:
|
||||
@ -1535,7 +1556,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// reflow the line containing the target of the incr. reflow
|
||||
// first mark the line dirty and set up the state object
|
||||
rv = PrepareChildIncrementalReflow(state);
|
||||
state.mIsInlineIncrReflow = PR_TRUE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
state.mPrevLine = prevLine;
|
||||
state.mCurrentLine = line;
|
||||
state.mNextRCFrame = state.mNextRCFrame;
|
||||
@ -1681,6 +1702,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
if (isStyleChange) {
|
||||
// Lots of things could have changed so damage our entire
|
||||
// bounds
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 1 (%d, %d, %d, %d)\n",
|
||||
this, 0, 0, mRect.width, mRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height));
|
||||
|
||||
} else {
|
||||
@ -1707,6 +1732,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = 0;
|
||||
damageRect.height = mRect.height;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 2 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
|
||||
@ -1730,6 +1759,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = mRect.height - border.bottom;
|
||||
damageRect.height = border.bottom;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 3 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -1868,7 +1901,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
||||
aState.mY, aState.mIsBottomMarginRoot ? "yes" : "no",
|
||||
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
||||
aState.mPrevBottomMargin,
|
||||
borderPadding.top, borderPadding.bottom);
|
||||
#endif
|
||||
@ -1946,7 +1979,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// contents or we fluff out to the maximum block width. Note:
|
||||
// We always shrink wrap when given an unconstrained width.
|
||||
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
|
||||
!aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
|
||||
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && !aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
||||
!compact) {
|
||||
// Set our width to the max width if we aren't already that
|
||||
// wide. Note that the max-width has nothing to do with our
|
||||
@ -1956,9 +1989,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// See if we should compute our max element size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Adjust the computedWidth
|
||||
if (aState.mNoWrap) {
|
||||
if (aState.GetFlag(BRS_NOWRAP)) {
|
||||
// When no-wrap is true the max-element-size.width is the
|
||||
// width of the widest line plus the right border. Note that
|
||||
// aState.mKidXMost already has the left border factored in
|
||||
@ -1996,7 +2029,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// need to do horizontal alignment of the inline lines and make sure
|
||||
// blocks are correctly sized and positioned. Any lines that need
|
||||
// final adjustment will have been marked as dirty
|
||||
if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
|
||||
// If the parent reflow state is also shrink wrap width, then
|
||||
// we don't need to do this, because it will reflow us after it
|
||||
// calculates the final width
|
||||
@ -2025,7 +2058,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
}
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
||||
if (aReflowState.parentReflowState) {
|
||||
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
||||
@ -2047,7 +2080,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// Don't carry out a bottom margin when our height is fixed
|
||||
// unless the bottom of the last line adjoins the bottom of our
|
||||
// content area.
|
||||
if (!aState.mIsBottomMarginRoot) {
|
||||
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
|
||||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
@ -2057,7 +2090,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
@ -2082,7 +2115,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
aMetrics.height = autoHeight;
|
||||
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxHeight = aState.mMaxElementSize.height +
|
||||
borderPadding.top + borderPadding.bottom;
|
||||
}
|
||||
@ -2090,7 +2123,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
aMetrics.descent = 0;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Store away the final value
|
||||
aMetrics.maxElementSize->width = maxWidth;
|
||||
aMetrics.maxElementSize->height = maxHeight;
|
||||
@ -2098,14 +2131,14 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
||||
}
|
||||
if (aState.mComputeMaxElementSize &&
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
||||
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
||||
@ -2115,7 +2148,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
#endif
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
printf("PASS1 ");
|
||||
@ -2130,7 +2163,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// If we're requested to update our maximum width, then compute it
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We need to add in for the right border/padding
|
||||
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
||||
}
|
||||
@ -2337,8 +2370,13 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
// See if we can try and avoid marking all the lines as dirty
|
||||
PRBool tryAndSkipLines = PR_FALSE;
|
||||
|
||||
// See if this is this a constrained resize reflow
|
||||
if ((aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
// we need to calculate if any part of then block itself
|
||||
// is impacted by a floater (bug 19579)
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
// See if this is this a constrained resize reflow that is not impacted by floaters
|
||||
if ((PR_FALSE==aState.IsImpactedByFloater()) &&
|
||||
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
||||
|
||||
// If the text is left-aligned, then we try and avoid reflowing the lines
|
||||
@ -2389,7 +2427,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool notWrapping = aState.mNoWrap;
|
||||
PRBool notWrapping = aState.GetFlag(BRS_NOWRAP);
|
||||
while (nsnull != line) {
|
||||
|
||||
if (line->IsBlock()) {
|
||||
@ -2402,8 +2440,6 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
||||
line, line->IsImpactedByFloater() ? "" : "not ");
|
||||
#endif
|
||||
|
||||
|
||||
if (notWrapping) {
|
||||
// When no-wrap is set then the only line-breaking that
|
||||
// occurs for inline lines is triggered by BR elements or by
|
||||
@ -2430,7 +2466,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
||||
line, line->mNext,
|
||||
line->IsBlock() ? "block" : "inline",
|
||||
aState.mNoWrap ? "no-wrap" : "wrapping",
|
||||
aState.GetFlag(BRS_NOWRAP) ? "no-wrap" : "wrapping",
|
||||
line->HasBreak() ? "has-break " : "",
|
||||
line->HasFloaters() ? "has-floaters " : "",
|
||||
line->IsImpactedByFloater() ? "impacted " : "",
|
||||
@ -2628,7 +2664,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.mIsInlineIncrReflow ? "true" : "false");
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
@ -2651,7 +2687,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// Reflow the lines that are already ours
|
||||
aState.mPrevLine = nsnull;
|
||||
nsLineBox* line = mLines;
|
||||
if (aState.mIsInlineIncrReflow && aState.mNextRCFrame)
|
||||
if (aState.GetFlag(BRS_ISINLINEINCRREFLOW) && aState.mNextRCFrame)
|
||||
{
|
||||
const nsLineBox* incrTargetLine = aState.mCurrentLine;
|
||||
aState.mCurrentLine = line;
|
||||
@ -2662,6 +2698,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 4 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
aState.mPrevLine = line;
|
||||
@ -2689,7 +2729,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// If we're supposed to update our maximum width, then we'll also need to
|
||||
// reflow this line if it's line wrapped and any of the continuing lines
|
||||
// are dirty
|
||||
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
|
||||
if (line->IsDirty() || (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line))) {
|
||||
// Compute the dirty lines "before" YMost, after factoring in
|
||||
// the running deltaY value - the running value is implicit in
|
||||
// aState.mY.
|
||||
@ -2729,6 +2769,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 5 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -2902,6 +2946,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// XXX We need to improve on this...
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
|
||||
} else {
|
||||
@ -2918,6 +2966,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.x;
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
||||
lineCombinedArea.height);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
if (oldCombinedArea.height != lineCombinedArea.height) {
|
||||
@ -2933,6 +2985,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
||||
lineCombinedArea.YMost()) -
|
||||
dirtyRect.y;
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -2951,21 +3007,21 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// we'll either need to recover the floater state that applies to the
|
||||
// unconstrained reflow or keep it around in a separate space manager...
|
||||
PRBool isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
|
||||
if (aState.mComputeMaximumWidth && isBeginningLine) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||
nscoord oldY = aState.mY;
|
||||
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
|
||||
PRBool oldUnconstrainedWidth = aState.mUnconstrainedWidth;
|
||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||
|
||||
// First reflow the line with an unconstrained width. When doing this
|
||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
||||
// associated floater we don't end up resetting the line's right edge and
|
||||
// have it think the width is unconstrained...
|
||||
aState.mUnconstrainedWidth = PR_TRUE;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
|
||||
aState.mY = oldY;
|
||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||
aState.mUnconstrainedWidth = oldUnconstrainedWidth;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||
|
||||
// Update the line's maximum width
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
@ -2980,14 +3036,14 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// Note: we need to reset both member variables, because the inline
|
||||
// code examines mComputeMaxElementSize and if there is a placeholder
|
||||
// on this line the code to reflow the floater looks at both...
|
||||
nscoord oldComputeMaxElementSize = aState.mComputeMaxElementSize;
|
||||
nscoord oldComputeMaximumWidth = aState.mComputeMaximumWidth;
|
||||
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
||||
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
||||
|
||||
aState.mComputeMaxElementSize = PR_FALSE;
|
||||
aState.mComputeMaximumWidth = PR_FALSE;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
aState.mComputeMaxElementSize = oldComputeMaxElementSize;
|
||||
aState.mComputeMaximumWidth = oldComputeMaximumWidth;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
||||
|
||||
} else {
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
@ -3001,6 +3057,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 9 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -3368,7 +3428,7 @@ PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -3377,7 +3437,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -3387,13 +3447,13 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (line->HasFloaters()) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
@ -3486,8 +3546,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
@ -3611,14 +3671,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, combinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line as block so once we known the final shrink wrap width
|
||||
// we can reflow the block to the correct size
|
||||
// XXX We don't always need to do this...
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
if (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Add the right margin to the line's bounnds. That way it will be taken into
|
||||
// account when we compute our shrink wrap size
|
||||
nscoord marginRight = brc.GetMargin().right;
|
||||
@ -3709,7 +3769,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(0, 0);
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxElementSize = brc.GetMaxElementSize();
|
||||
if (aState.IsImpactedByFloater() &&
|
||||
(NS_FRAME_SPLITTABLE_NON_RECTANGULAR != splitType)) {
|
||||
@ -3721,7 +3781,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
}
|
||||
// If we asked the block to update its maximum width, then record the
|
||||
// updated value in the line, and update the current maximum width
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
||||
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
|
||||
@ -3849,7 +3909,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -3872,7 +3932,7 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineLayout lineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
@ -3910,7 +3970,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -4359,7 +4419,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsSize maxElementSize;
|
||||
aLineLayout.VerticalAlignFrames(aLine, maxElementSize);
|
||||
// See if we're shrink wrapping the width
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// When determining the line's width we also need to include any
|
||||
// right floaters that impact us. This represents the shrink wrap
|
||||
// width of the line
|
||||
@ -4388,25 +4448,20 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// Only block frames horizontally align their children because
|
||||
// inline frames "shrink-wrap" around their children (therefore
|
||||
// there is no extra horizontal space).
|
||||
#if XXX_fix_me
|
||||
PRBool allowJustify = PR_TRUE;
|
||||
if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) {
|
||||
allowJustify = ShouldJustifyLine(aState, aLine);
|
||||
}
|
||||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PRBool successful;
|
||||
nsRect combinedArea;
|
||||
successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.mShrinkWrapWidth);
|
||||
const nsStyleText* styleText = (const nsStyleText*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Text);
|
||||
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
||||
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
||||
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
||||
if (!successful) {
|
||||
// Mark the line dirty and then later once we've determined the width
|
||||
// we can do the horizontal alignment
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
|
||||
nsRect combinedArea;
|
||||
aLineLayout.RelativePositionFrames(combinedArea);
|
||||
aLine->SetCombinedArea(combinedArea);
|
||||
if (addedBullet) {
|
||||
@ -4454,7 +4509,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
aState.mY = newY;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
@ -4478,7 +4533,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// we don't want updated...
|
||||
if (aUpdateMaximumWidth) {
|
||||
// However, we do need to update the max-element-size if requested
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(maxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4519,7 +4574,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mHaveRightFloaters &&
|
||||
(aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
|
||||
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// We are reflowing in an unconstrained situation or shrink wrapping and
|
||||
// have some right floaters. They were placed at the infinite right edge
|
||||
// which will cause the combined area to be unusable.
|
||||
@ -4540,11 +4595,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
|
||||
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line dirty so we come back and re-place the floater once
|
||||
// the shrink wrap width is determined
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
}
|
||||
aLine->SetCombinedArea(lineCombinedArea);
|
||||
@ -4629,7 +4684,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
// Update max-element-size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(aMaxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4639,7 +4694,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
// If this is an unconstrained reflow, then cache the line width in the
|
||||
// line. We'll need this during incremental reflow if we're asked to
|
||||
// calculate the maximum width
|
||||
if (aState.mUnconstrainedWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
}
|
||||
|
||||
@ -4653,7 +4708,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
#endif
|
||||
// If we're shrink wrapping our width and the line was wrapped,
|
||||
// then make sure we take up all of the available width
|
||||
if (aState.mShrinkWrapWidth && aLine->IsLineWrapped()) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
|
||||
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
|
||||
|
||||
}
|
||||
@ -5187,6 +5242,10 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||
// cases...
|
||||
nsRect lineCombinedArea;
|
||||
line->GetCombinedArea(&lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
||||
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, lineCombinedArea);
|
||||
line->Destroy(presShell);
|
||||
line = next;
|
||||
@ -5282,8 +5341,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
|
||||
// Setup block reflow state to reflow the floater
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// Reflow the floater
|
||||
@ -5324,7 +5383,7 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
floater->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
// If we computed it, then stash away the max-element-size for later
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.StoreMaxElementSize(floater, brc.GetMaxElementSize());
|
||||
}
|
||||
|
||||
@ -5389,7 +5448,7 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
@ -5615,7 +5674,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
}
|
||||
else {
|
||||
isLeftFloater = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
else {
|
||||
okToAddRectRegion = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.x;
|
||||
}
|
||||
}
|
||||
*aIsLeftFloater = isLeftFloater;
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
@ -5682,7 +5746,8 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
nsRect combinedArea = aFloaterCache->mCombinedArea;
|
||||
combinedArea.x += x;
|
||||
combinedArea.y += y;
|
||||
if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
|
||||
if (!isLeftFloater &&
|
||||
(GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// When we are placing a right floater in an unconstrained situation or
|
||||
// when shrink wrapping, we don't apply it to the floater combined area
|
||||
// immediately. Otherwise we end up with an infinitely wide combined
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
@ -61,6 +63,8 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
//#define NOISY_BLOCK_INVALIDATE // DO NOT CHECK THIS IN TURNED ON!
|
||||
|
||||
static PRBool gLamePaintMetrics;
|
||||
static PRBool gLameReflowMetrics;
|
||||
static PRBool gNoisy;
|
||||
@ -451,12 +455,6 @@ public:
|
||||
|
||||
nscoord mBottomEdge;
|
||||
|
||||
PRPackedBool mUnconstrainedWidth;
|
||||
PRPackedBool mUnconstrainedHeight;
|
||||
PRPackedBool mShrinkWrapWidth;
|
||||
PRPackedBool mNeedResizeReflow;
|
||||
PRPackedBool mIsInlineIncrReflow;
|
||||
|
||||
// The content area to reflow child frames within. The x/y
|
||||
// coordinates are known to be mBorderPadding.left and
|
||||
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
||||
@ -464,15 +462,6 @@ public:
|
||||
// unconstrained area.
|
||||
nsSize mContentArea;
|
||||
|
||||
// Our wrapping behavior
|
||||
PRPackedBool mNoWrap;
|
||||
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRPackedBool mIsTopMarginRoot, mIsBottomMarginRoot;
|
||||
|
||||
// See ShouldApplyTopMargin
|
||||
PRPackedBool mApplyTopMargin;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
@ -541,15 +530,48 @@ public:
|
||||
// being N^2.
|
||||
nsFloaterCacheFreeList mBelowCurrentLineFloaters;
|
||||
|
||||
PRPackedBool mComputeMaxElementSize;
|
||||
PRPackedBool mComputeMaximumWidth;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
nscoord mMaximumWidth;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
|
||||
// block reflow state flags
|
||||
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
||||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
@ -574,29 +596,25 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
mNeedResizeReflow(PR_FALSE),
|
||||
mIsInlineIncrReflow(PR_FALSE),
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
mLineNumber(0),
|
||||
mFlags(0)
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (mIsTopMarginRoot) {
|
||||
mApplyTopMargin = PR_TRUE;
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
}
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
@ -617,21 +635,19 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Compute content area width (the content area is inside the border
|
||||
// and padding)
|
||||
mUnconstrainedWidth = PR_FALSE;
|
||||
mShrinkWrapWidth = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
||||
mContentArea.width = aReflowState.mComputedWidth;
|
||||
}
|
||||
else {
|
||||
if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
|
||||
mContentArea.width = NS_UNCONSTRAINEDSIZE;
|
||||
mUnconstrainedWidth = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
}
|
||||
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
||||
// Choose a width based on the content (shrink wrap width) up
|
||||
// to the maximum width
|
||||
mContentArea.width = aReflowState.mComputedMaxWidth;
|
||||
mShrinkWrapWidth = PR_TRUE;
|
||||
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
|
||||
}
|
||||
else {
|
||||
nscoord lr = borderPadding.left + borderPadding.right;
|
||||
@ -646,7 +662,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
// specified style height then we may end up limiting our height if
|
||||
// the availableHeight is constrained (this situation occurs when we
|
||||
// are paginated).
|
||||
mUnconstrainedHeight = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
||||
// We are in a paginated situation. The bottom edge is just inside
|
||||
// the bottom border and padding. The content area height doesn't
|
||||
@ -657,7 +672,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
else {
|
||||
// When we are not in a paginated situation then we always use
|
||||
// an constrained height.
|
||||
mUnconstrainedHeight = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
|
||||
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
|
||||
@ -674,16 +689,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
switch (styleText->mWhiteSpace) {
|
||||
case NS_STYLE_WHITESPACE_PRE:
|
||||
case NS_STYLE_WHITESPACE_NOWRAP:
|
||||
mNoWrap = PR_TRUE;
|
||||
SetFlag(BRS_NOWRAP, PR_TRUE);
|
||||
break;
|
||||
default:
|
||||
mNoWrap = PR_FALSE;
|
||||
SetFlag(BRS_NOWRAP, PR_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
mComputeMaximumWidth = NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH);
|
||||
SetFlag(BRS_COMPUTEMAXWIDTH,
|
||||
(NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
|
||||
mMaximumWidth = 0;
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
@ -729,8 +745,12 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
|
||||
mBand.List();
|
||||
#endif
|
||||
aResult.y = mY;
|
||||
aResult.height = mUnconstrainedHeight
|
||||
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mBottomEdge - mY;
|
||||
|
||||
@ -749,7 +769,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// The child block will flow around the floater. Therefore
|
||||
// give it all of the available space.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
break;
|
||||
@ -776,7 +796,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
// determine width
|
||||
if (mUnconstrainedWidth) {
|
||||
if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aResult.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -810,7 +830,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// doesn't matter therefore give the block element all of the
|
||||
// available space since it will flow around the floater itself.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
}
|
||||
@ -957,12 +977,12 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
|
||||
#endif
|
||||
mKidXMost = xmost;
|
||||
}
|
||||
if (mComputeMaxElementSize) {
|
||||
if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
||||
}
|
||||
|
||||
// If computing the maximum width, then update mMaximumWidth
|
||||
if (mComputeMaximumWidth) {
|
||||
if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
}
|
||||
|
||||
@ -1454,6 +1474,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
||||
NS_BLOCK_MARGIN_ROOT & mState);
|
||||
PRInt32 sizeofBRS = sizeof nsBlockReflowState;
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
RenumberLists(aPresContext);
|
||||
@ -1462,7 +1483,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
PRBool isStyleChange = PR_FALSE;
|
||||
state.mIsInlineIncrReflow = PR_FALSE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_FALSE);
|
||||
nsIFrame* target;
|
||||
switch (aReflowState.reason) {
|
||||
case eReflowReason_Initial:
|
||||
@ -1535,7 +1556,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// reflow the line containing the target of the incr. reflow
|
||||
// first mark the line dirty and set up the state object
|
||||
rv = PrepareChildIncrementalReflow(state);
|
||||
state.mIsInlineIncrReflow = PR_TRUE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
state.mPrevLine = prevLine;
|
||||
state.mCurrentLine = line;
|
||||
state.mNextRCFrame = state.mNextRCFrame;
|
||||
@ -1681,6 +1702,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
if (isStyleChange) {
|
||||
// Lots of things could have changed so damage our entire
|
||||
// bounds
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 1 (%d, %d, %d, %d)\n",
|
||||
this, 0, 0, mRect.width, mRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height));
|
||||
|
||||
} else {
|
||||
@ -1707,6 +1732,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = 0;
|
||||
damageRect.height = mRect.height;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 2 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
|
||||
@ -1730,6 +1759,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = mRect.height - border.bottom;
|
||||
damageRect.height = border.bottom;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 3 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -1868,7 +1901,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
||||
aState.mY, aState.mIsBottomMarginRoot ? "yes" : "no",
|
||||
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
||||
aState.mPrevBottomMargin,
|
||||
borderPadding.top, borderPadding.bottom);
|
||||
#endif
|
||||
@ -1946,7 +1979,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// contents or we fluff out to the maximum block width. Note:
|
||||
// We always shrink wrap when given an unconstrained width.
|
||||
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
|
||||
!aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
|
||||
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && !aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
||||
!compact) {
|
||||
// Set our width to the max width if we aren't already that
|
||||
// wide. Note that the max-width has nothing to do with our
|
||||
@ -1956,9 +1989,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// See if we should compute our max element size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Adjust the computedWidth
|
||||
if (aState.mNoWrap) {
|
||||
if (aState.GetFlag(BRS_NOWRAP)) {
|
||||
// When no-wrap is true the max-element-size.width is the
|
||||
// width of the widest line plus the right border. Note that
|
||||
// aState.mKidXMost already has the left border factored in
|
||||
@ -1996,7 +2029,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// need to do horizontal alignment of the inline lines and make sure
|
||||
// blocks are correctly sized and positioned. Any lines that need
|
||||
// final adjustment will have been marked as dirty
|
||||
if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
|
||||
// If the parent reflow state is also shrink wrap width, then
|
||||
// we don't need to do this, because it will reflow us after it
|
||||
// calculates the final width
|
||||
@ -2025,7 +2058,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
}
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
||||
if (aReflowState.parentReflowState) {
|
||||
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
||||
@ -2047,7 +2080,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// Don't carry out a bottom margin when our height is fixed
|
||||
// unless the bottom of the last line adjoins the bottom of our
|
||||
// content area.
|
||||
if (!aState.mIsBottomMarginRoot) {
|
||||
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
|
||||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
@ -2057,7 +2090,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
@ -2082,7 +2115,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
aMetrics.height = autoHeight;
|
||||
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxHeight = aState.mMaxElementSize.height +
|
||||
borderPadding.top + borderPadding.bottom;
|
||||
}
|
||||
@ -2090,7 +2123,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
aMetrics.descent = 0;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Store away the final value
|
||||
aMetrics.maxElementSize->width = maxWidth;
|
||||
aMetrics.maxElementSize->height = maxHeight;
|
||||
@ -2098,14 +2131,14 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
||||
}
|
||||
if (aState.mComputeMaxElementSize &&
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
||||
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
||||
@ -2115,7 +2148,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
#endif
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
printf("PASS1 ");
|
||||
@ -2130,7 +2163,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// If we're requested to update our maximum width, then compute it
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We need to add in for the right border/padding
|
||||
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
||||
}
|
||||
@ -2337,8 +2370,13 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
// See if we can try and avoid marking all the lines as dirty
|
||||
PRBool tryAndSkipLines = PR_FALSE;
|
||||
|
||||
// See if this is this a constrained resize reflow
|
||||
if ((aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
// we need to calculate if any part of then block itself
|
||||
// is impacted by a floater (bug 19579)
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
// See if this is this a constrained resize reflow that is not impacted by floaters
|
||||
if ((PR_FALSE==aState.IsImpactedByFloater()) &&
|
||||
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
||||
|
||||
// If the text is left-aligned, then we try and avoid reflowing the lines
|
||||
@ -2389,7 +2427,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool notWrapping = aState.mNoWrap;
|
||||
PRBool notWrapping = aState.GetFlag(BRS_NOWRAP);
|
||||
while (nsnull != line) {
|
||||
|
||||
if (line->IsBlock()) {
|
||||
@ -2402,8 +2440,6 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
||||
line, line->IsImpactedByFloater() ? "" : "not ");
|
||||
#endif
|
||||
|
||||
|
||||
if (notWrapping) {
|
||||
// When no-wrap is set then the only line-breaking that
|
||||
// occurs for inline lines is triggered by BR elements or by
|
||||
@ -2430,7 +2466,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
||||
line, line->mNext,
|
||||
line->IsBlock() ? "block" : "inline",
|
||||
aState.mNoWrap ? "no-wrap" : "wrapping",
|
||||
aState.GetFlag(BRS_NOWRAP) ? "no-wrap" : "wrapping",
|
||||
line->HasBreak() ? "has-break " : "",
|
||||
line->HasFloaters() ? "has-floaters " : "",
|
||||
line->IsImpactedByFloater() ? "impacted " : "",
|
||||
@ -2628,7 +2664,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.mIsInlineIncrReflow ? "true" : "false");
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
@ -2651,7 +2687,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// Reflow the lines that are already ours
|
||||
aState.mPrevLine = nsnull;
|
||||
nsLineBox* line = mLines;
|
||||
if (aState.mIsInlineIncrReflow && aState.mNextRCFrame)
|
||||
if (aState.GetFlag(BRS_ISINLINEINCRREFLOW) && aState.mNextRCFrame)
|
||||
{
|
||||
const nsLineBox* incrTargetLine = aState.mCurrentLine;
|
||||
aState.mCurrentLine = line;
|
||||
@ -2662,6 +2698,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 4 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
aState.mPrevLine = line;
|
||||
@ -2689,7 +2729,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// If we're supposed to update our maximum width, then we'll also need to
|
||||
// reflow this line if it's line wrapped and any of the continuing lines
|
||||
// are dirty
|
||||
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
|
||||
if (line->IsDirty() || (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line))) {
|
||||
// Compute the dirty lines "before" YMost, after factoring in
|
||||
// the running deltaY value - the running value is implicit in
|
||||
// aState.mY.
|
||||
@ -2729,6 +2769,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 5 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -2902,6 +2946,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// XXX We need to improve on this...
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
|
||||
} else {
|
||||
@ -2918,6 +2966,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.x;
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
||||
lineCombinedArea.height);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
if (oldCombinedArea.height != lineCombinedArea.height) {
|
||||
@ -2933,6 +2985,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
||||
lineCombinedArea.YMost()) -
|
||||
dirtyRect.y;
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -2951,21 +3007,21 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// we'll either need to recover the floater state that applies to the
|
||||
// unconstrained reflow or keep it around in a separate space manager...
|
||||
PRBool isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
|
||||
if (aState.mComputeMaximumWidth && isBeginningLine) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||
nscoord oldY = aState.mY;
|
||||
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
|
||||
PRBool oldUnconstrainedWidth = aState.mUnconstrainedWidth;
|
||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||
|
||||
// First reflow the line with an unconstrained width. When doing this
|
||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
||||
// associated floater we don't end up resetting the line's right edge and
|
||||
// have it think the width is unconstrained...
|
||||
aState.mUnconstrainedWidth = PR_TRUE;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
|
||||
aState.mY = oldY;
|
||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||
aState.mUnconstrainedWidth = oldUnconstrainedWidth;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||
|
||||
// Update the line's maximum width
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
@ -2980,14 +3036,14 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// Note: we need to reset both member variables, because the inline
|
||||
// code examines mComputeMaxElementSize and if there is a placeholder
|
||||
// on this line the code to reflow the floater looks at both...
|
||||
nscoord oldComputeMaxElementSize = aState.mComputeMaxElementSize;
|
||||
nscoord oldComputeMaximumWidth = aState.mComputeMaximumWidth;
|
||||
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
||||
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
||||
|
||||
aState.mComputeMaxElementSize = PR_FALSE;
|
||||
aState.mComputeMaximumWidth = PR_FALSE;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
aState.mComputeMaxElementSize = oldComputeMaxElementSize;
|
||||
aState.mComputeMaximumWidth = oldComputeMaximumWidth;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
||||
|
||||
} else {
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
@ -3001,6 +3057,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 9 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -3368,7 +3428,7 @@ PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -3377,7 +3437,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -3387,13 +3447,13 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (line->HasFloaters()) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
@ -3486,8 +3546,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
@ -3611,14 +3671,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, combinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line as block so once we known the final shrink wrap width
|
||||
// we can reflow the block to the correct size
|
||||
// XXX We don't always need to do this...
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
if (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Add the right margin to the line's bounnds. That way it will be taken into
|
||||
// account when we compute our shrink wrap size
|
||||
nscoord marginRight = brc.GetMargin().right;
|
||||
@ -3709,7 +3769,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(0, 0);
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxElementSize = brc.GetMaxElementSize();
|
||||
if (aState.IsImpactedByFloater() &&
|
||||
(NS_FRAME_SPLITTABLE_NON_RECTANGULAR != splitType)) {
|
||||
@ -3721,7 +3781,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
}
|
||||
// If we asked the block to update its maximum width, then record the
|
||||
// updated value in the line, and update the current maximum width
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
||||
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
|
||||
@ -3849,7 +3909,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -3872,7 +3932,7 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineLayout lineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
@ -3910,7 +3970,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -4359,7 +4419,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsSize maxElementSize;
|
||||
aLineLayout.VerticalAlignFrames(aLine, maxElementSize);
|
||||
// See if we're shrink wrapping the width
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// When determining the line's width we also need to include any
|
||||
// right floaters that impact us. This represents the shrink wrap
|
||||
// width of the line
|
||||
@ -4388,25 +4448,20 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// Only block frames horizontally align their children because
|
||||
// inline frames "shrink-wrap" around their children (therefore
|
||||
// there is no extra horizontal space).
|
||||
#if XXX_fix_me
|
||||
PRBool allowJustify = PR_TRUE;
|
||||
if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) {
|
||||
allowJustify = ShouldJustifyLine(aState, aLine);
|
||||
}
|
||||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PRBool successful;
|
||||
nsRect combinedArea;
|
||||
successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.mShrinkWrapWidth);
|
||||
const nsStyleText* styleText = (const nsStyleText*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Text);
|
||||
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
||||
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
||||
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
||||
if (!successful) {
|
||||
// Mark the line dirty and then later once we've determined the width
|
||||
// we can do the horizontal alignment
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
|
||||
nsRect combinedArea;
|
||||
aLineLayout.RelativePositionFrames(combinedArea);
|
||||
aLine->SetCombinedArea(combinedArea);
|
||||
if (addedBullet) {
|
||||
@ -4454,7 +4509,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
aState.mY = newY;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
@ -4478,7 +4533,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// we don't want updated...
|
||||
if (aUpdateMaximumWidth) {
|
||||
// However, we do need to update the max-element-size if requested
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(maxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4519,7 +4574,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mHaveRightFloaters &&
|
||||
(aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
|
||||
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// We are reflowing in an unconstrained situation or shrink wrapping and
|
||||
// have some right floaters. They were placed at the infinite right edge
|
||||
// which will cause the combined area to be unusable.
|
||||
@ -4540,11 +4595,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
|
||||
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line dirty so we come back and re-place the floater once
|
||||
// the shrink wrap width is determined
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
}
|
||||
aLine->SetCombinedArea(lineCombinedArea);
|
||||
@ -4629,7 +4684,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
// Update max-element-size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(aMaxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4639,7 +4694,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
// If this is an unconstrained reflow, then cache the line width in the
|
||||
// line. We'll need this during incremental reflow if we're asked to
|
||||
// calculate the maximum width
|
||||
if (aState.mUnconstrainedWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
}
|
||||
|
||||
@ -4653,7 +4708,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
#endif
|
||||
// If we're shrink wrapping our width and the line was wrapped,
|
||||
// then make sure we take up all of the available width
|
||||
if (aState.mShrinkWrapWidth && aLine->IsLineWrapped()) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
|
||||
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
|
||||
|
||||
}
|
||||
@ -5187,6 +5242,10 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||
// cases...
|
||||
nsRect lineCombinedArea;
|
||||
line->GetCombinedArea(&lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
||||
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, lineCombinedArea);
|
||||
line->Destroy(presShell);
|
||||
line = next;
|
||||
@ -5282,8 +5341,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
|
||||
// Setup block reflow state to reflow the floater
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// Reflow the floater
|
||||
@ -5324,7 +5383,7 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
floater->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
// If we computed it, then stash away the max-element-size for later
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.StoreMaxElementSize(floater, brc.GetMaxElementSize());
|
||||
}
|
||||
|
||||
@ -5389,7 +5448,7 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
@ -5615,7 +5674,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
}
|
||||
else {
|
||||
isLeftFloater = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
else {
|
||||
okToAddRectRegion = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.x;
|
||||
}
|
||||
}
|
||||
*aIsLeftFloater = isLeftFloater;
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
@ -5682,7 +5746,8 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
nsRect combinedArea = aFloaterCache->mCombinedArea;
|
||||
combinedArea.x += x;
|
||||
combinedArea.y += y;
|
||||
if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
|
||||
if (!isLeftFloater &&
|
||||
(GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// When we are placing a right floater in an unconstrained situation or
|
||||
// when shrink wrapping, we don't apply it to the floater combined area
|
||||
// immediately. Otherwise we end up with an infinitely wide combined
|
||||
|
@ -879,6 +879,13 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nsHTMLAtoms::width == aAttribute || nsHTMLAtoms::height == aAttribute)
|
||||
{ // XXX: could check for new width == old width, and make that a no-op
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
aPresContext->GetShell(getter_AddRefs(presShell));
|
||||
mState |= NS_FRAME_IS_DIRTY;
|
||||
mParent->ReflowDirtyChild(presShell, (nsIFrame*) this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -18,8 +18,10 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* L. David Baron <dbaron@fas.harvard.edu>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLineLayout.h"
|
||||
@ -41,13 +43,14 @@
|
||||
#include "nsIView.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsTextFragment.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#undef NOISY_HORIZONTAL_ALIGN
|
||||
#undef NOISY_VERTICAL_ALIGN
|
||||
#undef REALLY_NOISY_VERTICAL_ALIGN
|
||||
#undef NOISY_REFLOW
|
||||
#undef REALLY_NOISY_REFLOW
|
||||
#undef REALLY_NOISY_REFLOW
|
||||
#undef NOISY_PUSHING
|
||||
#undef REALLY_NOISY_PUSHING
|
||||
#undef DEBUG_ADD_TEXT
|
||||
@ -120,15 +123,9 @@ nsLineLayout::nsLineLayout(nsIPresContext* aPresContext,
|
||||
mTextAlign = mStyleText->mTextAlign;
|
||||
mLineNumber = 0;
|
||||
mColumn = 0;
|
||||
mEndsInWhiteSpace = PR_TRUE;
|
||||
mUnderstandsWhiteSpace = PR_FALSE;
|
||||
mTextStartsWithNBSP = PR_FALSE;
|
||||
mFirstLetterStyleOK = PR_FALSE;
|
||||
mIsTopOfPage = PR_FALSE;
|
||||
mUpdatedBand = PR_FALSE;
|
||||
mFlags = 0; // default all flags to false except those that follow here...
|
||||
SetFlag(LL_ENDSINWHITESPACE, PR_TRUE);
|
||||
mPlacedFloaters = 0;
|
||||
mImpactedByFloaters = PR_FALSE;
|
||||
mLastFloaterWasLetterFrame = PR_FALSE;
|
||||
mTotalPlacedFrames = 0;
|
||||
mTopEdge = mBottomEdge = 0;
|
||||
mReflowTextRuns = nsnull;
|
||||
@ -148,14 +145,17 @@ nsLineLayout::nsLineLayout(nsIPresContext* aPresContext,
|
||||
mTextRuns = nsnull;
|
||||
mTextRunP = &mTextRuns;
|
||||
mNewTextRun = nsnull;
|
||||
mKnowStrictMode = PR_FALSE;
|
||||
SetFlag(LL_KNOWSTRICTMODE, PR_FALSE);
|
||||
PRInt32 size = sizeof nsLineLayout;
|
||||
PRInt32 size_pfd = sizeof PerFrameData;
|
||||
PRInt32 size_psd = sizeof PerSpanData;
|
||||
}
|
||||
|
||||
nsLineLayout::nsLineLayout(nsIPresContext* aPresContext)
|
||||
: mPresContext(aPresContext)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsLineLayout);
|
||||
|
||||
|
||||
mTextRuns = nsnull;
|
||||
mTextRunP = &mTextRuns;
|
||||
mNewTextRun = nsnull;
|
||||
@ -197,9 +197,9 @@ nsLineLayout::~nsLineLayout()
|
||||
PRBool
|
||||
nsLineLayout::InStrictMode()
|
||||
{
|
||||
if (!mKnowStrictMode) {
|
||||
mKnowStrictMode = PR_TRUE;
|
||||
mInStrictMode = PR_TRUE;
|
||||
if (!GetFlag(LL_KNOWSTRICTMODE)) {
|
||||
SetFlag(LL_KNOWSTRICTMODE, PR_TRUE);
|
||||
SetFlag(LL_INSTRICTMODE, PR_TRUE);
|
||||
|
||||
// Get the compatabilty mode from pres context via the document and pres shell
|
||||
if (mBlockReflowState->frame) {
|
||||
@ -217,7 +217,7 @@ nsLineLayout::InStrictMode()
|
||||
nsCompatibility mode;
|
||||
presContext->GetCompatibilityMode(&mode);
|
||||
if (eCompatibility_NavQuirks == mode) {
|
||||
mInStrictMode = PR_FALSE;
|
||||
SetFlag(LL_INSTRICTMODE, PR_FALSE);
|
||||
}
|
||||
}
|
||||
NS_RELEASE(shell);
|
||||
@ -226,7 +226,7 @@ nsLineLayout::InStrictMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
return mInStrictMode;
|
||||
return GetFlag(LL_INSTRICTMODE);
|
||||
}
|
||||
|
||||
void
|
||||
@ -235,10 +235,6 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
||||
PRBool aImpactedByFloaters,
|
||||
PRBool aIsTopOfPage)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("nsLL::BeginLineReflow %d, %d, %d, %d, impacted=%s\n",
|
||||
aX, aY, aWidth, aHeight, aImpactedByFloaters?"true":"false");
|
||||
#endif
|
||||
NS_ASSERTION(nsnull == mRootSpan, "bad linelayout user");
|
||||
#ifdef DEBUG
|
||||
if ((aWidth != NS_UNCONSTRAINEDSIZE) && CRAZY_WIDTH(aWidth)) {
|
||||
@ -256,8 +252,9 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
||||
#endif
|
||||
#ifdef NOISY_REFLOW
|
||||
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
||||
printf(": BeginLineReflow: %d,%d,%d,%d %s\n",
|
||||
printf(": BeginLineReflow: %d,%d,%d,%d impacted=%s %s\n",
|
||||
aX, aY, aWidth, aHeight,
|
||||
aImpactedByFloaters?"true":"false",
|
||||
aIsTopOfPage ? "top-of-page" : "");
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
@ -265,17 +262,18 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
||||
#endif
|
||||
|
||||
mColumn = 0;
|
||||
mEndsInWhiteSpace = PR_TRUE;
|
||||
mUnderstandsWhiteSpace = PR_FALSE;
|
||||
mTextStartsWithNBSP = PR_FALSE;
|
||||
mFirstLetterStyleOK = PR_FALSE;
|
||||
mIsTopOfPage = aIsTopOfPage;
|
||||
mUpdatedBand = PR_FALSE;
|
||||
|
||||
SetFlag(LL_ENDSINWHITESPACE, PR_TRUE);
|
||||
SetFlag(LL_UNDERSTANDSNWHITESPACE, PR_FALSE);
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, PR_FALSE);
|
||||
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);
|
||||
SetFlag(LL_ISTOPOFPAGE, aIsTopOfPage);
|
||||
SetFlag(LL_UPDATEDBAND, PR_FALSE);
|
||||
mPlacedFloaters = 0;
|
||||
mImpactedByFloaters = aImpactedByFloaters;
|
||||
SetFlag(LL_IMPACTEDBYFLOATERS, aImpactedByFloaters);
|
||||
mTotalPlacedFrames = 0;
|
||||
mCanPlaceFloater = PR_TRUE;
|
||||
mLineEndsInBR = PR_FALSE;
|
||||
SetFlag(LL_CANPLACEFLOATER, PR_TRUE);
|
||||
SetFlag(LL_LINEENDSINBR, PR_FALSE);
|
||||
mSpanDepth = 0;
|
||||
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
||||
|
||||
@ -355,7 +353,7 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
||||
nsIFrame* aFloaterFrame)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p placedLeft=%s\n will set mImpacted to PR_TRUE",
|
||||
printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p placedLeft=%s\n will set mImpacted to PR_TRUE\n",
|
||||
aX, aY, aWidth, aHeight, aFloaterFrame, aPlacedLeftFloater?"true":"false");
|
||||
#endif
|
||||
PerSpanData* psd = mRootSpan;
|
||||
@ -404,13 +402,13 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
||||
else {
|
||||
mBottomEdge = aY + aHeight;
|
||||
}
|
||||
mUpdatedBand = PR_TRUE;
|
||||
SetFlag(LL_UPDATEDBAND, PR_TRUE);
|
||||
mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT);
|
||||
mImpactedByFloaters = PR_TRUE;
|
||||
SetFlag(LL_IMPACTEDBYFLOATERS, PR_TRUE);
|
||||
|
||||
nsCOMPtr<nsIAtom> frameType;
|
||||
aFloaterFrame->GetFrameType(getter_AddRefs(frameType));
|
||||
mLastFloaterWasLetterFrame = nsLayoutAtoms::letterFrame == frameType.get();
|
||||
SetFlag(LL_LASTFLOATERWASLETTERFRAME, (nsLayoutAtoms::letterFrame == frameType.get()));
|
||||
|
||||
// Now update all of the open spans...
|
||||
mRootSpan->mContainsFloater = PR_TRUE; // make sure mRootSpan gets updated too
|
||||
@ -762,17 +760,10 @@ nsLineLayout::NewPerFrameData(PerFrameData** aResult)
|
||||
pfd->mNext = nsnull;
|
||||
pfd->mPrev = nsnull;
|
||||
pfd->mFrame = nsnull;
|
||||
pfd->mRelativePos = PR_FALSE;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
pfd->mIsNonWhitespaceTextFrame = PR_FALSE;
|
||||
pfd->mIsLetterFrame = PR_FALSE;
|
||||
pfd->mIsSticky = PR_FALSE;
|
||||
|
||||
pfd->mFlags = 0; // all flags default to false
|
||||
|
||||
#ifdef DEBUG
|
||||
pfd->mVerticalAlign = 0xFF;
|
||||
pfd->mRelativePos = PRBool(0xFF);
|
||||
mFramesAllocated++;
|
||||
#endif
|
||||
*aResult = pfd;
|
||||
@ -782,7 +773,7 @@ nsLineLayout::NewPerFrameData(PerFrameData** aResult)
|
||||
PRBool
|
||||
nsLineLayout::CanPlaceFloaterNow() const
|
||||
{
|
||||
return mCanPlaceFloater;
|
||||
return GetFlag(LL_CANPLACEFLOATER);
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -794,7 +785,7 @@ nsLineLayout::LineIsEmpty() const
|
||||
PRBool
|
||||
nsLineLayout::LineIsBreakable() const
|
||||
{
|
||||
if ((0 != mTotalPlacedFrames) || mImpactedByFloaters) {
|
||||
if ((0 != mTotalPlacedFrames) || GetFlag(LL_IMPACTEDBYFLOATERS)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
@ -903,9 +894,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
nsHTMLReflowState reflowState(mPresContext, *psd->mReflowState, aFrame,
|
||||
availSize, reason);
|
||||
reflowState.mLineLayout = this;
|
||||
reflowState.isTopOfPage = mIsTopOfPage;
|
||||
mUnderstandsWhiteSpace = PR_FALSE;
|
||||
mTextStartsWithNBSP = PR_FALSE;
|
||||
reflowState.isTopOfPage = GetFlag(LL_ISTOPOFPAGE);
|
||||
SetFlag(LL_UNDERSTANDSNWHITESPACE, PR_FALSE);
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, PR_FALSE);
|
||||
mTextJustificationNumSpaces = 0;
|
||||
mTextJustificationNumLetters = 0;
|
||||
|
||||
// Stash copies of some of the computed state away for later
|
||||
// (vertical alignment, for example)
|
||||
@ -913,9 +906,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
pfd->mMargin = reflowState.mComputedMargin;
|
||||
pfd->mBorderPadding = reflowState.mComputedBorderPadding;
|
||||
pfd->mFrameType = reflowState.mFrameType;
|
||||
pfd->mRelativePos =
|
||||
reflowState.mStylePosition->mPosition == NS_STYLE_POSITION_RELATIVE;
|
||||
if (pfd->mRelativePos) {
|
||||
pfd->SetFlag(PFD_RELATIVEPOS,
|
||||
(reflowState.mStylePosition->mPosition == NS_STYLE_POSITION_RELATIVE));
|
||||
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
||||
pfd->mOffsets = reflowState.mComputedOffsets;
|
||||
}
|
||||
|
||||
@ -969,14 +962,18 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
nscoord ty = y - psd->mReflowState->mComputedBorderPadding.top;
|
||||
mSpaceManager->Translate(tx, ty);
|
||||
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsLetterFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
pfd->mIsNonWhitespaceTextFrame = PR_FALSE;
|
||||
pfd->mIsSticky = PR_FALSE;
|
||||
pfd->SetFlag(PFD_ISTEXTFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISLETTERFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISNONEMPTYTEXTFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISNONWHITESPACETEXTFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISBULLET, PR_FALSE);
|
||||
|
||||
aFrame->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
||||
|
||||
pfd->mJustificationNumSpaces = mTextJustificationNumSpaces;
|
||||
pfd->mJustificationNumLetters = mTextJustificationNumLetters;
|
||||
|
||||
// XXX See if the frame is a placeholderFrame and if it is process
|
||||
// the floater.
|
||||
nsIAtom* frameType;
|
||||
@ -1000,7 +997,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
outOfFlowFrame->GetFrameType(&oofft);
|
||||
if (oofft) {
|
||||
if (oofft == nsLayoutAtoms::letterFrame) {
|
||||
mFirstLetterStyleOK = PR_FALSE;
|
||||
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);
|
||||
}
|
||||
NS_RELEASE(oofft);
|
||||
}
|
||||
@ -1009,11 +1006,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
}
|
||||
else if (frameType == nsLayoutAtoms::textFrame) {
|
||||
// Note non-empty text-frames for inline frame compatability hackery
|
||||
pfd->mIsTextFrame = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISTEXTFRAME, PR_TRUE);
|
||||
// XXX An empty text frame at the end of the line seems not
|
||||
// to have zero width.
|
||||
if (metrics.width) {
|
||||
pfd->mIsNonEmptyTextFrame = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISNONEMPTYTEXTFRAME, PR_TRUE);
|
||||
nsCOMPtr<nsIContent> content;
|
||||
nsresult result = pfd->mFrame->GetContent(getter_AddRefs(content));
|
||||
if ((NS_SUCCEEDED(result)) && content) {
|
||||
@ -1023,14 +1020,14 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
PRBool isWhitespace;
|
||||
result = textContent->IsOnlyWhitespace(&isWhitespace);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
pfd->mIsNonWhitespaceTextFrame = !isWhitespace;
|
||||
pfd->SetFlag(PFD_ISNONWHITESPACETEXTFRAME, !isWhitespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (frameType == nsLayoutAtoms::letterFrame) {
|
||||
pfd->mIsLetterFrame = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISLETTERFRAME, PR_TRUE);
|
||||
}
|
||||
NS_RELEASE(frameType);
|
||||
}
|
||||
@ -1170,7 +1167,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
else {
|
||||
PushFrame(aFrame);
|
||||
}
|
||||
mTextStartsWithNBSP = PR_FALSE; // reset for next time
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, PR_FALSE); // reset for next time
|
||||
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
nsFrame::IndentBy(stdout, mSpanDepth);
|
||||
@ -1330,7 +1327,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
// There are no frames on the line or we are in the first word on
|
||||
// the line. If the line isn't impacted by a floater then the
|
||||
// current frame fits.
|
||||
if (!mImpactedByFloaters) {
|
||||
if (!GetFlag(LL_IMPACTEDBYFLOATERS)) {
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> not-safe and not-impacted fits: ");
|
||||
while (nsnull != psd) {
|
||||
@ -1341,28 +1338,28 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
#endif
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (mLastFloaterWasLetterFrame) {
|
||||
else if (GetFlag(LL_LASTFLOATERWASLETTERFRAME)) {
|
||||
// Another special case: see if the floater is a letter
|
||||
// frame. If it is, then allow the frame next to it to fit.
|
||||
if (pfd->mIsNonEmptyTextFrame) {
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
// This must be the first piece of non-empty text (because
|
||||
// aNotSafeToBreak is true) or its a piece of text that is
|
||||
// part of a larger word.
|
||||
pfd->mIsSticky = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
||||
}
|
||||
else if (pfd->mSpan) {
|
||||
PerFrameData* pf = pfd->mSpan->mFirstFrame;
|
||||
while (pf) {
|
||||
if (pf->mIsSticky) {
|
||||
if (pf->GetFlag(PFD_ISSTICKY)) {
|
||||
// If one of the spans children was sticky then the span
|
||||
// itself is sticky.
|
||||
pfd->mIsSticky = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
||||
}
|
||||
pf = pf->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
if (pfd->mIsSticky) {
|
||||
if (pfd->GetFlag(PFD_ISSTICKY)) {
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> last floater was letter frame && frame is sticky\n");
|
||||
#endif
|
||||
@ -1372,8 +1369,8 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
}
|
||||
|
||||
// If this is a piece of text inside a letter frame...
|
||||
if (pfd->mIsNonEmptyTextFrame) {
|
||||
if (psd->mFrame && psd->mFrame->mIsLetterFrame) {
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
if (psd->mFrame && psd->mFrame->GetFlag(PFD_ISLETTERFRAME)) {
|
||||
nsIFrame* prevInFlow;
|
||||
psd->mFrame->mFrame->GetPrevInFlow(&prevInFlow);
|
||||
if (prevInFlow) {
|
||||
@ -1387,7 +1384,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pfd->mIsLetterFrame) {
|
||||
else if (pfd->GetFlag(PFD_ISLETTERFRAME)) {
|
||||
// If this is the first continuation of the letter frame...
|
||||
nsIFrame* prevInFlow;
|
||||
pfd->mFrame->GetPrevInFlow(&prevInFlow);
|
||||
@ -1433,7 +1430,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
// edge...Which means that whatever piece of text we just formatted
|
||||
// will be the piece that fits (the text frame logic knows to stop
|
||||
// when it runs out of room).
|
||||
if (pfd->mIsNonEmptyTextFrame && mTextStartsWithNBSP) {
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME) && GetFlag(LL_TEXTSTARTSWITHNBSP)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -1467,9 +1464,9 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
||||
|
||||
// If the band was updated during the reflow of that frame then we
|
||||
// need to adjust any prior frames that were reflowed.
|
||||
if (mUpdatedBand && InBlockContext()) {
|
||||
if (GetFlag(LL_UPDATEDBAND) && InBlockContext()) {
|
||||
UpdateFrames();
|
||||
mUpdatedBand = PR_FALSE;
|
||||
SetFlag(LL_UPDATEDBAND, PR_FALSE);
|
||||
}
|
||||
|
||||
// Advance to next X coordinate
|
||||
@ -1478,8 +1475,8 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
||||
// If the frame is a not aware of white-space and it takes up some
|
||||
// width, disable leading white-space compression for the next frame
|
||||
// to be reflowed.
|
||||
if (!mUnderstandsWhiteSpace && pfd->mBounds.width) {
|
||||
mEndsInWhiteSpace = PR_FALSE;
|
||||
if ((!GetFlag(LL_UNDERSTANDSNWHITESPACE)) && pfd->mBounds.width) {
|
||||
SetFlag(LL_ENDSINWHITESPACE, PR_FALSE);
|
||||
}
|
||||
|
||||
// Count the number of frames on the line...
|
||||
@ -1487,7 +1484,7 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
||||
if (psd->mX != psd->mLeftEdge) {
|
||||
// As soon as a frame placed on the line advances an X coordinate
|
||||
// of any span we can no longer place a floater on the line.
|
||||
mCanPlaceFloater = PR_FALSE;
|
||||
SetFlag(LL_CANPLACEFLOATER, PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1505,14 +1502,10 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
||||
pfd->mMargin.SizeTo(0, 0, 0, 0);
|
||||
pfd->mBorderPadding.SizeTo(0, 0, 0, 0);
|
||||
pfd->mFrameType = NS_CSS_FRAME_TYPE_INLINE|NS_FRAME_REPLACED_ELEMENT;
|
||||
pfd->mRelativePos = PR_FALSE;
|
||||
pfd->mFlags = 0; // all flags default to false
|
||||
pfd->SetFlag(PFD_ISBULLET, PR_TRUE);
|
||||
pfd->mAscent = aMetrics.ascent;
|
||||
pfd->mDescent = aMetrics.descent;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
pfd->mIsNonWhitespaceTextFrame = PR_FALSE;
|
||||
pfd->mIsLetterFrame = PR_FALSE;
|
||||
pfd->mIsSticky = PR_FALSE;
|
||||
|
||||
// Note: y value will be updated during vertical alignment
|
||||
aFrame->GetRect(pfd->mBounds);
|
||||
@ -1857,7 +1850,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
||||
zeroEffectiveSpanBox = PR_TRUE;
|
||||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
while (nsnull != pfd) {
|
||||
if (preMode?pfd->mIsTextFrame:pfd->mIsNonWhitespaceTextFrame) {
|
||||
if (preMode?pfd->GetFlag(PFD_ISTEXTFRAME):pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) {
|
||||
zeroEffectiveSpanBox = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
@ -2154,7 +2147,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
||||
if (pfd->mVerticalAlign == VALIGN_OTHER) {
|
||||
// Text frames do not contribute to the min/max Y values for the
|
||||
// line (instead their parent frame's font-size contributes).
|
||||
if (!pfd->mIsTextFrame) {
|
||||
if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
nscoord yTop, yBottom;
|
||||
if (frameSpan) {
|
||||
// For spans that were are now placing, use their position
|
||||
@ -2212,7 +2205,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
||||
// BR) (NN4/IE5 quirk)
|
||||
PRBool applyMinLH = !(psd->mZeroEffectiveSpanBox); // (1) above
|
||||
PRBool isFirstLine = !mLineNumber; // if the line number is 0
|
||||
PRBool isLastLine = (!mLineBox->IsLineWrapped() && !mLineEndsInBR);
|
||||
PRBool isLastLine = (!mLineBox->IsLineWrapped() && !GetFlag(LL_LINEENDSINBR));
|
||||
//PRBool isLastLine = mBlockRS->mCurLine->IsLineWrapped();
|
||||
if (!applyMinLH && (isFirstLine || isLastLine)) {
|
||||
nsCOMPtr<nsIContent> blockContent;
|
||||
@ -2412,13 +2405,13 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
else if (!pfd->mIsTextFrame) {
|
||||
else if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
// If we hit a frame on the end that's not text, then there is
|
||||
// no trailing whitespace to trim. Stop the search.
|
||||
*aDeltaWidth = 0;
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (pfd->mIsNonEmptyTextFrame) {
|
||||
else if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
nscoord deltaWidth = 0;
|
||||
pfd->mFrame->TrimTrailingWhiteSpace(mPresContext,
|
||||
*mBlockReflowState->rendContext,
|
||||
@ -2432,6 +2425,10 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
|
||||
printf(" returned %d\n", deltaWidth);
|
||||
#endif
|
||||
if (deltaWidth) {
|
||||
if (pfd->mJustificationNumSpaces > 0) {
|
||||
pfd->mJustificationNumSpaces--;
|
||||
}
|
||||
|
||||
pfd->mBounds.width -= deltaWidth;
|
||||
pfd->mCombinedArea.width -= deltaWidth;
|
||||
if (0 == pfd->mBounds.width) {
|
||||
@ -2479,6 +2476,95 @@ nsLineLayout::TrimTrailingWhiteSpace()
|
||||
return 0 != deltaWidth;
|
||||
}
|
||||
|
||||
void
|
||||
nsLineLayout::ComputeJustificationWeights(PerSpanData* aPSD,
|
||||
PRInt32* aNumSpaces,
|
||||
PRInt32* aNumLetters)
|
||||
{
|
||||
NS_ASSERTION(aPSD, "null arg");
|
||||
NS_ASSERTION(aNumSpaces, "null arg");
|
||||
NS_ASSERTION(aNumLetters, "null arg");
|
||||
PRInt32 numSpaces = 0;
|
||||
PRInt32 numLetters = 0;
|
||||
|
||||
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
|
||||
nscoord dw = 0;
|
||||
|
||||
if (PR_TRUE == pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
numSpaces += pfd->mJustificationNumSpaces;
|
||||
numLetters += pfd->mJustificationNumLetters;
|
||||
}
|
||||
else if (pfd->mSpan != nsnull) {
|
||||
PRInt32 spanSpaces;
|
||||
PRInt32 spanLetters;
|
||||
|
||||
ComputeJustificationWeights(pfd->mSpan, &spanSpaces, &spanLetters);
|
||||
|
||||
numSpaces += spanSpaces;
|
||||
numLetters += spanLetters;
|
||||
}
|
||||
}
|
||||
|
||||
*aNumSpaces = numSpaces;
|
||||
*aNumLetters = numLetters;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState* aState)
|
||||
{
|
||||
NS_ASSERTION(aPSD, "null arg");
|
||||
NS_ASSERTION(aState, "null arg");
|
||||
|
||||
nscoord deltaX = 0;
|
||||
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
|
||||
// Don't reposition bullets (and other frames that occur out of X-order?)
|
||||
if (!pfd->GetFlag(PFD_ISBULLET)) {
|
||||
nscoord dw = 0;
|
||||
|
||||
pfd->mBounds.x += deltaX;
|
||||
|
||||
if (PR_TRUE == pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
if (aState->mTotalWidthForSpaces > 0 &&
|
||||
aState->mTotalNumSpaces > 0 && // we divide by this value, so must be non-zero
|
||||
aState->mTotalNumLetters >0 // we divide by this value, so must be non-zero
|
||||
) {
|
||||
aState->mNumSpacesProcessed += pfd->mJustificationNumSpaces;
|
||||
|
||||
nscoord newAllocatedWidthForSpaces =
|
||||
(aState->mTotalWidthForSpaces*aState->mNumSpacesProcessed)
|
||||
/aState->mTotalNumSpaces;
|
||||
|
||||
dw += newAllocatedWidthForSpaces - aState->mWidthForSpacesProcessed;
|
||||
|
||||
aState->mWidthForSpacesProcessed = newAllocatedWidthForSpaces;
|
||||
}
|
||||
|
||||
if (aState->mTotalWidthForLetters > 0) {
|
||||
aState->mNumLettersProcessed += pfd->mJustificationNumLetters;
|
||||
|
||||
nscoord newAllocatedWidthForLetters =
|
||||
(aState->mTotalWidthForLetters*aState->mNumLettersProcessed)
|
||||
/aState->mTotalNumLetters;
|
||||
|
||||
dw += newAllocatedWidthForLetters - aState->mWidthForLettersProcessed;
|
||||
|
||||
aState->mWidthForLettersProcessed = newAllocatedWidthForLetters;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (nsnull != pfd->mSpan) {
|
||||
dw += ApplyFrameJustification(pfd->mSpan, aState);
|
||||
}
|
||||
}
|
||||
|
||||
pfd->mBounds.width += dw;
|
||||
deltaX += dw;
|
||||
pfd->mFrame->SetRect(mPresContext, pfd->mBounds);
|
||||
}
|
||||
}
|
||||
return deltaX;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
|
||||
PRBool aAllowJustify,
|
||||
@ -2525,7 +2611,18 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
|
||||
// frames in the line. If it is the last line then if the
|
||||
// direction is right-to-left then we right-align the frames.
|
||||
if (aAllowJustify) {
|
||||
break;
|
||||
if (!aShrinkWrapWidth) {
|
||||
PRInt32 numSpaces;
|
||||
PRInt32 numLetters;
|
||||
|
||||
ComputeJustificationWeights(psd, &numSpaces, &numLetters);
|
||||
|
||||
if (numSpaces > 0) {
|
||||
FrameJustificationState state = { numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 };
|
||||
|
||||
ApplyFrameJustification(psd, &state);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
|
||||
// right align the frames
|
||||
@ -2617,7 +2714,7 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
|
||||
nscoord y = pfd->mBounds.y;
|
||||
|
||||
// Adjust the origin of the frame
|
||||
if (pfd->mRelativePos) {
|
||||
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
||||
nsIFrame* frame = pfd->mFrame;
|
||||
frame->GetOrigin(origin);
|
||||
// XXX what about right and bottom?
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
*/
|
||||
#ifndef nsLineLayout_h___
|
||||
#define nsLineLayout_h___
|
||||
@ -32,7 +34,7 @@ class nsBlockReflowState;
|
||||
class nsPlaceholderFrame;
|
||||
struct nsStyleText;
|
||||
|
||||
#define NS_LINELAYOUT_NUM_FRAMES 10
|
||||
#define NS_LINELAYOUT_NUM_FRAMES 5
|
||||
#define NS_LINELAYOUT_NUM_SPANS 5
|
||||
|
||||
class nsLineLayout {
|
||||
@ -122,23 +124,69 @@ public:
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// Supporting methods and data for flags
|
||||
protected:
|
||||
#define LL_ENDSINWHITESPACE 0x00000001
|
||||
#define LL_UNDERSTANDSNWHITESPACE 0x00000002
|
||||
#define LL_TEXTSTARTSWITHNBSP 0x00000004
|
||||
#define LL_FIRSTLETTERSTYLEOK 0x00000008
|
||||
#define LL_ISTOPOFPAGE 0x00000010
|
||||
#define LL_UPDATEDBAND 0x00000020
|
||||
#define LL_IMPACTEDBYFLOATERS 0x00000040
|
||||
#define LL_LASTFLOATERWASLETTERFRAME 0x00000080
|
||||
#define LL_CANPLACEFLOATER 0x00000100
|
||||
#define LL_KNOWSTRICTMODE 0x00000200
|
||||
#define LL_INSTRICTMODE 0x00000400
|
||||
#define LL_LINEENDSINBR 0x00000800
|
||||
#define LL_LASTFLAG LL_LINEENDSINBR
|
||||
|
||||
PRUint16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=LL_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=LL_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Support methods for white-space compression and word-wrapping
|
||||
// during line reflow
|
||||
|
||||
void SetEndsInWhiteSpace(PRBool aState) {
|
||||
mEndsInWhiteSpace = aState;
|
||||
SetFlag(LL_ENDSINWHITESPACE, aState);
|
||||
}
|
||||
|
||||
PRBool GetEndsInWhiteSpace() const {
|
||||
return mEndsInWhiteSpace;
|
||||
return GetFlag(LL_ENDSINWHITESPACE);
|
||||
}
|
||||
|
||||
void SetUnderstandsWhiteSpace(PRBool aSetting) {
|
||||
mUnderstandsWhiteSpace = aSetting;
|
||||
SetFlag(LL_UNDERSTANDSNWHITESPACE, aSetting);
|
||||
}
|
||||
|
||||
void SetTextJustificationWeights(PRInt32 aNumSpaces, PRInt32 aNumLetters) {
|
||||
mTextJustificationNumSpaces = aNumSpaces;
|
||||
mTextJustificationNumLetters = aNumLetters;
|
||||
}
|
||||
|
||||
|
||||
void SetTextStartsWithNBSP(PRBool aYes) {
|
||||
mTextStartsWithNBSP = aYes;
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, aYes);
|
||||
}
|
||||
|
||||
void RecordWordFrame(nsIFrame* aWordFrame) {
|
||||
@ -163,9 +211,15 @@ public:
|
||||
|
||||
PRBool LineIsBreakable() const;
|
||||
|
||||
PRBool GetLineEndsInBR() const { return mLineEndsInBR; }
|
||||
PRBool GetLineEndsInBR() const
|
||||
{
|
||||
return GetFlag(LL_LINEENDSINBR);
|
||||
}
|
||||
|
||||
void SetLineEndsInBR(PRBool aOn) { mLineEndsInBR = aOn; }
|
||||
void SetLineEndsInBR(PRBool aOn)
|
||||
{
|
||||
SetFlag(LL_LINEENDSINBR, aOn);
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Inform the line-layout about the presence of a floating frame
|
||||
@ -176,11 +230,11 @@ public:
|
||||
//----------------------------------------
|
||||
|
||||
PRBool GetFirstLetterStyleOK() const {
|
||||
return mFirstLetterStyleOK;
|
||||
return GetFlag(LL_FIRSTLETTERSTYLEOK);
|
||||
}
|
||||
|
||||
void SetFirstLetterStyleOK(PRBool aSetting) {
|
||||
mFirstLetterStyleOK = aSetting;
|
||||
SetFlag(LL_FIRSTLETTERSTYLEOK, aSetting);
|
||||
}
|
||||
|
||||
void SetFirstLetterFrame(nsIFrame* aFrame) {
|
||||
@ -233,19 +287,11 @@ protected:
|
||||
nsIFrame* mFirstLetterFrame;
|
||||
PRInt32 mLineNumber;
|
||||
PRInt32 mColumn;
|
||||
PRInt32 mTextJustificationNumSpaces;
|
||||
PRInt32 mTextJustificationNumLetters;
|
||||
|
||||
nsLineBox* mLineBox;
|
||||
PRPackedBool mEndsInWhiteSpace;
|
||||
PRPackedBool mUnderstandsWhiteSpace;
|
||||
PRPackedBool mTextStartsWithNBSP;
|
||||
PRPackedBool mFirstLetterStyleOK;
|
||||
PRPackedBool mIsTopOfPage;
|
||||
PRPackedBool mUpdatedBand;
|
||||
PRPackedBool mImpactedByFloaters;
|
||||
PRPackedBool mLastFloaterWasLetterFrame;
|
||||
PRPackedBool mCanPlaceFloater;
|
||||
PRPackedBool mKnowStrictMode;
|
||||
PRPackedBool mInStrictMode;
|
||||
PRPackedBool mLineEndsInBR;
|
||||
|
||||
PRUint8 mPlacedFloaters;
|
||||
PRInt32 mTotalPlacedFrames;
|
||||
nsVoidArray mWordFrames;
|
||||
@ -294,15 +340,47 @@ protected:
|
||||
nsMargin mMargin;
|
||||
nsMargin mBorderPadding;
|
||||
nsMargin mOffsets;
|
||||
PRPackedBool mRelativePos;
|
||||
|
||||
// Other state we use
|
||||
PRUint8 mVerticalAlign;
|
||||
PRPackedBool mIsTextFrame;
|
||||
PRPackedBool mIsNonEmptyTextFrame;
|
||||
PRPackedBool mIsNonWhitespaceTextFrame;
|
||||
PRPackedBool mIsLetterFrame;
|
||||
PRPackedBool mIsSticky;
|
||||
|
||||
// state for text justification
|
||||
PRInt32 mJustificationNumSpaces;
|
||||
PRInt32 mJustificationNumLetters;
|
||||
|
||||
|
||||
// PerFrameData flags
|
||||
#define PFD_RELATIVEPOS 0x00000001
|
||||
#define PFD_ISTEXTFRAME 0x00000002
|
||||
#define PFD_ISNONEMPTYTEXTFRAME 0x00000004
|
||||
#define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
|
||||
#define PFD_ISLETTERFRAME 0x00000010
|
||||
#define PFD_ISSTICKY 0x00000020
|
||||
#define PFD_ISBULLET 0x00000040
|
||||
#define PFD_LASTFLAG PFD_ISBULLET
|
||||
|
||||
PRPackedBool mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
PerFrameData* Last() {
|
||||
PerFrameData* pfd = this;
|
||||
@ -409,6 +487,22 @@ protected:
|
||||
|
||||
PRBool TrimTrailingWhiteSpaceIn(PerSpanData* psd, nscoord* aDeltaWidth);
|
||||
|
||||
|
||||
void ComputeJustificationWeights(PerSpanData* psd, PRInt32* numSpaces, PRInt32* numLetters);
|
||||
|
||||
struct FrameJustificationState {
|
||||
PRInt32 mTotalNumSpaces;
|
||||
PRInt32 mTotalNumLetters;
|
||||
nscoord mTotalWidthForSpaces;
|
||||
nscoord mTotalWidthForLetters;
|
||||
PRInt32 mNumSpacesProcessed;
|
||||
PRInt32 mNumLettersProcessed;
|
||||
nscoord mWidthForSpacesProcessed;
|
||||
nscoord mWidthForLettersProcessed;
|
||||
};
|
||||
nscoord ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState* aState);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent);
|
||||
#endif
|
||||
|
@ -19,6 +19,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHTMLParts.h"
|
||||
@ -458,9 +459,10 @@ public:
|
||||
nscoord mAveCharWidth;
|
||||
PRBool mJustifying;
|
||||
PRBool mPreformatted;
|
||||
PRIntn mNumSpaces;
|
||||
PRInt32 mNumSpacesToRender;
|
||||
PRInt32 mNumSpacesToMeasure;
|
||||
nscoord mExtraSpacePerSpace;
|
||||
nscoord mRemainingExtraSpace;
|
||||
PRInt32 mNumSpacesReceivingExtraJot;
|
||||
|
||||
TextStyle(nsIPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
@ -521,20 +523,25 @@ public:
|
||||
|
||||
// Get the word and letter spacing
|
||||
mWordSpacing = 0;
|
||||
mLetterSpacing = 0;
|
||||
PRIntn unit = mText->mWordSpacing.GetUnit();
|
||||
if (eStyleUnit_Coord == unit) {
|
||||
mWordSpacing = mText->mWordSpacing.GetCoordValue();
|
||||
}
|
||||
|
||||
mLetterSpacing = 0;
|
||||
unit = mText->mLetterSpacing.GetUnit();
|
||||
if (eStyleUnit_Coord == unit) {
|
||||
mLetterSpacing = mText->mLetterSpacing.GetCoordValue();
|
||||
}
|
||||
mNumSpaces = 0;
|
||||
mRemainingExtraSpace = 0;
|
||||
mNumSpacesToRender = 0;
|
||||
mNumSpacesToMeasure = 0;
|
||||
mNumSpacesReceivingExtraJot = 0;
|
||||
mExtraSpacePerSpace = 0;
|
||||
mPreformatted = (NS_STYLE_WHITESPACE_PRE == mText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == mText->mWhiteSpace);
|
||||
|
||||
mJustifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mText->mTextAlign) &&
|
||||
!mPreformatted;
|
||||
}
|
||||
|
||||
~TextStyle() {
|
||||
@ -590,6 +597,9 @@ public:
|
||||
nsAutoIndexBuffer* aIndexBuffer,
|
||||
nsAutoTextBuffer* aTextBuffer,
|
||||
PRInt32* aTextLen);
|
||||
void ComputeExtraJustificationSpacing(nsIRenderingContext& aRenderingContext,
|
||||
TextStyle& aTextStyle,
|
||||
PRUnichar* aBuffer, PRInt32 aLength, PRInt32 aNumSpaces);
|
||||
|
||||
void PaintTextDecorations(nsIRenderingContext& aRenderingContext,
|
||||
nsIStyleContext* aStyleContext,
|
||||
@ -1192,7 +1202,8 @@ nsTextFrame::Paint(nsIPresContext* aPresContext,
|
||||
sc->GetStyleData(eStyleStruct_Display);
|
||||
if (disp->IsVisible()) {
|
||||
TextStyle ts(aPresContext, aRenderingContext, mStyleContext);
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing)) {
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing)
|
||||
|| ts.mJustifying) {
|
||||
PaintTextSlowly(aPresContext, aRenderingContext, sc, ts, 0, 0);
|
||||
}
|
||||
else {
|
||||
@ -1261,7 +1272,9 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
PRBool isWhitespace, wasTransformed;
|
||||
PRInt32 wordLen, contentLen;
|
||||
aTX.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed);
|
||||
NS_ASSERTION(isWhitespace, "mState and content are out of sync");
|
||||
// we trip this assertion in bug 31053, but I think it's unnecessary
|
||||
//NS_ASSERTION(isWhitespace, "mState and content are out of sync");
|
||||
|
||||
if (isWhitespace) {
|
||||
if (nsnull != indexp) {
|
||||
// Point mapping indicies at the same content index since
|
||||
@ -1301,7 +1314,6 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
}
|
||||
inWord = PR_FALSE;
|
||||
if (isWhitespace) {
|
||||
numSpaces++;
|
||||
if ('\t' == bp[0]) {
|
||||
PRInt32 spaces = 8 - (7 & column);
|
||||
PRUnichar* tp = bp;
|
||||
@ -1339,20 +1351,30 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
}
|
||||
}
|
||||
}
|
||||
numSpaces += wordLen;
|
||||
}
|
||||
else {
|
||||
PRInt32 i;
|
||||
if (nsnull != indexp) {
|
||||
// Point mapping indicies at each content index in the word
|
||||
PRInt32 i = contentLen;
|
||||
i = contentLen;
|
||||
while (--i >= 0) {
|
||||
*indexp++ = strInx++;
|
||||
}
|
||||
}
|
||||
// Nonbreaking spaces count as spaces, not letters
|
||||
PRUnichar* tp = bp;
|
||||
i = wordLen;
|
||||
while (--i >= 0) {
|
||||
if (*tp++ == ' ') {
|
||||
numSpaces++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grow the buffer before we run out of room. The only time this
|
||||
// happens is because of tab expansion.
|
||||
if (dstOffset + wordLen > aTextBuffer->mBufferLen) {
|
||||
if (aTextBuffer != nsnull && dstOffset + wordLen > aTextBuffer->mBufferLen) {
|
||||
nsresult rv = aTextBuffer->GrowBy(wordLen);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
@ -1362,8 +1384,10 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
column += wordLen;
|
||||
textLength += wordLen;
|
||||
n -= contentLen;
|
||||
nsCRT::memcpy(aTextBuffer->mBuffer + dstOffset, bp,
|
||||
sizeof(PRUnichar)*wordLen);
|
||||
if (aTextBuffer != nsnull) {
|
||||
nsCRT::memcpy(aTextBuffer->mBuffer + dstOffset, bp,
|
||||
sizeof(PRUnichar)*wordLen);
|
||||
}
|
||||
dstOffset += wordLen;
|
||||
}
|
||||
|
||||
@ -1372,19 +1396,24 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
NS_ASSERTION(indexp <= aIndexBuffer->mBuffer + aIndexBuffer->mBufferLen,
|
||||
"yikes - we just overwrote memory");
|
||||
}
|
||||
NS_ASSERTION(dstOffset <= aTextBuffer->mBufferLen,
|
||||
"yikes - we just overwrote memory");
|
||||
if (aTextBuffer) {
|
||||
NS_ASSERTION(dstOffset <= aTextBuffer->mBufferLen,
|
||||
"yikes - we just overwrote memory");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Remove trailing whitespace if it was trimmed after reflow
|
||||
if (TEXT_TRIMMED_WS & mState) {
|
||||
NS_ASSERTION(aTextBuffer != nsnull,
|
||||
"Nonexistent text buffer should only occur during reflow, i.e. before whitespace is trimmed");
|
||||
if (--dstOffset >= 0) {
|
||||
PRUnichar ch = aTextBuffer->mBuffer[dstOffset];
|
||||
if (XP_IS_SPACE(ch)) {
|
||||
textLength--;
|
||||
numSpaces--;
|
||||
}
|
||||
}
|
||||
numSpaces--;
|
||||
}
|
||||
|
||||
if (aIndexBuffer) {
|
||||
@ -1716,6 +1745,7 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
// no need to worry about justification, that's always on the slow path
|
||||
PrepareUnicodeText(tx, (displaySelection ? &indexBuffer : nsnull),
|
||||
&paintBuffer, &textLength);
|
||||
|
||||
@ -1833,7 +1863,7 @@ nsTextFrame::GetPositionSlowly(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
TextStyle ts(aPresContext, *aRendContext, mStyleContext);
|
||||
if (!ts.mSmallCaps && !ts.mWordSpacing && !ts.mLetterSpacing) {
|
||||
if (!ts.mSmallCaps && !ts.mWordSpacing && !ts.mLetterSpacing && !ts.mJustifying) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
nsIView * view;
|
||||
@ -1861,12 +1891,16 @@ nsTextFrame::GetPositionSlowly(nsIPresContext* aPresContext,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
PRInt32 numSpaces;
|
||||
|
||||
numSpaces = PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
if (textLength <= 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//IF STYLE SAYS TO SELCT TO END OF FRAME HERE...
|
||||
ComputeExtraJustificationSpacing(*aRendContext, ts, paintBuffer.mBuffer, textLength, numSpaces);
|
||||
|
||||
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
|
||||
nsCOMPtr<nsIPref> prefs;
|
||||
PRInt32 prefInt = 0;
|
||||
rv = nsServiceManager::GetService(kPrefCID,
|
||||
@ -1929,7 +1963,7 @@ nsTextFrame::RenderString(nsIRenderingContext& aRenderingContext,
|
||||
PRUnichar* bp = bp0;
|
||||
|
||||
PRBool spacing = (0 != aTextStyle.mLetterSpacing) ||
|
||||
(0 != aTextStyle.mWordSpacing);
|
||||
(0 != aTextStyle.mWordSpacing) || aTextStyle.mJustifying;
|
||||
nscoord spacingMem[TEXT_BUF_SIZE];
|
||||
PRIntn* sp0 = spacingMem;
|
||||
if (spacing && (aLength > TEXT_BUF_SIZE)) {
|
||||
@ -1977,12 +2011,12 @@ nsTextFrame::RenderString(nsIRenderingContext& aRenderingContext,
|
||||
else if (ch == ' ') {
|
||||
nextFont = aTextStyle.mNormalFont;
|
||||
nextY = aY;
|
||||
glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing;
|
||||
nscoord extra = aTextStyle.mExtraSpacePerSpace;
|
||||
if (--aTextStyle.mNumSpaces == 0) {
|
||||
extra += aTextStyle.mRemainingExtraSpace;
|
||||
glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing
|
||||
+ aTextStyle.mExtraSpacePerSpace;
|
||||
if ((PRUint32)--aTextStyle.mNumSpacesToRender <
|
||||
(PRUint32)aTextStyle.mNumSpacesReceivingExtraJot) {
|
||||
glyphWidth++;
|
||||
}
|
||||
glyphWidth += extra;
|
||||
}
|
||||
else {
|
||||
if (lastFont != aTextStyle.mNormalFont) {
|
||||
@ -2096,12 +2130,12 @@ nsTextFrame::GetWidthOrLength(nsIRenderingContext& aRenderingContext,
|
||||
glyphWidth = charWidth + aStyle.mLetterSpacing;
|
||||
}
|
||||
else if (ch == ' ') {
|
||||
glyphWidth = aStyle.mSpaceWidth + aStyle.mWordSpacing;
|
||||
nscoord extra = aStyle.mExtraSpacePerSpace;
|
||||
if (--aStyle.mNumSpaces == 0) {
|
||||
extra += aStyle.mRemainingExtraSpace;
|
||||
glyphWidth = aStyle.mSpaceWidth + aStyle.mWordSpacing
|
||||
+ aStyle.mExtraSpacePerSpace;
|
||||
if ((PRUint32)--aStyle.mNumSpacesToMeasure
|
||||
< (PRUint32)aStyle.mNumSpacesReceivingExtraJot) {
|
||||
glyphWidth++;
|
||||
}
|
||||
glyphWidth += extra;
|
||||
}
|
||||
else {
|
||||
if (lastFont != aStyle.mNormalFont) {
|
||||
@ -2147,6 +2181,45 @@ nsTextFrame::GetLengthSlowly(nsIRenderingContext& aRenderingContext,
|
||||
return GetWidthOrLength(aRenderingContext,aStyle,aBuffer,aLength,&aWidth,PR_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
nsTextFrame::ComputeExtraJustificationSpacing(nsIRenderingContext& aRenderingContext,
|
||||
TextStyle& aTextStyle,
|
||||
PRUnichar* aBuffer, PRInt32 aLength,
|
||||
PRInt32 aNumSpaces)
|
||||
{
|
||||
if (aTextStyle.mJustifying) {
|
||||
nscoord trueWidth;
|
||||
|
||||
// OK, so this is a bit ugly. The problem is that to get the right margin
|
||||
// nice and clean, we have to apply a little extra space to *some* of the
|
||||
// spaces. It has to be the same ones every time or things will go haywire.
|
||||
// This implies that the GetWidthOrLength and RenderString functions depend
|
||||
// on a little bit of secret state: which part of the prepared text they are
|
||||
// looking at. It turns out that they get called in a regular way: they look
|
||||
// at the text from the beginning to the end. So we just count which spaces
|
||||
// we're up to, for each context.
|
||||
// This is not a great solution, but a perfect solution requires much more
|
||||
// widespread changes, to explicitly annotate all the transformed text fragments
|
||||
// that are passed around with their position in the transformed text
|
||||
// for the entire frame.
|
||||
aTextStyle.mNumSpacesToMeasure = 0;
|
||||
aTextStyle.mExtraSpacePerSpace = 0;
|
||||
aTextStyle.mNumSpacesReceivingExtraJot = 0;
|
||||
|
||||
GetWidth(aRenderingContext, aTextStyle, aBuffer, aLength, &trueWidth);
|
||||
|
||||
aTextStyle.mNumSpacesToMeasure = aNumSpaces;
|
||||
aTextStyle.mNumSpacesToRender = aNumSpaces;
|
||||
|
||||
nscoord extraSpace = mRect.width - trueWidth;
|
||||
|
||||
if (extraSpace > 0 && aNumSpaces > 0) {
|
||||
aTextStyle.mExtraSpacePerSpace = extraSpace/aNumSpaces;
|
||||
aTextStyle.mNumSpacesReceivingExtraJot =
|
||||
extraSpace - aTextStyle.mExtraSpacePerSpace*aNumSpaces;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
|
||||
@ -2173,10 +2246,11 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
|
||||
nsCOMPtr<nsILineBreaker> lb;
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
aTextStyle.mNumSpaces = PrepareUnicodeText(tx,
|
||||
(displaySelection
|
||||
? &indexBuffer : nsnull),
|
||||
&paintBuffer, &textLength);
|
||||
PRInt32 numSpaces;
|
||||
|
||||
numSpaces = PrepareUnicodeText(tx, (displaySelection ? &indexBuffer : nsnull),
|
||||
&paintBuffer, &textLength);
|
||||
|
||||
|
||||
PRInt32* ip = indexBuffer.mBuffer;
|
||||
PRUnichar* text = paintBuffer.mBuffer;
|
||||
@ -2185,6 +2259,7 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
|
||||
GetFrameState(&frameState);
|
||||
isSelected = (frameState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
|
||||
if (0 != textLength) {
|
||||
ComputeExtraJustificationSpacing(aRenderingContext, aTextStyle, text, textLength, numSpaces);
|
||||
if (!displaySelection || !isSelected) {
|
||||
// When there is no selection showing, use the fastest and
|
||||
// simplest rendering approach
|
||||
@ -2550,8 +2625,7 @@ nsTextFrame::GetPosition(nsIPresContext* aCX,
|
||||
rv = shell->CreateRenderingContext(this, getter_AddRefs(acx));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
TextStyle ts(aCX, *acx, mStyleContext);
|
||||
if (ts.mSmallCaps || ts.mWordSpacing || ts.mLetterSpacing) {
|
||||
|
||||
if (ts.mSmallCaps || ts.mWordSpacing || ts.mLetterSpacing || ts.mJustifying) {
|
||||
nsresult result = GetPositionSlowly(aCX, acx, aPoint, aNewContent,
|
||||
aContentOffset);
|
||||
aContentOffsetEnd = aContentOffset;
|
||||
@ -2582,6 +2656,7 @@ nsTextFrame::GetPosition(nsIPresContext* aCX,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
// no need to worry about justification, that's always on the slow path
|
||||
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
|
||||
if (textLength <=0) {
|
||||
@ -2593,7 +2668,7 @@ nsTextFrame::GetPosition(nsIPresContext* aCX,
|
||||
nsIView * view;
|
||||
GetOffsetFromView(aCX, origin, &view);
|
||||
|
||||
//IF SYLE SAYS TO SELCT TO END OF FRAME HERE...
|
||||
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
|
||||
nsCOMPtr<nsIPref> prefs;
|
||||
PRInt32 prefInt = 0;
|
||||
rv = nsServiceManager::GetService(kPrefCID,
|
||||
@ -2880,7 +2955,12 @@ nsTextFrame::GetPointFromOffset(nsIPresContext* aPresContext,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
PRInt32 numSpaces;
|
||||
|
||||
numSpaces = PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
|
||||
ComputeExtraJustificationSpacing(*inRendContext, ts, paintBuffer.mBuffer, textLength, numSpaces);
|
||||
|
||||
|
||||
PRInt32* ip = indexBuffer.mBuffer;
|
||||
if (inOffset > mContentLength){
|
||||
@ -2889,7 +2969,7 @@ nsTextFrame::GetPointFromOffset(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
nscoord width = mRect.width;
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing))
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing) || ts.mJustifying)
|
||||
{
|
||||
GetWidth(*inRendContext, ts,
|
||||
paintBuffer.mBuffer, ip[inOffset]-mContentOffset,
|
||||
@ -2907,7 +2987,8 @@ nsTextFrame::GetPointFromOffset(nsIPresContext* aPresContext,
|
||||
// to the total width, so the caret appears
|
||||
// in the proper place!
|
||||
//
|
||||
width += ts.mSpaceWidth;
|
||||
// NOTE: the trailing whitespace includes the word spacing!!
|
||||
width += ts.mSpaceWidth + ts.mWordSpacing;
|
||||
}
|
||||
|
||||
outPoint->x = width;
|
||||
@ -3502,6 +3583,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
#ifdef _WIN32
|
||||
PRBool measureTextRuns = !aTextData.mComputeMaxWordWidth && !aTs.mPreformatted &&
|
||||
!aTs.mSmallCaps && !aTs.mWordSpacing && !aTs.mLetterSpacing;
|
||||
// Don't measure text runs with letter spacing active, it doesn't work
|
||||
#else
|
||||
PRBool measureTextRuns = PR_FALSE;
|
||||
#endif
|
||||
@ -3579,10 +3661,17 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
mState |= TEXT_SKIP_LEADING_WS;
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: Even if the textRun absorbs the whitespace below, we still
|
||||
// want to remember that we're breakable.
|
||||
aTextData.mIsBreakable = PR_TRUE;
|
||||
aTextData.mFirstLetterOK = PR_FALSE;
|
||||
|
||||
if ('\t' == firstChar) {
|
||||
// Expand tabs to the proper width
|
||||
wordLen = 8 - (7 & column);
|
||||
width = aTs.mSpaceWidth * wordLen;
|
||||
// Apply word spacing to every space derived from a tab
|
||||
width = (aTs.mSpaceWidth + aTs.mWordSpacing)*wordLen;
|
||||
|
||||
// Because we have to expand the tab when rendering consider that
|
||||
// a transformation of the text
|
||||
@ -3594,10 +3683,9 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
width = (wordLen * aTs.mSpaceWidth) + aTs.mWordSpacing;// XXX simplistic
|
||||
// Apply word spacing to every space, if there's more than one
|
||||
width = wordLen*(aTs.mWordSpacing + aTs.mSpaceWidth);// XXX simplistic
|
||||
}
|
||||
aTextData.mIsBreakable = PR_TRUE;
|
||||
aTextData.mFirstLetterOK = PR_FALSE;
|
||||
|
||||
if (aTextData.mMeasureText) {
|
||||
// See if there is room for the text
|
||||
@ -3612,7 +3700,6 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
endsInWhitespace = PR_TRUE;
|
||||
prevOffset = aTextData.mOffset;
|
||||
aTextData.mOffset += contentLen;
|
||||
|
||||
} else {
|
||||
// See if the first thing in the section of text is a
|
||||
// non-breaking space (html nbsp entity). If it is then make
|
||||
@ -3704,6 +3791,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
MeasureTextRun:
|
||||
#ifdef _WIN32
|
||||
PRInt32 numCharsFit;
|
||||
// These calls can return numCharsFit not positioned at a break in the textRun. Beware.
|
||||
if (aTx.TransformedTextIsAscii()) {
|
||||
aReflowState.rendContext->GetWidth((char*)aTx.GetWordBuffer(), textRun.mTotalNumChars,
|
||||
maxWidth - aTextData.mX,
|
||||
@ -3722,22 +3810,43 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
// Find the index of the last segment that fit
|
||||
PRInt32 lastSegment = textRun.mNumSegments - 1;
|
||||
if (numCharsFit != textRun.mTotalNumChars) {
|
||||
PRInt32 lastSegment;
|
||||
if (numCharsFit == textRun.mTotalNumChars) { // fast path, normal case
|
||||
lastSegment = textRun.mNumSegments - 1;
|
||||
} else {
|
||||
for (lastSegment = 0; textRun.mBreaks[lastSegment] < numCharsFit; lastSegment++) ;
|
||||
NS_ASSERTION(lastSegment < textRun.mNumSegments, "failed to find segment");
|
||||
// now we have textRun.mBreaks[lastSegment] >= numCharsFit
|
||||
/* O'Callahan XXX: This snippet together with the snippet below prevents mail from loading
|
||||
Justification seems to work just fine without these changes.
|
||||
We get into trouble in a case where lastSegment gets set to -1
|
||||
|
||||
if (textRun.mBreaks[lastSegment] > numCharsFit) {
|
||||
// NOTE: this segment did not actually fit!
|
||||
lastSegment--;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* O'Callahan XXX: This snippet together with the snippet above prevents mail from loading
|
||||
|
||||
if (lastSegment < 0) {
|
||||
// no segments fit
|
||||
break;
|
||||
} else */
|
||||
if (lastSegment == 0) {
|
||||
// Only one segment fit
|
||||
prevColumn = column;
|
||||
prevOffset = aTextData.mOffset;
|
||||
|
||||
} else {
|
||||
// The previous state is for the next to last word
|
||||
prevColumn = textRun.mBreaks[lastSegment - 1];
|
||||
prevOffset = textRun.mSegments[lastSegment - 1].ContentLen();
|
||||
// NOTE: The textRun data are relative to the last updated column and offset!
|
||||
prevColumn = column + textRun.mBreaks[lastSegment - 1];
|
||||
prevOffset = aTextData.mOffset + textRun.mSegments[lastSegment - 1].ContentLen();
|
||||
}
|
||||
|
||||
aTextData.mX += width;
|
||||
column += numCharsFit;
|
||||
aTextData.mOffset += textRun.mSegments[lastSegment].ContentLen();
|
||||
@ -3775,7 +3884,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
aTextData.mX = mRect.width;
|
||||
if (mState & TEXT_TRIMMED_WS) {
|
||||
// Add back in the width of a space since it was trimmed away last time
|
||||
aTextData.mX += aTs.mSpaceWidth;
|
||||
// NOTE: Trailing whitespace includes word spacing!
|
||||
aTextData.mX += aTs.mSpaceWidth + aTs.mWordSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4056,19 +4166,22 @@ nsTextFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// current frame width -or-
|
||||
// we're not wrapping text and we're at the same column as before (this is
|
||||
// an issue for preformatted tabbed text only)
|
||||
// - AND we aren't justified (in which case the frame width has already been tweaked and can't be used)
|
||||
if ((eReflowReason_Resize == aReflowState.reason) &&
|
||||
(0 == (mState & NS_FRAME_IS_DIRTY))) {
|
||||
|
||||
nscoord realWidth = mRect.width;
|
||||
if (mState & TEXT_TRIMMED_WS) {
|
||||
realWidth += ts.mSpaceWidth;
|
||||
// NOTE: Trailing whitespace includes word spacing!
|
||||
realWidth += ts.mSpaceWidth + ts.mWordSpacing;
|
||||
}
|
||||
if (!mNextInFlow &&
|
||||
(mState & TEXT_OPTIMIZE_RESIZE) &&
|
||||
!aMetrics.maxElementSize &&
|
||||
(lastTimeWeSkippedLeadingWS == skipWhitespace) &&
|
||||
((wrapping && (maxWidth >= realWidth)) ||
|
||||
(!wrapping && (prevColumn == column)))) {
|
||||
(!wrapping && (prevColumn == column))) &&
|
||||
!ts.mJustifying) {
|
||||
// We can skip measuring of text and use the value from our
|
||||
// previous reflow
|
||||
measureText = PR_FALSE;
|
||||
@ -4120,6 +4233,23 @@ nsTextFrame::Reflow(nsIPresContext* aPresContext,
|
||||
mContentOffset = startingOffset;
|
||||
mContentLength = textData.mOffset - startingOffset;
|
||||
|
||||
// Compute space and letter counts for justification, if required
|
||||
if (ts.mJustifying) {
|
||||
PRInt32 numSpaces;
|
||||
PRInt32 textLength;
|
||||
|
||||
// This will include a space for trailing whitespace, if any is present.
|
||||
// This is corrected for in nsLineLayout::TrimWhiteSpaceIn.
|
||||
|
||||
// This work could be done in MeasureText, but it's complex to do accurately
|
||||
// there because of the need to repair counts when wrapped words are backed out.
|
||||
// So I do it via PrepareUnicodeText ... a little slower perhaps, but a lot saner,
|
||||
// and it localizes the counting logic to one place.
|
||||
numSpaces = PrepareUnicodeText(tx, nsnull, nsnull, &textLength);
|
||||
lineLayout.SetTextJustificationWeights(numSpaces, textLength - numSpaces);
|
||||
}
|
||||
|
||||
|
||||
#ifdef MOZ_MATHML
|
||||
// Simple minded code to also return the bounding metrics if the caller wants it...
|
||||
// More consolidation is needed -- a better approach is to follow what is done by
|
||||
@ -4226,6 +4356,11 @@ nsTextFrame::TrimTrailingWhiteSpace(nsIPresContext* aPresContext,
|
||||
mStyleContext->GetStyleData(eStyleStruct_Font);
|
||||
aRC.SetFont(fontStyle->mFont);
|
||||
aRC.GetWidth(' ', dw);
|
||||
// NOTE: Trailing whitespace includes word spacing!
|
||||
PRIntn unit = textStyle->mWordSpacing.GetUnit();
|
||||
if (eStyleUnit_Coord == unit) {
|
||||
dw += textStyle->mWordSpacing.GetCoordValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4406,6 +4541,8 @@ nsTextFrame::ComputeWordFragmentWidth(nsIPresContext* aPresContext,
|
||||
}
|
||||
else {
|
||||
rc.GetWidth(bp, wordLen, width);
|
||||
// NOTE: Don't forget to add letter spacing for the word fragment!
|
||||
width += wordLen*ts.mLetterSpacing;
|
||||
}
|
||||
rc.SetFont(oldfm);
|
||||
|
||||
|
@ -81,6 +81,10 @@ nsBlockBandData::GetAvailableSpace(nscoord aY, nsRect& aResult)
|
||||
// between any left and right floaters.
|
||||
ComputeAvailSpaceRect();
|
||||
aResult = mAvailSpace;
|
||||
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
|
||||
printf("nsBBD %p GetAvailableSpace(%d) returing (%d, %d, %d, %d)\n",
|
||||
this, aY, aResult.x, aResult.y, aResult.width, aResult.height);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -134,7 +138,7 @@ void
|
||||
nsBlockBandData::ComputeAvailSpaceRect()
|
||||
{
|
||||
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
|
||||
printf("nsBlockBandData::ComputeAvailSpaceRect %p \n", this);
|
||||
printf("nsBlockBandData::ComputeAvailSpaceRect %p with count %d\n", this, mCount);
|
||||
#endif
|
||||
if (0 == mCount) {
|
||||
mAvailSpace.x = 0;
|
||||
@ -248,6 +252,11 @@ nsBlockBandData::ComputeAvailSpaceRect()
|
||||
if (NS_UNCONSTRAINEDSIZE == mSpace.width) {
|
||||
mAvailSpace.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT
|
||||
printf(" ComputeAvailSpaceRect settting state mAvailSpace (%d,%d,%d,%d)\n",
|
||||
mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -471,3 +480,15 @@ nsBlockBandData::GetMaxElementSize(nsIPresContext* aPresContext,
|
||||
*aWidthResult = maxWidth;
|
||||
*aHeightResult = maxHeight;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void nsBlockBandData::List()
|
||||
{
|
||||
printf("nsBlockBandData %p sm=%p, sm coord = (%d,%d), mSpace = (%d,%d)\n",
|
||||
this, mSpaceManager, mSpaceManagerX, mSpaceManagerY,
|
||||
mSpace.width, mSpace.height);
|
||||
printf(" availSpace=(%d, %d, %d, %d), floaters l=%d r=%d\n",
|
||||
mAvailSpace.x, mAvailSpace.y, mAvailSpace.width, mAvailSpace.height,
|
||||
mLeftFloaters, mRightFloaters);
|
||||
}
|
||||
#endif
|
||||
|
@ -89,6 +89,10 @@ public:
|
||||
nsIFrame* aFrame,
|
||||
nsSize* aResult);
|
||||
|
||||
#ifdef DEBUG
|
||||
void List();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
/** utility method to calculate the band data at aY.
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
@ -61,6 +63,8 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
//#define NOISY_BLOCK_INVALIDATE // DO NOT CHECK THIS IN TURNED ON!
|
||||
|
||||
static PRBool gLamePaintMetrics;
|
||||
static PRBool gLameReflowMetrics;
|
||||
static PRBool gNoisy;
|
||||
@ -451,12 +455,6 @@ public:
|
||||
|
||||
nscoord mBottomEdge;
|
||||
|
||||
PRPackedBool mUnconstrainedWidth;
|
||||
PRPackedBool mUnconstrainedHeight;
|
||||
PRPackedBool mShrinkWrapWidth;
|
||||
PRPackedBool mNeedResizeReflow;
|
||||
PRPackedBool mIsInlineIncrReflow;
|
||||
|
||||
// The content area to reflow child frames within. The x/y
|
||||
// coordinates are known to be mBorderPadding.left and
|
||||
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
||||
@ -464,15 +462,6 @@ public:
|
||||
// unconstrained area.
|
||||
nsSize mContentArea;
|
||||
|
||||
// Our wrapping behavior
|
||||
PRPackedBool mNoWrap;
|
||||
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRPackedBool mIsTopMarginRoot, mIsBottomMarginRoot;
|
||||
|
||||
// See ShouldApplyTopMargin
|
||||
PRPackedBool mApplyTopMargin;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
@ -541,15 +530,48 @@ public:
|
||||
// being N^2.
|
||||
nsFloaterCacheFreeList mBelowCurrentLineFloaters;
|
||||
|
||||
PRPackedBool mComputeMaxElementSize;
|
||||
PRPackedBool mComputeMaximumWidth;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
nscoord mMaximumWidth;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
|
||||
// block reflow state flags
|
||||
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
||||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
@ -574,29 +596,25 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
mNeedResizeReflow(PR_FALSE),
|
||||
mIsInlineIncrReflow(PR_FALSE),
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
mLineNumber(0),
|
||||
mFlags(0)
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (mIsTopMarginRoot) {
|
||||
mApplyTopMargin = PR_TRUE;
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
}
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
@ -617,21 +635,19 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Compute content area width (the content area is inside the border
|
||||
// and padding)
|
||||
mUnconstrainedWidth = PR_FALSE;
|
||||
mShrinkWrapWidth = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
||||
mContentArea.width = aReflowState.mComputedWidth;
|
||||
}
|
||||
else {
|
||||
if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
|
||||
mContentArea.width = NS_UNCONSTRAINEDSIZE;
|
||||
mUnconstrainedWidth = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
}
|
||||
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
||||
// Choose a width based on the content (shrink wrap width) up
|
||||
// to the maximum width
|
||||
mContentArea.width = aReflowState.mComputedMaxWidth;
|
||||
mShrinkWrapWidth = PR_TRUE;
|
||||
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
|
||||
}
|
||||
else {
|
||||
nscoord lr = borderPadding.left + borderPadding.right;
|
||||
@ -646,7 +662,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
// specified style height then we may end up limiting our height if
|
||||
// the availableHeight is constrained (this situation occurs when we
|
||||
// are paginated).
|
||||
mUnconstrainedHeight = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
||||
// We are in a paginated situation. The bottom edge is just inside
|
||||
// the bottom border and padding. The content area height doesn't
|
||||
@ -657,7 +672,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
else {
|
||||
// When we are not in a paginated situation then we always use
|
||||
// an constrained height.
|
||||
mUnconstrainedHeight = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
|
||||
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
|
||||
@ -674,16 +689,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
switch (styleText->mWhiteSpace) {
|
||||
case NS_STYLE_WHITESPACE_PRE:
|
||||
case NS_STYLE_WHITESPACE_NOWRAP:
|
||||
mNoWrap = PR_TRUE;
|
||||
SetFlag(BRS_NOWRAP, PR_TRUE);
|
||||
break;
|
||||
default:
|
||||
mNoWrap = PR_FALSE;
|
||||
SetFlag(BRS_NOWRAP, PR_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
mComputeMaximumWidth = NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH);
|
||||
SetFlag(BRS_COMPUTEMAXWIDTH,
|
||||
(NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
|
||||
mMaximumWidth = 0;
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
@ -729,8 +745,12 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
|
||||
mBand.List();
|
||||
#endif
|
||||
aResult.y = mY;
|
||||
aResult.height = mUnconstrainedHeight
|
||||
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mBottomEdge - mY;
|
||||
|
||||
@ -749,7 +769,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// The child block will flow around the floater. Therefore
|
||||
// give it all of the available space.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
break;
|
||||
@ -776,7 +796,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
// determine width
|
||||
if (mUnconstrainedWidth) {
|
||||
if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aResult.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -810,7 +830,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// doesn't matter therefore give the block element all of the
|
||||
// available space since it will flow around the floater itself.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
}
|
||||
@ -957,12 +977,12 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
|
||||
#endif
|
||||
mKidXMost = xmost;
|
||||
}
|
||||
if (mComputeMaxElementSize) {
|
||||
if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
||||
}
|
||||
|
||||
// If computing the maximum width, then update mMaximumWidth
|
||||
if (mComputeMaximumWidth) {
|
||||
if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
}
|
||||
|
||||
@ -1454,6 +1474,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
||||
NS_BLOCK_MARGIN_ROOT & mState);
|
||||
PRInt32 sizeofBRS = sizeof nsBlockReflowState;
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
RenumberLists(aPresContext);
|
||||
@ -1462,7 +1483,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
PRBool isStyleChange = PR_FALSE;
|
||||
state.mIsInlineIncrReflow = PR_FALSE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_FALSE);
|
||||
nsIFrame* target;
|
||||
switch (aReflowState.reason) {
|
||||
case eReflowReason_Initial:
|
||||
@ -1535,7 +1556,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// reflow the line containing the target of the incr. reflow
|
||||
// first mark the line dirty and set up the state object
|
||||
rv = PrepareChildIncrementalReflow(state);
|
||||
state.mIsInlineIncrReflow = PR_TRUE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
state.mPrevLine = prevLine;
|
||||
state.mCurrentLine = line;
|
||||
state.mNextRCFrame = state.mNextRCFrame;
|
||||
@ -1681,6 +1702,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
if (isStyleChange) {
|
||||
// Lots of things could have changed so damage our entire
|
||||
// bounds
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 1 (%d, %d, %d, %d)\n",
|
||||
this, 0, 0, mRect.width, mRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height));
|
||||
|
||||
} else {
|
||||
@ -1707,6 +1732,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = 0;
|
||||
damageRect.height = mRect.height;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 2 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
|
||||
@ -1730,6 +1759,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = mRect.height - border.bottom;
|
||||
damageRect.height = border.bottom;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 3 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -1868,7 +1901,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
||||
aState.mY, aState.mIsBottomMarginRoot ? "yes" : "no",
|
||||
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
||||
aState.mPrevBottomMargin,
|
||||
borderPadding.top, borderPadding.bottom);
|
||||
#endif
|
||||
@ -1946,7 +1979,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// contents or we fluff out to the maximum block width. Note:
|
||||
// We always shrink wrap when given an unconstrained width.
|
||||
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
|
||||
!aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
|
||||
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && !aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
||||
!compact) {
|
||||
// Set our width to the max width if we aren't already that
|
||||
// wide. Note that the max-width has nothing to do with our
|
||||
@ -1956,9 +1989,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// See if we should compute our max element size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Adjust the computedWidth
|
||||
if (aState.mNoWrap) {
|
||||
if (aState.GetFlag(BRS_NOWRAP)) {
|
||||
// When no-wrap is true the max-element-size.width is the
|
||||
// width of the widest line plus the right border. Note that
|
||||
// aState.mKidXMost already has the left border factored in
|
||||
@ -1996,7 +2029,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// need to do horizontal alignment of the inline lines and make sure
|
||||
// blocks are correctly sized and positioned. Any lines that need
|
||||
// final adjustment will have been marked as dirty
|
||||
if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
|
||||
// If the parent reflow state is also shrink wrap width, then
|
||||
// we don't need to do this, because it will reflow us after it
|
||||
// calculates the final width
|
||||
@ -2025,7 +2058,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
}
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
||||
if (aReflowState.parentReflowState) {
|
||||
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
||||
@ -2047,7 +2080,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// Don't carry out a bottom margin when our height is fixed
|
||||
// unless the bottom of the last line adjoins the bottom of our
|
||||
// content area.
|
||||
if (!aState.mIsBottomMarginRoot) {
|
||||
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
|
||||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
@ -2057,7 +2090,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
@ -2082,7 +2115,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
aMetrics.height = autoHeight;
|
||||
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxHeight = aState.mMaxElementSize.height +
|
||||
borderPadding.top + borderPadding.bottom;
|
||||
}
|
||||
@ -2090,7 +2123,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
aMetrics.descent = 0;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Store away the final value
|
||||
aMetrics.maxElementSize->width = maxWidth;
|
||||
aMetrics.maxElementSize->height = maxHeight;
|
||||
@ -2098,14 +2131,14 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
||||
}
|
||||
if (aState.mComputeMaxElementSize &&
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
||||
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
||||
@ -2115,7 +2148,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
#endif
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
printf("PASS1 ");
|
||||
@ -2130,7 +2163,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// If we're requested to update our maximum width, then compute it
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We need to add in for the right border/padding
|
||||
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
||||
}
|
||||
@ -2337,8 +2370,13 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
// See if we can try and avoid marking all the lines as dirty
|
||||
PRBool tryAndSkipLines = PR_FALSE;
|
||||
|
||||
// See if this is this a constrained resize reflow
|
||||
if ((aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
// we need to calculate if any part of then block itself
|
||||
// is impacted by a floater (bug 19579)
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
// See if this is this a constrained resize reflow that is not impacted by floaters
|
||||
if ((PR_FALSE==aState.IsImpactedByFloater()) &&
|
||||
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
||||
|
||||
// If the text is left-aligned, then we try and avoid reflowing the lines
|
||||
@ -2389,7 +2427,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool notWrapping = aState.mNoWrap;
|
||||
PRBool notWrapping = aState.GetFlag(BRS_NOWRAP);
|
||||
while (nsnull != line) {
|
||||
|
||||
if (line->IsBlock()) {
|
||||
@ -2402,8 +2440,6 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
||||
line, line->IsImpactedByFloater() ? "" : "not ");
|
||||
#endif
|
||||
|
||||
|
||||
if (notWrapping) {
|
||||
// When no-wrap is set then the only line-breaking that
|
||||
// occurs for inline lines is triggered by BR elements or by
|
||||
@ -2430,7 +2466,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
||||
line, line->mNext,
|
||||
line->IsBlock() ? "block" : "inline",
|
||||
aState.mNoWrap ? "no-wrap" : "wrapping",
|
||||
aState.GetFlag(BRS_NOWRAP) ? "no-wrap" : "wrapping",
|
||||
line->HasBreak() ? "has-break " : "",
|
||||
line->HasFloaters() ? "has-floaters " : "",
|
||||
line->IsImpactedByFloater() ? "impacted " : "",
|
||||
@ -2628,7 +2664,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.mIsInlineIncrReflow ? "true" : "false");
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
@ -2651,7 +2687,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// Reflow the lines that are already ours
|
||||
aState.mPrevLine = nsnull;
|
||||
nsLineBox* line = mLines;
|
||||
if (aState.mIsInlineIncrReflow && aState.mNextRCFrame)
|
||||
if (aState.GetFlag(BRS_ISINLINEINCRREFLOW) && aState.mNextRCFrame)
|
||||
{
|
||||
const nsLineBox* incrTargetLine = aState.mCurrentLine;
|
||||
aState.mCurrentLine = line;
|
||||
@ -2662,6 +2698,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 4 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
aState.mPrevLine = line;
|
||||
@ -2689,7 +2729,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// If we're supposed to update our maximum width, then we'll also need to
|
||||
// reflow this line if it's line wrapped and any of the continuing lines
|
||||
// are dirty
|
||||
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
|
||||
if (line->IsDirty() || (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line))) {
|
||||
// Compute the dirty lines "before" YMost, after factoring in
|
||||
// the running deltaY value - the running value is implicit in
|
||||
// aState.mY.
|
||||
@ -2729,6 +2769,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 5 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -2902,6 +2946,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// XXX We need to improve on this...
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
|
||||
} else {
|
||||
@ -2918,6 +2966,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.x;
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
||||
lineCombinedArea.height);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
if (oldCombinedArea.height != lineCombinedArea.height) {
|
||||
@ -2933,6 +2985,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
||||
lineCombinedArea.YMost()) -
|
||||
dirtyRect.y;
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -2951,21 +3007,21 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// we'll either need to recover the floater state that applies to the
|
||||
// unconstrained reflow or keep it around in a separate space manager...
|
||||
PRBool isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
|
||||
if (aState.mComputeMaximumWidth && isBeginningLine) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||
nscoord oldY = aState.mY;
|
||||
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
|
||||
PRBool oldUnconstrainedWidth = aState.mUnconstrainedWidth;
|
||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||
|
||||
// First reflow the line with an unconstrained width. When doing this
|
||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
||||
// associated floater we don't end up resetting the line's right edge and
|
||||
// have it think the width is unconstrained...
|
||||
aState.mUnconstrainedWidth = PR_TRUE;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
|
||||
aState.mY = oldY;
|
||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||
aState.mUnconstrainedWidth = oldUnconstrainedWidth;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||
|
||||
// Update the line's maximum width
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
@ -2980,14 +3036,14 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// Note: we need to reset both member variables, because the inline
|
||||
// code examines mComputeMaxElementSize and if there is a placeholder
|
||||
// on this line the code to reflow the floater looks at both...
|
||||
nscoord oldComputeMaxElementSize = aState.mComputeMaxElementSize;
|
||||
nscoord oldComputeMaximumWidth = aState.mComputeMaximumWidth;
|
||||
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
||||
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
||||
|
||||
aState.mComputeMaxElementSize = PR_FALSE;
|
||||
aState.mComputeMaximumWidth = PR_FALSE;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
aState.mComputeMaxElementSize = oldComputeMaxElementSize;
|
||||
aState.mComputeMaximumWidth = oldComputeMaximumWidth;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
||||
|
||||
} else {
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
@ -3001,6 +3057,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 9 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -3368,7 +3428,7 @@ PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -3377,7 +3437,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -3387,13 +3447,13 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (line->HasFloaters()) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
@ -3486,8 +3546,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
@ -3611,14 +3671,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, combinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line as block so once we known the final shrink wrap width
|
||||
// we can reflow the block to the correct size
|
||||
// XXX We don't always need to do this...
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
if (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Add the right margin to the line's bounnds. That way it will be taken into
|
||||
// account when we compute our shrink wrap size
|
||||
nscoord marginRight = brc.GetMargin().right;
|
||||
@ -3709,7 +3769,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(0, 0);
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxElementSize = brc.GetMaxElementSize();
|
||||
if (aState.IsImpactedByFloater() &&
|
||||
(NS_FRAME_SPLITTABLE_NON_RECTANGULAR != splitType)) {
|
||||
@ -3721,7 +3781,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
}
|
||||
// If we asked the block to update its maximum width, then record the
|
||||
// updated value in the line, and update the current maximum width
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
||||
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
|
||||
@ -3849,7 +3909,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -3872,7 +3932,7 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineLayout lineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
@ -3910,7 +3970,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -4359,7 +4419,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsSize maxElementSize;
|
||||
aLineLayout.VerticalAlignFrames(aLine, maxElementSize);
|
||||
// See if we're shrink wrapping the width
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// When determining the line's width we also need to include any
|
||||
// right floaters that impact us. This represents the shrink wrap
|
||||
// width of the line
|
||||
@ -4388,25 +4448,20 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// Only block frames horizontally align their children because
|
||||
// inline frames "shrink-wrap" around their children (therefore
|
||||
// there is no extra horizontal space).
|
||||
#if XXX_fix_me
|
||||
PRBool allowJustify = PR_TRUE;
|
||||
if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) {
|
||||
allowJustify = ShouldJustifyLine(aState, aLine);
|
||||
}
|
||||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PRBool successful;
|
||||
nsRect combinedArea;
|
||||
successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.mShrinkWrapWidth);
|
||||
const nsStyleText* styleText = (const nsStyleText*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Text);
|
||||
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
||||
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
||||
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
||||
if (!successful) {
|
||||
// Mark the line dirty and then later once we've determined the width
|
||||
// we can do the horizontal alignment
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
|
||||
nsRect combinedArea;
|
||||
aLineLayout.RelativePositionFrames(combinedArea);
|
||||
aLine->SetCombinedArea(combinedArea);
|
||||
if (addedBullet) {
|
||||
@ -4454,7 +4509,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
aState.mY = newY;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
@ -4478,7 +4533,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// we don't want updated...
|
||||
if (aUpdateMaximumWidth) {
|
||||
// However, we do need to update the max-element-size if requested
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(maxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4519,7 +4574,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mHaveRightFloaters &&
|
||||
(aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
|
||||
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// We are reflowing in an unconstrained situation or shrink wrapping and
|
||||
// have some right floaters. They were placed at the infinite right edge
|
||||
// which will cause the combined area to be unusable.
|
||||
@ -4540,11 +4595,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
|
||||
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line dirty so we come back and re-place the floater once
|
||||
// the shrink wrap width is determined
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
}
|
||||
aLine->SetCombinedArea(lineCombinedArea);
|
||||
@ -4629,7 +4684,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
// Update max-element-size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(aMaxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4639,7 +4694,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
// If this is an unconstrained reflow, then cache the line width in the
|
||||
// line. We'll need this during incremental reflow if we're asked to
|
||||
// calculate the maximum width
|
||||
if (aState.mUnconstrainedWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
}
|
||||
|
||||
@ -4653,7 +4708,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
#endif
|
||||
// If we're shrink wrapping our width and the line was wrapped,
|
||||
// then make sure we take up all of the available width
|
||||
if (aState.mShrinkWrapWidth && aLine->IsLineWrapped()) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
|
||||
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
|
||||
|
||||
}
|
||||
@ -5187,6 +5242,10 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||
// cases...
|
||||
nsRect lineCombinedArea;
|
||||
line->GetCombinedArea(&lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
||||
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, lineCombinedArea);
|
||||
line->Destroy(presShell);
|
||||
line = next;
|
||||
@ -5282,8 +5341,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
|
||||
// Setup block reflow state to reflow the floater
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// Reflow the floater
|
||||
@ -5324,7 +5383,7 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
floater->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
// If we computed it, then stash away the max-element-size for later
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.StoreMaxElementSize(floater, brc.GetMaxElementSize());
|
||||
}
|
||||
|
||||
@ -5389,7 +5448,7 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
@ -5615,7 +5674,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
}
|
||||
else {
|
||||
isLeftFloater = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
else {
|
||||
okToAddRectRegion = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.x;
|
||||
}
|
||||
}
|
||||
*aIsLeftFloater = isLeftFloater;
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
@ -5682,7 +5746,8 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
nsRect combinedArea = aFloaterCache->mCombinedArea;
|
||||
combinedArea.x += x;
|
||||
combinedArea.y += y;
|
||||
if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
|
||||
if (!isLeftFloater &&
|
||||
(GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// When we are placing a right floater in an unconstrained situation or
|
||||
// when shrink wrapping, we don't apply it to the floater combined area
|
||||
// immediately. Otherwise we end up with an infinitely wide combined
|
||||
|
@ -197,10 +197,12 @@ nsBlockReflowContext::AlignBlockHorizontally(nscoord aWidth,
|
||||
// compatability cases.
|
||||
switch (styleText->mTextAlign) {
|
||||
case NS_STYLE_TEXT_ALIGN_MOZ_RIGHT:
|
||||
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
||||
aAlign.mXOffset += remainingSpace;
|
||||
doCSS = PR_FALSE;
|
||||
break;
|
||||
case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
|
||||
case NS_STYLE_TEXT_ALIGN_CENTER:
|
||||
aAlign.mXOffset += remainingSpace / 2;
|
||||
doCSS = PR_FALSE;
|
||||
break;
|
||||
@ -359,7 +361,11 @@ nsBlockReflowContext::ReflowBlock(nsIFrame* aFrame,
|
||||
reflowState.mComputedBorderPadding.right;
|
||||
}
|
||||
|
||||
x = aSpace.XMost() - mMargin.right - frameWidth;
|
||||
// if this is an unconstrained width reflow, then just place the floater at the left margin
|
||||
if (NS_UNCONSTRAINEDSIZE == aSpace.width)
|
||||
x = aSpace.x;
|
||||
else
|
||||
x = aSpace.XMost() - mMargin.right - frameWidth;
|
||||
|
||||
} else {
|
||||
x = aSpace.x + mMargin.left;
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
@ -61,6 +63,8 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
//#define NOISY_BLOCK_INVALIDATE // DO NOT CHECK THIS IN TURNED ON!
|
||||
|
||||
static PRBool gLamePaintMetrics;
|
||||
static PRBool gLameReflowMetrics;
|
||||
static PRBool gNoisy;
|
||||
@ -451,12 +455,6 @@ public:
|
||||
|
||||
nscoord mBottomEdge;
|
||||
|
||||
PRPackedBool mUnconstrainedWidth;
|
||||
PRPackedBool mUnconstrainedHeight;
|
||||
PRPackedBool mShrinkWrapWidth;
|
||||
PRPackedBool mNeedResizeReflow;
|
||||
PRPackedBool mIsInlineIncrReflow;
|
||||
|
||||
// The content area to reflow child frames within. The x/y
|
||||
// coordinates are known to be mBorderPadding.left and
|
||||
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
||||
@ -464,15 +462,6 @@ public:
|
||||
// unconstrained area.
|
||||
nsSize mContentArea;
|
||||
|
||||
// Our wrapping behavior
|
||||
PRPackedBool mNoWrap;
|
||||
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRPackedBool mIsTopMarginRoot, mIsBottomMarginRoot;
|
||||
|
||||
// See ShouldApplyTopMargin
|
||||
PRPackedBool mApplyTopMargin;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
@ -541,15 +530,48 @@ public:
|
||||
// being N^2.
|
||||
nsFloaterCacheFreeList mBelowCurrentLineFloaters;
|
||||
|
||||
PRPackedBool mComputeMaxElementSize;
|
||||
PRPackedBool mComputeMaximumWidth;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
nscoord mMaximumWidth;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
|
||||
// block reflow state flags
|
||||
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
||||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
@ -574,29 +596,25 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
mNeedResizeReflow(PR_FALSE),
|
||||
mIsInlineIncrReflow(PR_FALSE),
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
mLineNumber(0),
|
||||
mFlags(0)
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (mIsTopMarginRoot) {
|
||||
mApplyTopMargin = PR_TRUE;
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
}
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
@ -617,21 +635,19 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Compute content area width (the content area is inside the border
|
||||
// and padding)
|
||||
mUnconstrainedWidth = PR_FALSE;
|
||||
mShrinkWrapWidth = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
||||
mContentArea.width = aReflowState.mComputedWidth;
|
||||
}
|
||||
else {
|
||||
if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
|
||||
mContentArea.width = NS_UNCONSTRAINEDSIZE;
|
||||
mUnconstrainedWidth = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
}
|
||||
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
||||
// Choose a width based on the content (shrink wrap width) up
|
||||
// to the maximum width
|
||||
mContentArea.width = aReflowState.mComputedMaxWidth;
|
||||
mShrinkWrapWidth = PR_TRUE;
|
||||
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
|
||||
}
|
||||
else {
|
||||
nscoord lr = borderPadding.left + borderPadding.right;
|
||||
@ -646,7 +662,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
// specified style height then we may end up limiting our height if
|
||||
// the availableHeight is constrained (this situation occurs when we
|
||||
// are paginated).
|
||||
mUnconstrainedHeight = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
||||
// We are in a paginated situation. The bottom edge is just inside
|
||||
// the bottom border and padding. The content area height doesn't
|
||||
@ -657,7 +672,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
else {
|
||||
// When we are not in a paginated situation then we always use
|
||||
// an constrained height.
|
||||
mUnconstrainedHeight = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
|
||||
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
|
||||
@ -674,16 +689,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
switch (styleText->mWhiteSpace) {
|
||||
case NS_STYLE_WHITESPACE_PRE:
|
||||
case NS_STYLE_WHITESPACE_NOWRAP:
|
||||
mNoWrap = PR_TRUE;
|
||||
SetFlag(BRS_NOWRAP, PR_TRUE);
|
||||
break;
|
||||
default:
|
||||
mNoWrap = PR_FALSE;
|
||||
SetFlag(BRS_NOWRAP, PR_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
mComputeMaximumWidth = NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH);
|
||||
SetFlag(BRS_COMPUTEMAXWIDTH,
|
||||
(NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
|
||||
mMaximumWidth = 0;
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
@ -729,8 +745,12 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
|
||||
mBand.List();
|
||||
#endif
|
||||
aResult.y = mY;
|
||||
aResult.height = mUnconstrainedHeight
|
||||
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mBottomEdge - mY;
|
||||
|
||||
@ -749,7 +769,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// The child block will flow around the floater. Therefore
|
||||
// give it all of the available space.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
break;
|
||||
@ -776,7 +796,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
// determine width
|
||||
if (mUnconstrainedWidth) {
|
||||
if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aResult.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -810,7 +830,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// doesn't matter therefore give the block element all of the
|
||||
// available space since it will flow around the floater itself.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
}
|
||||
@ -957,12 +977,12 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
|
||||
#endif
|
||||
mKidXMost = xmost;
|
||||
}
|
||||
if (mComputeMaxElementSize) {
|
||||
if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
||||
}
|
||||
|
||||
// If computing the maximum width, then update mMaximumWidth
|
||||
if (mComputeMaximumWidth) {
|
||||
if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
}
|
||||
|
||||
@ -1454,6 +1474,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
||||
NS_BLOCK_MARGIN_ROOT & mState);
|
||||
PRInt32 sizeofBRS = sizeof nsBlockReflowState;
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
RenumberLists(aPresContext);
|
||||
@ -1462,7 +1483,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
PRBool isStyleChange = PR_FALSE;
|
||||
state.mIsInlineIncrReflow = PR_FALSE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_FALSE);
|
||||
nsIFrame* target;
|
||||
switch (aReflowState.reason) {
|
||||
case eReflowReason_Initial:
|
||||
@ -1535,7 +1556,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// reflow the line containing the target of the incr. reflow
|
||||
// first mark the line dirty and set up the state object
|
||||
rv = PrepareChildIncrementalReflow(state);
|
||||
state.mIsInlineIncrReflow = PR_TRUE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
state.mPrevLine = prevLine;
|
||||
state.mCurrentLine = line;
|
||||
state.mNextRCFrame = state.mNextRCFrame;
|
||||
@ -1681,6 +1702,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
if (isStyleChange) {
|
||||
// Lots of things could have changed so damage our entire
|
||||
// bounds
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 1 (%d, %d, %d, %d)\n",
|
||||
this, 0, 0, mRect.width, mRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height));
|
||||
|
||||
} else {
|
||||
@ -1707,6 +1732,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = 0;
|
||||
damageRect.height = mRect.height;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 2 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
|
||||
@ -1730,6 +1759,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = mRect.height - border.bottom;
|
||||
damageRect.height = border.bottom;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 3 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -1868,7 +1901,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
||||
aState.mY, aState.mIsBottomMarginRoot ? "yes" : "no",
|
||||
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
||||
aState.mPrevBottomMargin,
|
||||
borderPadding.top, borderPadding.bottom);
|
||||
#endif
|
||||
@ -1946,7 +1979,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// contents or we fluff out to the maximum block width. Note:
|
||||
// We always shrink wrap when given an unconstrained width.
|
||||
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
|
||||
!aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
|
||||
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && !aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
||||
!compact) {
|
||||
// Set our width to the max width if we aren't already that
|
||||
// wide. Note that the max-width has nothing to do with our
|
||||
@ -1956,9 +1989,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// See if we should compute our max element size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Adjust the computedWidth
|
||||
if (aState.mNoWrap) {
|
||||
if (aState.GetFlag(BRS_NOWRAP)) {
|
||||
// When no-wrap is true the max-element-size.width is the
|
||||
// width of the widest line plus the right border. Note that
|
||||
// aState.mKidXMost already has the left border factored in
|
||||
@ -1996,7 +2029,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// need to do horizontal alignment of the inline lines and make sure
|
||||
// blocks are correctly sized and positioned. Any lines that need
|
||||
// final adjustment will have been marked as dirty
|
||||
if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
|
||||
// If the parent reflow state is also shrink wrap width, then
|
||||
// we don't need to do this, because it will reflow us after it
|
||||
// calculates the final width
|
||||
@ -2025,7 +2058,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
}
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
||||
if (aReflowState.parentReflowState) {
|
||||
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
||||
@ -2047,7 +2080,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// Don't carry out a bottom margin when our height is fixed
|
||||
// unless the bottom of the last line adjoins the bottom of our
|
||||
// content area.
|
||||
if (!aState.mIsBottomMarginRoot) {
|
||||
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
|
||||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
@ -2057,7 +2090,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
@ -2082,7 +2115,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
aMetrics.height = autoHeight;
|
||||
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxHeight = aState.mMaxElementSize.height +
|
||||
borderPadding.top + borderPadding.bottom;
|
||||
}
|
||||
@ -2090,7 +2123,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
aMetrics.descent = 0;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Store away the final value
|
||||
aMetrics.maxElementSize->width = maxWidth;
|
||||
aMetrics.maxElementSize->height = maxHeight;
|
||||
@ -2098,14 +2131,14 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
||||
}
|
||||
if (aState.mComputeMaxElementSize &&
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
||||
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
||||
@ -2115,7 +2148,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
#endif
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
printf("PASS1 ");
|
||||
@ -2130,7 +2163,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// If we're requested to update our maximum width, then compute it
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We need to add in for the right border/padding
|
||||
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
||||
}
|
||||
@ -2337,8 +2370,13 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
// See if we can try and avoid marking all the lines as dirty
|
||||
PRBool tryAndSkipLines = PR_FALSE;
|
||||
|
||||
// See if this is this a constrained resize reflow
|
||||
if ((aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
// we need to calculate if any part of then block itself
|
||||
// is impacted by a floater (bug 19579)
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
// See if this is this a constrained resize reflow that is not impacted by floaters
|
||||
if ((PR_FALSE==aState.IsImpactedByFloater()) &&
|
||||
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
||||
|
||||
// If the text is left-aligned, then we try and avoid reflowing the lines
|
||||
@ -2389,7 +2427,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool notWrapping = aState.mNoWrap;
|
||||
PRBool notWrapping = aState.GetFlag(BRS_NOWRAP);
|
||||
while (nsnull != line) {
|
||||
|
||||
if (line->IsBlock()) {
|
||||
@ -2402,8 +2440,6 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
||||
line, line->IsImpactedByFloater() ? "" : "not ");
|
||||
#endif
|
||||
|
||||
|
||||
if (notWrapping) {
|
||||
// When no-wrap is set then the only line-breaking that
|
||||
// occurs for inline lines is triggered by BR elements or by
|
||||
@ -2430,7 +2466,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
||||
line, line->mNext,
|
||||
line->IsBlock() ? "block" : "inline",
|
||||
aState.mNoWrap ? "no-wrap" : "wrapping",
|
||||
aState.GetFlag(BRS_NOWRAP) ? "no-wrap" : "wrapping",
|
||||
line->HasBreak() ? "has-break " : "",
|
||||
line->HasFloaters() ? "has-floaters " : "",
|
||||
line->IsImpactedByFloater() ? "impacted " : "",
|
||||
@ -2628,7 +2664,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.mIsInlineIncrReflow ? "true" : "false");
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
@ -2651,7 +2687,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// Reflow the lines that are already ours
|
||||
aState.mPrevLine = nsnull;
|
||||
nsLineBox* line = mLines;
|
||||
if (aState.mIsInlineIncrReflow && aState.mNextRCFrame)
|
||||
if (aState.GetFlag(BRS_ISINLINEINCRREFLOW) && aState.mNextRCFrame)
|
||||
{
|
||||
const nsLineBox* incrTargetLine = aState.mCurrentLine;
|
||||
aState.mCurrentLine = line;
|
||||
@ -2662,6 +2698,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 4 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
aState.mPrevLine = line;
|
||||
@ -2689,7 +2729,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// If we're supposed to update our maximum width, then we'll also need to
|
||||
// reflow this line if it's line wrapped and any of the continuing lines
|
||||
// are dirty
|
||||
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
|
||||
if (line->IsDirty() || (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line))) {
|
||||
// Compute the dirty lines "before" YMost, after factoring in
|
||||
// the running deltaY value - the running value is implicit in
|
||||
// aState.mY.
|
||||
@ -2729,6 +2769,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 5 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -2902,6 +2946,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// XXX We need to improve on this...
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
|
||||
} else {
|
||||
@ -2918,6 +2966,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.x;
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
||||
lineCombinedArea.height);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
if (oldCombinedArea.height != lineCombinedArea.height) {
|
||||
@ -2933,6 +2985,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
||||
lineCombinedArea.YMost()) -
|
||||
dirtyRect.y;
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -2951,21 +3007,21 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// we'll either need to recover the floater state that applies to the
|
||||
// unconstrained reflow or keep it around in a separate space manager...
|
||||
PRBool isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
|
||||
if (aState.mComputeMaximumWidth && isBeginningLine) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||
nscoord oldY = aState.mY;
|
||||
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
|
||||
PRBool oldUnconstrainedWidth = aState.mUnconstrainedWidth;
|
||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||
|
||||
// First reflow the line with an unconstrained width. When doing this
|
||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
||||
// associated floater we don't end up resetting the line's right edge and
|
||||
// have it think the width is unconstrained...
|
||||
aState.mUnconstrainedWidth = PR_TRUE;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
|
||||
aState.mY = oldY;
|
||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||
aState.mUnconstrainedWidth = oldUnconstrainedWidth;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||
|
||||
// Update the line's maximum width
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
@ -2980,14 +3036,14 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// Note: we need to reset both member variables, because the inline
|
||||
// code examines mComputeMaxElementSize and if there is a placeholder
|
||||
// on this line the code to reflow the floater looks at both...
|
||||
nscoord oldComputeMaxElementSize = aState.mComputeMaxElementSize;
|
||||
nscoord oldComputeMaximumWidth = aState.mComputeMaximumWidth;
|
||||
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
||||
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
||||
|
||||
aState.mComputeMaxElementSize = PR_FALSE;
|
||||
aState.mComputeMaximumWidth = PR_FALSE;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
aState.mComputeMaxElementSize = oldComputeMaxElementSize;
|
||||
aState.mComputeMaximumWidth = oldComputeMaximumWidth;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
||||
|
||||
} else {
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
@ -3001,6 +3057,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 9 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -3368,7 +3428,7 @@ PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -3377,7 +3437,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -3387,13 +3447,13 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (line->HasFloaters()) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
@ -3486,8 +3546,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
@ -3611,14 +3671,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, combinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line as block so once we known the final shrink wrap width
|
||||
// we can reflow the block to the correct size
|
||||
// XXX We don't always need to do this...
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
if (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Add the right margin to the line's bounnds. That way it will be taken into
|
||||
// account when we compute our shrink wrap size
|
||||
nscoord marginRight = brc.GetMargin().right;
|
||||
@ -3709,7 +3769,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(0, 0);
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxElementSize = brc.GetMaxElementSize();
|
||||
if (aState.IsImpactedByFloater() &&
|
||||
(NS_FRAME_SPLITTABLE_NON_RECTANGULAR != splitType)) {
|
||||
@ -3721,7 +3781,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
}
|
||||
// If we asked the block to update its maximum width, then record the
|
||||
// updated value in the line, and update the current maximum width
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
||||
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
|
||||
@ -3849,7 +3909,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -3872,7 +3932,7 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineLayout lineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
@ -3910,7 +3970,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -4359,7 +4419,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsSize maxElementSize;
|
||||
aLineLayout.VerticalAlignFrames(aLine, maxElementSize);
|
||||
// See if we're shrink wrapping the width
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// When determining the line's width we also need to include any
|
||||
// right floaters that impact us. This represents the shrink wrap
|
||||
// width of the line
|
||||
@ -4388,25 +4448,20 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// Only block frames horizontally align their children because
|
||||
// inline frames "shrink-wrap" around their children (therefore
|
||||
// there is no extra horizontal space).
|
||||
#if XXX_fix_me
|
||||
PRBool allowJustify = PR_TRUE;
|
||||
if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) {
|
||||
allowJustify = ShouldJustifyLine(aState, aLine);
|
||||
}
|
||||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PRBool successful;
|
||||
nsRect combinedArea;
|
||||
successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.mShrinkWrapWidth);
|
||||
const nsStyleText* styleText = (const nsStyleText*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Text);
|
||||
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
||||
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
||||
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
||||
if (!successful) {
|
||||
// Mark the line dirty and then later once we've determined the width
|
||||
// we can do the horizontal alignment
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
|
||||
nsRect combinedArea;
|
||||
aLineLayout.RelativePositionFrames(combinedArea);
|
||||
aLine->SetCombinedArea(combinedArea);
|
||||
if (addedBullet) {
|
||||
@ -4454,7 +4509,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
aState.mY = newY;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
@ -4478,7 +4533,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// we don't want updated...
|
||||
if (aUpdateMaximumWidth) {
|
||||
// However, we do need to update the max-element-size if requested
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(maxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4519,7 +4574,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mHaveRightFloaters &&
|
||||
(aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
|
||||
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// We are reflowing in an unconstrained situation or shrink wrapping and
|
||||
// have some right floaters. They were placed at the infinite right edge
|
||||
// which will cause the combined area to be unusable.
|
||||
@ -4540,11 +4595,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
|
||||
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line dirty so we come back and re-place the floater once
|
||||
// the shrink wrap width is determined
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
}
|
||||
aLine->SetCombinedArea(lineCombinedArea);
|
||||
@ -4629,7 +4684,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
// Update max-element-size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(aMaxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4639,7 +4694,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
// If this is an unconstrained reflow, then cache the line width in the
|
||||
// line. We'll need this during incremental reflow if we're asked to
|
||||
// calculate the maximum width
|
||||
if (aState.mUnconstrainedWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
}
|
||||
|
||||
@ -4653,7 +4708,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
#endif
|
||||
// If we're shrink wrapping our width and the line was wrapped,
|
||||
// then make sure we take up all of the available width
|
||||
if (aState.mShrinkWrapWidth && aLine->IsLineWrapped()) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
|
||||
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
|
||||
|
||||
}
|
||||
@ -5187,6 +5242,10 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||
// cases...
|
||||
nsRect lineCombinedArea;
|
||||
line->GetCombinedArea(&lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
||||
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, lineCombinedArea);
|
||||
line->Destroy(presShell);
|
||||
line = next;
|
||||
@ -5282,8 +5341,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
|
||||
// Setup block reflow state to reflow the floater
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// Reflow the floater
|
||||
@ -5324,7 +5383,7 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
floater->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
// If we computed it, then stash away the max-element-size for later
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.StoreMaxElementSize(floater, brc.GetMaxElementSize());
|
||||
}
|
||||
|
||||
@ -5389,7 +5448,7 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
@ -5615,7 +5674,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
}
|
||||
else {
|
||||
isLeftFloater = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
else {
|
||||
okToAddRectRegion = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.x;
|
||||
}
|
||||
}
|
||||
*aIsLeftFloater = isLeftFloater;
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
@ -5682,7 +5746,8 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
nsRect combinedArea = aFloaterCache->mCombinedArea;
|
||||
combinedArea.x += x;
|
||||
combinedArea.y += y;
|
||||
if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
|
||||
if (!isLeftFloater &&
|
||||
(GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// When we are placing a right floater in an unconstrained situation or
|
||||
// when shrink wrapping, we don't apply it to the floater combined area
|
||||
// immediately. Otherwise we end up with an infinitely wide combined
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
@ -61,6 +63,8 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
//#define NOISY_BLOCK_INVALIDATE // DO NOT CHECK THIS IN TURNED ON!
|
||||
|
||||
static PRBool gLamePaintMetrics;
|
||||
static PRBool gLameReflowMetrics;
|
||||
static PRBool gNoisy;
|
||||
@ -451,12 +455,6 @@ public:
|
||||
|
||||
nscoord mBottomEdge;
|
||||
|
||||
PRPackedBool mUnconstrainedWidth;
|
||||
PRPackedBool mUnconstrainedHeight;
|
||||
PRPackedBool mShrinkWrapWidth;
|
||||
PRPackedBool mNeedResizeReflow;
|
||||
PRPackedBool mIsInlineIncrReflow;
|
||||
|
||||
// The content area to reflow child frames within. The x/y
|
||||
// coordinates are known to be mBorderPadding.left and
|
||||
// mBorderPadding.top. The width/height may be NS_UNCONSTRAINEDSIZE
|
||||
@ -464,15 +462,6 @@ public:
|
||||
// unconstrained area.
|
||||
nsSize mContentArea;
|
||||
|
||||
// Our wrapping behavior
|
||||
PRPackedBool mNoWrap;
|
||||
|
||||
// Is this frame a root for top/bottom margin collapsing?
|
||||
PRPackedBool mIsTopMarginRoot, mIsBottomMarginRoot;
|
||||
|
||||
// See ShouldApplyTopMargin
|
||||
PRPackedBool mApplyTopMargin;
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// This state is "running" state updated by the reflow of each line
|
||||
@ -541,15 +530,48 @@ public:
|
||||
// being N^2.
|
||||
nsFloaterCacheFreeList mBelowCurrentLineFloaters;
|
||||
|
||||
PRPackedBool mComputeMaxElementSize;
|
||||
PRPackedBool mComputeMaximumWidth;
|
||||
|
||||
nsSize mMaxElementSize;
|
||||
nscoord mMaximumWidth;
|
||||
|
||||
nscoord mMinLineHeight;
|
||||
|
||||
PRInt32 mLineNumber;
|
||||
|
||||
// block reflow state flags
|
||||
#define BRS_UNCONSTRAINEDWIDTH 0x00000001
|
||||
#define BRS_UNCONSTRAINEDHEIGHT 0x00000002
|
||||
#define BRS_SHRINKWRAPWIDTH 0x00000004
|
||||
#define BRS_NEEDRESIZEREFLOW 0x00000008
|
||||
#define BRS_ISINLINEINCRREFLOW 0x00000010
|
||||
#define BRS_NOWRAP 0x00000020
|
||||
#define BRS_ISTOPMARGINROOT 0x00000040 // Is this frame a root for top/bottom margin collapsing?
|
||||
#define BRS_ISBOTTOMMARGINROOT 0x00000080
|
||||
#define BRS_APPLYTOPMARGIN 0x00000100 // See ShouldApplyTopMargin
|
||||
#define BRS_COMPUTEMAXELEMENTSIZE 0x00000200
|
||||
#define BRS_COMPUTEMAXWIDTH 0x00000400
|
||||
#define BRS_LASTFLAG BRS_COMPUTEMAXWIDTH
|
||||
|
||||
PRInt16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
// XXX This is vile. Make it go away
|
||||
@ -574,29 +596,25 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
: mBlock(aFrame),
|
||||
mPresContext(aPresContext),
|
||||
mReflowState(aReflowState),
|
||||
mNeedResizeReflow(PR_FALSE),
|
||||
mIsInlineIncrReflow(PR_FALSE),
|
||||
mIsTopMarginRoot(PR_FALSE),
|
||||
mIsBottomMarginRoot(PR_FALSE),
|
||||
mApplyTopMargin(PR_FALSE),
|
||||
mNextRCFrame(nsnull),
|
||||
mPrevBottomMargin(0),
|
||||
mLineNumber(0)
|
||||
mLineNumber(0),
|
||||
mFlags(0)
|
||||
{
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
|
||||
if (aBlockMarginRoot) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.top) {
|
||||
mIsTopMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISTOPMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (0 != aReflowState.mComputedBorderPadding.bottom) {
|
||||
mIsBottomMarginRoot = PR_TRUE;
|
||||
SetFlag(BRS_ISBOTTOMMARGINROOT, PR_TRUE);
|
||||
}
|
||||
if (mIsTopMarginRoot) {
|
||||
mApplyTopMargin = PR_TRUE;
|
||||
if (GetFlag(BRS_ISTOPMARGINROOT)) {
|
||||
SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
}
|
||||
|
||||
mSpaceManager = aReflowState.mSpaceManager;
|
||||
@ -617,21 +635,19 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Compute content area width (the content area is inside the border
|
||||
// and padding)
|
||||
mUnconstrainedWidth = PR_FALSE;
|
||||
mShrinkWrapWidth = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedWidth) {
|
||||
mContentArea.width = aReflowState.mComputedWidth;
|
||||
}
|
||||
else {
|
||||
if (NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth) {
|
||||
mContentArea.width = NS_UNCONSTRAINEDSIZE;
|
||||
mUnconstrainedWidth = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
}
|
||||
else if (NS_UNCONSTRAINEDSIZE != aReflowState.mComputedMaxWidth) {
|
||||
// Choose a width based on the content (shrink wrap width) up
|
||||
// to the maximum width
|
||||
mContentArea.width = aReflowState.mComputedMaxWidth;
|
||||
mShrinkWrapWidth = PR_TRUE;
|
||||
SetFlag(BRS_SHRINKWRAPWIDTH, PR_TRUE);
|
||||
}
|
||||
else {
|
||||
nscoord lr = borderPadding.left + borderPadding.right;
|
||||
@ -646,7 +662,6 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
// specified style height then we may end up limiting our height if
|
||||
// the availableHeight is constrained (this situation occurs when we
|
||||
// are paginated).
|
||||
mUnconstrainedHeight = PR_FALSE;
|
||||
if (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight) {
|
||||
// We are in a paginated situation. The bottom edge is just inside
|
||||
// the bottom border and padding. The content area height doesn't
|
||||
@ -657,7 +672,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
else {
|
||||
// When we are not in a paginated situation then we always use
|
||||
// an constrained height.
|
||||
mUnconstrainedHeight = PR_TRUE;
|
||||
SetFlag(BRS_UNCONSTRAINEDHEIGHT, PR_TRUE);
|
||||
mContentArea.height = mBottomEdge = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
|
||||
@ -674,16 +689,17 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
|
||||
switch (styleText->mWhiteSpace) {
|
||||
case NS_STYLE_WHITESPACE_PRE:
|
||||
case NS_STYLE_WHITESPACE_NOWRAP:
|
||||
mNoWrap = PR_TRUE;
|
||||
SetFlag(BRS_NOWRAP, PR_TRUE);
|
||||
break;
|
||||
default:
|
||||
mNoWrap = PR_FALSE;
|
||||
SetFlag(BRS_NOWRAP, PR_FALSE);
|
||||
break;
|
||||
}
|
||||
|
||||
mComputeMaxElementSize = nsnull != aMetrics.maxElementSize;
|
||||
SetFlag(BRS_COMPUTEMAXELEMENTSIZE, (nsnull != aMetrics.maxElementSize));
|
||||
mMaxElementSize.SizeTo(0, 0);
|
||||
mComputeMaximumWidth = NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH);
|
||||
SetFlag(BRS_COMPUTEMAXWIDTH,
|
||||
(NS_REFLOW_CALC_MAX_WIDTH == (aMetrics.mFlags & NS_REFLOW_CALC_MAX_WIDTH)));
|
||||
mMaximumWidth = 0;
|
||||
|
||||
mMinLineHeight = nsHTMLReflowState::CalcLineHeight(mPresContext,
|
||||
@ -729,8 +745,12 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
const nsStyleDisplay* aDisplay,
|
||||
nsRect& aResult)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("CBAS frame=%p has floater count %d\n", aFrame, mBand.GetFloaterCount());
|
||||
mBand.List();
|
||||
#endif
|
||||
aResult.y = mY;
|
||||
aResult.height = mUnconstrainedHeight
|
||||
aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mBottomEdge - mY;
|
||||
|
||||
@ -749,7 +769,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// The child block will flow around the floater. Therefore
|
||||
// give it all of the available space.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
break;
|
||||
@ -776,7 +796,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
}
|
||||
|
||||
// determine width
|
||||
if (mUnconstrainedWidth) {
|
||||
if (GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aResult.width = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -810,7 +830,7 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
|
||||
// doesn't matter therefore give the block element all of the
|
||||
// available space since it will flow around the floater itself.
|
||||
aResult.x = borderPadding.left;
|
||||
aResult.width = mUnconstrainedWidth
|
||||
aResult.width = GetFlag(BRS_UNCONSTRAINEDWIDTH)
|
||||
? NS_UNCONSTRAINEDSIZE
|
||||
: mContentArea.width;
|
||||
}
|
||||
@ -957,12 +977,12 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine,
|
||||
#endif
|
||||
mKidXMost = xmost;
|
||||
}
|
||||
if (mComputeMaxElementSize) {
|
||||
if (GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
UpdateMaxElementSize(nsSize(aLine->mMaxElementWidth, aLine->mBounds.height));
|
||||
}
|
||||
|
||||
// If computing the maximum width, then update mMaximumWidth
|
||||
if (mComputeMaximumWidth) {
|
||||
if (GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
}
|
||||
|
||||
@ -1454,6 +1474,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics,
|
||||
NS_BLOCK_MARGIN_ROOT & mState);
|
||||
PRInt32 sizeofBRS = sizeof nsBlockReflowState;
|
||||
|
||||
if (eReflowReason_Resize != aReflowState.reason) {
|
||||
RenumberLists(aPresContext);
|
||||
@ -1462,7 +1483,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
PRBool isStyleChange = PR_FALSE;
|
||||
state.mIsInlineIncrReflow = PR_FALSE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_FALSE);
|
||||
nsIFrame* target;
|
||||
switch (aReflowState.reason) {
|
||||
case eReflowReason_Initial:
|
||||
@ -1535,7 +1556,7 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// reflow the line containing the target of the incr. reflow
|
||||
// first mark the line dirty and set up the state object
|
||||
rv = PrepareChildIncrementalReflow(state);
|
||||
state.mIsInlineIncrReflow = PR_TRUE;
|
||||
state.SetFlag(BRS_ISINLINEINCRREFLOW, PR_TRUE);
|
||||
state.mPrevLine = prevLine;
|
||||
state.mCurrentLine = line;
|
||||
state.mNextRCFrame = state.mNextRCFrame;
|
||||
@ -1681,6 +1702,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
if (isStyleChange) {
|
||||
// Lots of things could have changed so damage our entire
|
||||
// bounds
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 1 (%d, %d, %d, %d)\n",
|
||||
this, 0, 0, mRect.width, mRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height));
|
||||
|
||||
} else {
|
||||
@ -1707,6 +1732,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = 0;
|
||||
damageRect.height = mRect.height;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 2 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
|
||||
@ -1730,6 +1759,10 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
|
||||
damageRect.y = mRect.height - border.bottom;
|
||||
damageRect.height = border.bottom;
|
||||
}
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 3 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -1868,7 +1901,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
#ifdef NOISY_FINAL_SIZE
|
||||
ListTag(stdout);
|
||||
printf(": mY=%d mIsBottomMarginRoot=%s mPrevBottomMargin=%d bp=%d,%d\n",
|
||||
aState.mY, aState.mIsBottomMarginRoot ? "yes" : "no",
|
||||
aState.mY, aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? "yes" : "no",
|
||||
aState.mPrevBottomMargin,
|
||||
borderPadding.top, borderPadding.bottom);
|
||||
#endif
|
||||
@ -1946,7 +1979,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// contents or we fluff out to the maximum block width. Note:
|
||||
// We always shrink wrap when given an unconstrained width.
|
||||
if ((0 == (NS_BLOCK_SHRINK_WRAP & mState)) &&
|
||||
!aState.mUnconstrainedWidth && !aState.mShrinkWrapWidth &&
|
||||
!aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) && !aState.GetFlag(BRS_SHRINKWRAPWIDTH) &&
|
||||
!compact) {
|
||||
// Set our width to the max width if we aren't already that
|
||||
// wide. Note that the max-width has nothing to do with our
|
||||
@ -1956,9 +1989,9 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// See if we should compute our max element size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Adjust the computedWidth
|
||||
if (aState.mNoWrap) {
|
||||
if (aState.GetFlag(BRS_NOWRAP)) {
|
||||
// When no-wrap is true the max-element-size.width is the
|
||||
// width of the widest line plus the right border. Note that
|
||||
// aState.mKidXMost already has the left border factored in
|
||||
@ -1996,7 +2029,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// need to do horizontal alignment of the inline lines and make sure
|
||||
// blocks are correctly sized and positioned. Any lines that need
|
||||
// final adjustment will have been marked as dirty
|
||||
if (aState.mShrinkWrapWidth && aState.mNeedResizeReflow) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aState.GetFlag(BRS_NEEDRESIZEREFLOW)) {
|
||||
// If the parent reflow state is also shrink wrap width, then
|
||||
// we don't need to do this, because it will reflow us after it
|
||||
// calculates the final width
|
||||
@ -2025,7 +2058,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
}
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
PRBool parentIsShrinkWrapWidth = PR_FALSE;
|
||||
if (aReflowState.parentReflowState) {
|
||||
if (NS_SHRINKWRAPWIDTH == aReflowState.parentReflowState->mComputedWidth) {
|
||||
@ -2047,7 +2080,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
// Don't carry out a bottom margin when our height is fixed
|
||||
// unless the bottom of the last line adjoins the bottom of our
|
||||
// content area.
|
||||
if (!aState.mIsBottomMarginRoot) {
|
||||
if (!aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
if (aState.mY + aState.mPrevBottomMargin != aMetrics.height) {
|
||||
aState.mPrevBottomMargin = 0;
|
||||
}
|
||||
@ -2057,7 +2090,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
nscoord autoHeight = aState.mY;
|
||||
|
||||
// Shrink wrap our height around our contents.
|
||||
if (aState.mIsBottomMarginRoot) {
|
||||
if (aState.GetFlag(BRS_ISBOTTOMMARGINROOT)) {
|
||||
// When we are a bottom-margin root make sure that our last
|
||||
// childs bottom margin is fully applied.
|
||||
// XXX check for a fit
|
||||
@ -2082,7 +2115,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
aMetrics.height = autoHeight;
|
||||
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxHeight = aState.mMaxElementSize.height +
|
||||
borderPadding.top + borderPadding.bottom;
|
||||
}
|
||||
@ -2090,7 +2123,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
aMetrics.ascent = aMetrics.height;
|
||||
aMetrics.descent = 0;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
// Store away the final value
|
||||
aMetrics.maxElementSize->width = maxWidth;
|
||||
aMetrics.maxElementSize->height = maxHeight;
|
||||
@ -2098,14 +2131,14 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
|
||||
// Return bottom margin information
|
||||
aMetrics.mCarriedOutBottomMargin =
|
||||
aState.mIsBottomMarginRoot ? 0 : aState.mPrevBottomMargin;
|
||||
aState.GetFlag(BRS_ISBOTTOMMARGINROOT) ? 0 : aState.mPrevBottomMargin;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (CRAZY_WIDTH(aMetrics.width) || CRAZY_HEIGHT(aMetrics.height)) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: desired:%d,%d\n", aMetrics.width, aMetrics.height);
|
||||
}
|
||||
if (aState.mComputeMaxElementSize &&
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE) &&
|
||||
((maxWidth > aMetrics.width) || (maxHeight > aMetrics.height))) {
|
||||
ListTag(stdout);
|
||||
printf(": WARNING: max-element-size:%d,%d desired:%d,%d maxSize:%d,%d\n",
|
||||
@ -2115,7 +2148,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
#endif
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
printf("PASS1 ");
|
||||
@ -2130,7 +2163,7 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
|
||||
}
|
||||
|
||||
// If we're requested to update our maximum width, then compute it
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
// We need to add in for the right border/padding
|
||||
aMetrics.mMaximumWidth = aState.mMaximumWidth + borderPadding.right;
|
||||
}
|
||||
@ -2337,8 +2370,13 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
// See if we can try and avoid marking all the lines as dirty
|
||||
PRBool tryAndSkipLines = PR_FALSE;
|
||||
|
||||
// See if this is this a constrained resize reflow
|
||||
if ((aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
// we need to calculate if any part of then block itself
|
||||
// is impacted by a floater (bug 19579)
|
||||
aState.GetAvailableSpace();
|
||||
|
||||
// See if this is this a constrained resize reflow that is not impacted by floaters
|
||||
if ((PR_FALSE==aState.IsImpactedByFloater()) &&
|
||||
(aState.mReflowState.reason == eReflowReason_Resize) &&
|
||||
(NS_UNCONSTRAINEDSIZE != aState.mReflowState.availableWidth)) {
|
||||
|
||||
// If the text is left-aligned, then we try and avoid reflowing the lines
|
||||
@ -2389,7 +2427,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
}
|
||||
#endif
|
||||
|
||||
PRBool notWrapping = aState.mNoWrap;
|
||||
PRBool notWrapping = aState.GetFlag(BRS_NOWRAP);
|
||||
while (nsnull != line) {
|
||||
|
||||
if (line->IsBlock()) {
|
||||
@ -2402,8 +2440,6 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("PrepareResizeReflow thinks line %p is %simpacted by floaters\n",
|
||||
line, line->IsImpactedByFloater() ? "" : "not ");
|
||||
#endif
|
||||
|
||||
|
||||
if (notWrapping) {
|
||||
// When no-wrap is set then the only line-breaking that
|
||||
// occurs for inline lines is triggered by BR elements or by
|
||||
@ -2430,7 +2466,7 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState)
|
||||
printf("skipped: line=%p next=%p %s %s %s%s%s breakType=%d xmost=%d\n",
|
||||
line, line->mNext,
|
||||
line->IsBlock() ? "block" : "inline",
|
||||
aState.mNoWrap ? "no-wrap" : "wrapping",
|
||||
aState.GetFlag(BRS_NOWRAP) ? "no-wrap" : "wrapping",
|
||||
line->HasBreak() ? "has-break " : "",
|
||||
line->HasFloaters() ? "has-floaters " : "",
|
||||
line->IsImpactedByFloater() ? "impacted " : "",
|
||||
@ -2628,7 +2664,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
ListTag(stdout);
|
||||
printf(": incrementally reflowing dirty lines: type=%s(%d) isInline=%s",
|
||||
kReflowCommandType[type], type,
|
||||
aState.mIsInlineIncrReflow ? "true" : "false");
|
||||
aState.GetFlag(BRS_ISINLINEINCRREFLOW) ? "true" : "false");
|
||||
}
|
||||
else {
|
||||
IndentBy(stdout, gNoiseIndent);
|
||||
@ -2651,7 +2687,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// Reflow the lines that are already ours
|
||||
aState.mPrevLine = nsnull;
|
||||
nsLineBox* line = mLines;
|
||||
if (aState.mIsInlineIncrReflow && aState.mNextRCFrame)
|
||||
if (aState.GetFlag(BRS_ISINLINEINCRREFLOW) && aState.mNextRCFrame)
|
||||
{
|
||||
const nsLineBox* incrTargetLine = aState.mCurrentLine;
|
||||
aState.mCurrentLine = line;
|
||||
@ -2662,6 +2698,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 4 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
aState.mPrevLine = line;
|
||||
@ -2689,7 +2729,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
// If we're supposed to update our maximum width, then we'll also need to
|
||||
// reflow this line if it's line wrapped and any of the continuing lines
|
||||
// are dirty
|
||||
if (line->IsDirty() || (aState.mComputeMaximumWidth && ::WrappedLinesAreDirty(line))) {
|
||||
if (line->IsDirty() || (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && ::WrappedLinesAreDirty(line))) {
|
||||
// Compute the dirty lines "before" YMost, after factoring in
|
||||
// the running deltaY value - the running value is implicit in
|
||||
// aState.mY.
|
||||
@ -2729,6 +2769,10 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
RecoverStateFrom(aState, line, deltaY, incrementalReflow ?
|
||||
&damageRect : 0);
|
||||
if (incrementalReflow && !damageRect.IsEmpty()) {
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 5 (%d, %d, %d, %d)\n",
|
||||
this, damageRect.x, damageRect.y, damageRect.width, damageRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, damageRect);
|
||||
}
|
||||
}
|
||||
@ -2902,6 +2946,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// XXX We need to improve on this...
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 6 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
|
||||
} else {
|
||||
@ -2918,6 +2966,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.x;
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.height,
|
||||
lineCombinedArea.height);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 7 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
if (oldCombinedArea.height != lineCombinedArea.height) {
|
||||
@ -2933,6 +2985,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
dirtyRect.height = PR_MAX(oldCombinedArea.YMost(),
|
||||
lineCombinedArea.YMost()) -
|
||||
dirtyRect.y;
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 8 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -2951,21 +3007,21 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// we'll either need to recover the floater state that applies to the
|
||||
// unconstrained reflow or keep it around in a separate space manager...
|
||||
PRBool isBeginningLine = !aState.mPrevLine || !aState.mPrevLine->IsLineWrapped();
|
||||
if (aState.mComputeMaximumWidth && isBeginningLine) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH) && isBeginningLine) {
|
||||
nscoord oldY = aState.mY;
|
||||
nscoord oldPrevBottomMargin = aState.mPrevBottomMargin;
|
||||
PRBool oldUnconstrainedWidth = aState.mUnconstrainedWidth;
|
||||
PRBool oldUnconstrainedWidth = aState.GetFlag(BRS_UNCONSTRAINEDWIDTH);
|
||||
|
||||
// First reflow the line with an unconstrained width. When doing this
|
||||
// we need to set the block reflow state's "mUnconstrainedWidth" variable
|
||||
// to PR_TRUE so if we encounter a placeholder and then reflow its
|
||||
// associated floater we don't end up resetting the line's right edge and
|
||||
// have it think the width is unconstrained...
|
||||
aState.mUnconstrainedWidth = PR_TRUE;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, PR_TRUE);
|
||||
ReflowInlineFrames(aState, aLine, aKeepReflowGoing, PR_TRUE);
|
||||
aState.mY = oldY;
|
||||
aState.mPrevBottomMargin = oldPrevBottomMargin;
|
||||
aState.mUnconstrainedWidth = oldUnconstrainedWidth;
|
||||
aState.SetFlag(BRS_UNCONSTRAINEDWIDTH, oldUnconstrainedWidth);
|
||||
|
||||
// Update the line's maximum width
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
@ -2980,14 +3036,14 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
// Note: we need to reset both member variables, because the inline
|
||||
// code examines mComputeMaxElementSize and if there is a placeholder
|
||||
// on this line the code to reflow the floater looks at both...
|
||||
nscoord oldComputeMaxElementSize = aState.mComputeMaxElementSize;
|
||||
nscoord oldComputeMaximumWidth = aState.mComputeMaximumWidth;
|
||||
nscoord oldComputeMaxElementSize = aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE);
|
||||
nscoord oldComputeMaximumWidth = aState.GetFlag(BRS_COMPUTEMAXWIDTH);
|
||||
|
||||
aState.mComputeMaxElementSize = PR_FALSE;
|
||||
aState.mComputeMaximumWidth = PR_FALSE;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, PR_FALSE);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, PR_FALSE);
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
aState.mComputeMaxElementSize = oldComputeMaxElementSize;
|
||||
aState.mComputeMaximumWidth = oldComputeMaximumWidth;
|
||||
aState.SetFlag(BRS_COMPUTEMAXELEMENTSIZE, oldComputeMaxElementSize);
|
||||
aState.SetFlag(BRS_COMPUTEMAXWIDTH, oldComputeMaximumWidth);
|
||||
|
||||
} else {
|
||||
rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
|
||||
@ -3001,6 +3057,10 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState,
|
||||
|
||||
nsRect dirtyRect;
|
||||
dirtyRect.UnionRect(oldCombinedArea, combinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 9 (%d, %d, %d, %d)\n",
|
||||
this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height);
|
||||
#endif
|
||||
Invalidate(aState.mPresContext, dirtyRect);
|
||||
}
|
||||
}
|
||||
@ -3368,7 +3428,7 @@ PRBool
|
||||
nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
nsLineBox* aLine)
|
||||
{
|
||||
if (aState.mApplyTopMargin) {
|
||||
if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
|
||||
// Apply short-circuit check to avoid searching the line list
|
||||
return PR_TRUE;
|
||||
}
|
||||
@ -3377,7 +3437,7 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
// If we aren't at the top Y coordinate then something of non-zero
|
||||
// height must have been placed. Therefore the childs top-margin
|
||||
// applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -3387,13 +3447,13 @@ nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
|
||||
if (line->IsBlock()) {
|
||||
// A line which preceeds aLine contains a block; therefore the
|
||||
// top margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (line->HasFloaters()) {
|
||||
// A line which preceeds aLine is not empty therefore the top
|
||||
// margin applies.
|
||||
aState.mApplyTopMargin = PR_TRUE;
|
||||
aState.SetFlag(BRS_APPLYTOPMARGIN, PR_TRUE);
|
||||
return PR_TRUE;
|
||||
}
|
||||
line = line->mNext;
|
||||
@ -3486,8 +3546,8 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
frame->GetStyleData(eStyleStruct_Display,
|
||||
(const nsStyleStruct*&) display);
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// See if we should apply the top margin. If the block frame being
|
||||
@ -3611,14 +3671,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
&collapsedBottomMargin,
|
||||
aLine->mBounds, combinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line as block so once we known the final shrink wrap width
|
||||
// we can reflow the block to the correct size
|
||||
// XXX We don't always need to do this...
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
if (aState.mUnconstrainedWidth || aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Add the right margin to the line's bounnds. That way it will be taken into
|
||||
// account when we compute our shrink wrap size
|
||||
nscoord marginRight = brc.GetMargin().right;
|
||||
@ -3709,7 +3769,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
|
||||
// Post-process the "line"
|
||||
nsSize maxElementSize(0, 0);
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
maxElementSize = brc.GetMaxElementSize();
|
||||
if (aState.IsImpactedByFloater() &&
|
||||
(NS_FRAME_SPLITTABLE_NON_RECTANGULAR != splitType)) {
|
||||
@ -3721,7 +3781,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
|
||||
}
|
||||
// If we asked the block to update its maximum width, then record the
|
||||
// updated value in the line, and update the current maximum width
|
||||
if (aState.mComputeMaximumWidth) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXWIDTH)) {
|
||||
aLine->mMaximumWidth = brc.GetMaximumWidth();
|
||||
aState.UpdateMaximumWidth(aLine->mMaximumWidth);
|
||||
|
||||
@ -3849,7 +3909,7 @@ nsBlockFrame::DoReflowInlineFramesMalloc(nsBlockReflowState& aState,
|
||||
nsLineLayout* ll = new nsLineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
if (!ll) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -3872,7 +3932,7 @@ nsBlockFrame::DoReflowInlineFramesAuto(nsBlockReflowState& aState,
|
||||
nsLineLayout lineLayout(aState.mPresContext,
|
||||
aState.mReflowState.mSpaceManager,
|
||||
&aState.mReflowState,
|
||||
aState.mComputeMaxElementSize);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE));
|
||||
lineLayout.Init(&aState, aState.mMinLineHeight, aState.mLineNumber);
|
||||
lineLayout.SetReflowTextRuns(mTextRuns);
|
||||
nsresult rv = DoReflowInlineFrames(aState, lineLayout, aLine,
|
||||
@ -3910,7 +3970,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
nscoord x = aState.mAvailSpaceRect.x + borderPadding.left;
|
||||
nscoord availWidth = aState.mAvailSpaceRect.width;
|
||||
nscoord availHeight;
|
||||
if (aState.mUnconstrainedHeight) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDHEIGHT)) {
|
||||
availHeight = NS_UNCONSTRAINEDSIZE;
|
||||
}
|
||||
else {
|
||||
@ -4359,7 +4419,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
nsSize maxElementSize;
|
||||
aLineLayout.VerticalAlignFrames(aLine, maxElementSize);
|
||||
// See if we're shrink wrapping the width
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// When determining the line's width we also need to include any
|
||||
// right floaters that impact us. This represents the shrink wrap
|
||||
// width of the line
|
||||
@ -4388,25 +4448,20 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// Only block frames horizontally align their children because
|
||||
// inline frames "shrink-wrap" around their children (therefore
|
||||
// there is no extra horizontal space).
|
||||
#if XXX_fix_me
|
||||
PRBool allowJustify = PR_TRUE;
|
||||
if (NS_STYLE_TEXT_ALIGN_JUSTIFY == aState.mStyleText->mTextAlign) {
|
||||
allowJustify = ShouldJustifyLine(aState, aLine);
|
||||
}
|
||||
#else
|
||||
PRBool allowJustify = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PRBool successful;
|
||||
nsRect combinedArea;
|
||||
successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.mShrinkWrapWidth);
|
||||
const nsStyleText* styleText = (const nsStyleText*)
|
||||
mStyleContext->GetStyleData(eStyleStruct_Text);
|
||||
PRBool allowJustify = NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign
|
||||
&& !aLineLayout.GetLineEndsInBR() && ShouldJustifyLine(aState, aLine);
|
||||
PRBool successful = aLineLayout.HorizontalAlignFrames(aLine->mBounds, allowJustify,
|
||||
aState.GetFlag(BRS_SHRINKWRAPWIDTH));
|
||||
if (!successful) {
|
||||
// Mark the line dirty and then later once we've determined the width
|
||||
// we can do the horizontal alignment
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
|
||||
nsRect combinedArea;
|
||||
aLineLayout.RelativePositionFrames(combinedArea);
|
||||
aLine->SetCombinedArea(combinedArea);
|
||||
if (addedBullet) {
|
||||
@ -4454,7 +4509,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
aState.mY = newY;
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||
IndentBy(stdout, GetDepth());
|
||||
if (NS_UNCONSTRAINEDSIZE == aState.mReflowState.availableWidth) {
|
||||
@ -4478,7 +4533,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
// we don't want updated...
|
||||
if (aUpdateMaximumWidth) {
|
||||
// However, we do need to update the max-element-size if requested
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(maxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4519,7 +4574,7 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
CombineRects(aState.mFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mHaveRightFloaters &&
|
||||
(aState.mUnconstrainedWidth || aState.mShrinkWrapWidth)) {
|
||||
(aState.GetFlag(BRS_UNCONSTRAINEDWIDTH) || aState.GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// We are reflowing in an unconstrained situation or shrink wrapping and
|
||||
// have some right floaters. They were placed at the infinite right edge
|
||||
// which will cause the combined area to be unusable.
|
||||
@ -4540,11 +4595,11 @@ nsBlockFrame::PlaceLine(nsBlockReflowState& aState,
|
||||
aState.mRightFloaterCombinedArea.x = aLine->mBounds.XMost();
|
||||
CombineRects(aState.mRightFloaterCombinedArea, lineCombinedArea);
|
||||
|
||||
if (aState.mShrinkWrapWidth) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH)) {
|
||||
// Mark the line dirty so we come back and re-place the floater once
|
||||
// the shrink wrap width is determined
|
||||
aLine->MarkDirty();
|
||||
aState.mNeedResizeReflow = PR_TRUE;
|
||||
aState.SetFlag(BRS_NEEDRESIZEREFLOW, PR_TRUE);
|
||||
}
|
||||
}
|
||||
aLine->SetCombinedArea(lineCombinedArea);
|
||||
@ -4629,7 +4684,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
}
|
||||
|
||||
// Update max-element-size
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.UpdateMaxElementSize(aMaxElementSize);
|
||||
// We also cache the max element width in the line. This is needed for
|
||||
// incremental reflow
|
||||
@ -4639,7 +4694,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
// If this is an unconstrained reflow, then cache the line width in the
|
||||
// line. We'll need this during incremental reflow if we're asked to
|
||||
// calculate the maximum width
|
||||
if (aState.mUnconstrainedWidth) {
|
||||
if (aState.GetFlag(BRS_UNCONSTRAINEDWIDTH)) {
|
||||
aLine->mMaximumWidth = aLine->mBounds.XMost();
|
||||
}
|
||||
|
||||
@ -4653,7 +4708,7 @@ nsBlockFrame::PostPlaceLine(nsBlockReflowState& aState,
|
||||
#endif
|
||||
// If we're shrink wrapping our width and the line was wrapped,
|
||||
// then make sure we take up all of the available width
|
||||
if (aState.mShrinkWrapWidth && aLine->IsLineWrapped()) {
|
||||
if (aState.GetFlag(BRS_SHRINKWRAPWIDTH) && aLine->IsLineWrapped()) {
|
||||
aState.mKidXMost = aState.BorderPadding().left + aState.mContentArea.width;
|
||||
|
||||
}
|
||||
@ -5187,6 +5242,10 @@ nsBlockFrame::DoRemoveFrame(nsIPresContext* aPresContext,
|
||||
// cases...
|
||||
nsRect lineCombinedArea;
|
||||
line->GetCombinedArea(&lineCombinedArea);
|
||||
#ifdef NOISY_BLOCK_INVALIDATE
|
||||
printf("%p invalidate 10 (%d, %d, %d, %d)\n",
|
||||
this, lineCombinedArea.x, lineCombinedArea.y, lineCombinedArea.width, lineCombinedArea.height);
|
||||
#endif
|
||||
Invalidate(aPresContext, lineCombinedArea);
|
||||
line->Destroy(presShell);
|
||||
line = next;
|
||||
@ -5282,8 +5341,8 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
|
||||
// Setup block reflow state to reflow the floater
|
||||
nsBlockReflowContext brc(aState.mPresContext, aState.mReflowState,
|
||||
aState.mComputeMaxElementSize,
|
||||
aState.mComputeMaximumWidth);
|
||||
aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE),
|
||||
aState.GetFlag(BRS_COMPUTEMAXWIDTH));
|
||||
brc.SetNextRCFrame(aState.mNextRCFrame);
|
||||
|
||||
// Reflow the floater
|
||||
@ -5324,7 +5383,7 @@ nsBlockFrame::ReflowFloater(nsBlockReflowState& aState,
|
||||
floater->DidReflow(aState.mPresContext, NS_FRAME_REFLOW_FINISHED);
|
||||
|
||||
// If we computed it, then stash away the max-element-size for later
|
||||
if (aState.mComputeMaxElementSize) {
|
||||
if (aState.GetFlag(BRS_COMPUTEMAXELEMENTSIZE)) {
|
||||
aState.StoreMaxElementSize(floater, brc.GetMaxElementSize());
|
||||
}
|
||||
|
||||
@ -5389,7 +5448,7 @@ nsBlockReflowState::AddFloater(nsLineLayout& aLineLayout,
|
||||
// Pass on updated available space to the current inline reflow engine
|
||||
GetAvailableSpace();
|
||||
aLineLayout.UpdateBand(mAvailSpaceRect.x + BorderPadding().left, mY,
|
||||
mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
GetFlag(BRS_UNCONSTRAINEDWIDTH) ? NS_UNCONSTRAINEDSIZE : mAvailSpaceRect.width,
|
||||
mAvailSpaceRect.height,
|
||||
isLeftFloater,
|
||||
aPlaceholder->GetOutOfFlowFrame());
|
||||
@ -5615,7 +5674,12 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
}
|
||||
else {
|
||||
isLeftFloater = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
if (NS_UNCONSTRAINEDSIZE != mAvailSpaceRect.XMost())
|
||||
region.x = mAvailSpaceRect.XMost() - region.width;
|
||||
else {
|
||||
okToAddRectRegion = PR_FALSE;
|
||||
region.x = mAvailSpaceRect.x;
|
||||
}
|
||||
}
|
||||
*aIsLeftFloater = isLeftFloater;
|
||||
const nsMargin& borderPadding = BorderPadding();
|
||||
@ -5682,7 +5746,8 @@ nsBlockReflowState::PlaceFloater(nsFloaterCache* aFloaterCache,
|
||||
nsRect combinedArea = aFloaterCache->mCombinedArea;
|
||||
combinedArea.x += x;
|
||||
combinedArea.y += y;
|
||||
if (!isLeftFloater && (mUnconstrainedWidth || mShrinkWrapWidth)) {
|
||||
if (!isLeftFloater &&
|
||||
(GetFlag(BRS_UNCONSTRAINEDWIDTH) || GetFlag(BRS_SHRINKWRAPWIDTH))) {
|
||||
// When we are placing a right floater in an unconstrained situation or
|
||||
// when shrink wrapping, we don't apply it to the floater combined area
|
||||
// immediately. Otherwise we end up with an infinitely wide combined
|
||||
|
@ -879,6 +879,13 @@ nsImageFrame::AttributeChanged(nsIPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (nsHTMLAtoms::width == aAttribute || nsHTMLAtoms::height == aAttribute)
|
||||
{ // XXX: could check for new width == old width, and make that a no-op
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
aPresContext->GetShell(getter_AddRefs(presShell));
|
||||
mState |= NS_FRAME_IS_DIRTY;
|
||||
mParent->ReflowDirtyChild(presShell, (nsIFrame*) this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -18,8 +18,10 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* L. David Baron <dbaron@fas.harvard.edu>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsLineLayout.h"
|
||||
@ -41,13 +43,14 @@
|
||||
#include "nsIView.h"
|
||||
#include "nsIViewManager.h"
|
||||
#include "nsHTMLAtoms.h"
|
||||
#include "nsTextFragment.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#undef NOISY_HORIZONTAL_ALIGN
|
||||
#undef NOISY_VERTICAL_ALIGN
|
||||
#undef REALLY_NOISY_VERTICAL_ALIGN
|
||||
#undef NOISY_REFLOW
|
||||
#undef REALLY_NOISY_REFLOW
|
||||
#undef REALLY_NOISY_REFLOW
|
||||
#undef NOISY_PUSHING
|
||||
#undef REALLY_NOISY_PUSHING
|
||||
#undef DEBUG_ADD_TEXT
|
||||
@ -120,15 +123,9 @@ nsLineLayout::nsLineLayout(nsIPresContext* aPresContext,
|
||||
mTextAlign = mStyleText->mTextAlign;
|
||||
mLineNumber = 0;
|
||||
mColumn = 0;
|
||||
mEndsInWhiteSpace = PR_TRUE;
|
||||
mUnderstandsWhiteSpace = PR_FALSE;
|
||||
mTextStartsWithNBSP = PR_FALSE;
|
||||
mFirstLetterStyleOK = PR_FALSE;
|
||||
mIsTopOfPage = PR_FALSE;
|
||||
mUpdatedBand = PR_FALSE;
|
||||
mFlags = 0; // default all flags to false except those that follow here...
|
||||
SetFlag(LL_ENDSINWHITESPACE, PR_TRUE);
|
||||
mPlacedFloaters = 0;
|
||||
mImpactedByFloaters = PR_FALSE;
|
||||
mLastFloaterWasLetterFrame = PR_FALSE;
|
||||
mTotalPlacedFrames = 0;
|
||||
mTopEdge = mBottomEdge = 0;
|
||||
mReflowTextRuns = nsnull;
|
||||
@ -148,14 +145,17 @@ nsLineLayout::nsLineLayout(nsIPresContext* aPresContext,
|
||||
mTextRuns = nsnull;
|
||||
mTextRunP = &mTextRuns;
|
||||
mNewTextRun = nsnull;
|
||||
mKnowStrictMode = PR_FALSE;
|
||||
SetFlag(LL_KNOWSTRICTMODE, PR_FALSE);
|
||||
PRInt32 size = sizeof nsLineLayout;
|
||||
PRInt32 size_pfd = sizeof PerFrameData;
|
||||
PRInt32 size_psd = sizeof PerSpanData;
|
||||
}
|
||||
|
||||
nsLineLayout::nsLineLayout(nsIPresContext* aPresContext)
|
||||
: mPresContext(aPresContext)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsLineLayout);
|
||||
|
||||
|
||||
mTextRuns = nsnull;
|
||||
mTextRunP = &mTextRuns;
|
||||
mNewTextRun = nsnull;
|
||||
@ -197,9 +197,9 @@ nsLineLayout::~nsLineLayout()
|
||||
PRBool
|
||||
nsLineLayout::InStrictMode()
|
||||
{
|
||||
if (!mKnowStrictMode) {
|
||||
mKnowStrictMode = PR_TRUE;
|
||||
mInStrictMode = PR_TRUE;
|
||||
if (!GetFlag(LL_KNOWSTRICTMODE)) {
|
||||
SetFlag(LL_KNOWSTRICTMODE, PR_TRUE);
|
||||
SetFlag(LL_INSTRICTMODE, PR_TRUE);
|
||||
|
||||
// Get the compatabilty mode from pres context via the document and pres shell
|
||||
if (mBlockReflowState->frame) {
|
||||
@ -217,7 +217,7 @@ nsLineLayout::InStrictMode()
|
||||
nsCompatibility mode;
|
||||
presContext->GetCompatibilityMode(&mode);
|
||||
if (eCompatibility_NavQuirks == mode) {
|
||||
mInStrictMode = PR_FALSE;
|
||||
SetFlag(LL_INSTRICTMODE, PR_FALSE);
|
||||
}
|
||||
}
|
||||
NS_RELEASE(shell);
|
||||
@ -226,7 +226,7 @@ nsLineLayout::InStrictMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
return mInStrictMode;
|
||||
return GetFlag(LL_INSTRICTMODE);
|
||||
}
|
||||
|
||||
void
|
||||
@ -235,10 +235,6 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
||||
PRBool aImpactedByFloaters,
|
||||
PRBool aIsTopOfPage)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("nsLL::BeginLineReflow %d, %d, %d, %d, impacted=%s\n",
|
||||
aX, aY, aWidth, aHeight, aImpactedByFloaters?"true":"false");
|
||||
#endif
|
||||
NS_ASSERTION(nsnull == mRootSpan, "bad linelayout user");
|
||||
#ifdef DEBUG
|
||||
if ((aWidth != NS_UNCONSTRAINEDSIZE) && CRAZY_WIDTH(aWidth)) {
|
||||
@ -256,8 +252,9 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
||||
#endif
|
||||
#ifdef NOISY_REFLOW
|
||||
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
||||
printf(": BeginLineReflow: %d,%d,%d,%d %s\n",
|
||||
printf(": BeginLineReflow: %d,%d,%d,%d impacted=%s %s\n",
|
||||
aX, aY, aWidth, aHeight,
|
||||
aImpactedByFloaters?"true":"false",
|
||||
aIsTopOfPage ? "top-of-page" : "");
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
@ -265,17 +262,18 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
||||
#endif
|
||||
|
||||
mColumn = 0;
|
||||
mEndsInWhiteSpace = PR_TRUE;
|
||||
mUnderstandsWhiteSpace = PR_FALSE;
|
||||
mTextStartsWithNBSP = PR_FALSE;
|
||||
mFirstLetterStyleOK = PR_FALSE;
|
||||
mIsTopOfPage = aIsTopOfPage;
|
||||
mUpdatedBand = PR_FALSE;
|
||||
|
||||
SetFlag(LL_ENDSINWHITESPACE, PR_TRUE);
|
||||
SetFlag(LL_UNDERSTANDSNWHITESPACE, PR_FALSE);
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, PR_FALSE);
|
||||
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);
|
||||
SetFlag(LL_ISTOPOFPAGE, aIsTopOfPage);
|
||||
SetFlag(LL_UPDATEDBAND, PR_FALSE);
|
||||
mPlacedFloaters = 0;
|
||||
mImpactedByFloaters = aImpactedByFloaters;
|
||||
SetFlag(LL_IMPACTEDBYFLOATERS, aImpactedByFloaters);
|
||||
mTotalPlacedFrames = 0;
|
||||
mCanPlaceFloater = PR_TRUE;
|
||||
mLineEndsInBR = PR_FALSE;
|
||||
SetFlag(LL_CANPLACEFLOATER, PR_TRUE);
|
||||
SetFlag(LL_LINEENDSINBR, PR_FALSE);
|
||||
mSpanDepth = 0;
|
||||
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
||||
|
||||
@ -355,7 +353,7 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
||||
nsIFrame* aFloaterFrame)
|
||||
{
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p placedLeft=%s\n will set mImpacted to PR_TRUE",
|
||||
printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p placedLeft=%s\n will set mImpacted to PR_TRUE\n",
|
||||
aX, aY, aWidth, aHeight, aFloaterFrame, aPlacedLeftFloater?"true":"false");
|
||||
#endif
|
||||
PerSpanData* psd = mRootSpan;
|
||||
@ -404,13 +402,13 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
||||
else {
|
||||
mBottomEdge = aY + aHeight;
|
||||
}
|
||||
mUpdatedBand = PR_TRUE;
|
||||
SetFlag(LL_UPDATEDBAND, PR_TRUE);
|
||||
mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT);
|
||||
mImpactedByFloaters = PR_TRUE;
|
||||
SetFlag(LL_IMPACTEDBYFLOATERS, PR_TRUE);
|
||||
|
||||
nsCOMPtr<nsIAtom> frameType;
|
||||
aFloaterFrame->GetFrameType(getter_AddRefs(frameType));
|
||||
mLastFloaterWasLetterFrame = nsLayoutAtoms::letterFrame == frameType.get();
|
||||
SetFlag(LL_LASTFLOATERWASLETTERFRAME, (nsLayoutAtoms::letterFrame == frameType.get()));
|
||||
|
||||
// Now update all of the open spans...
|
||||
mRootSpan->mContainsFloater = PR_TRUE; // make sure mRootSpan gets updated too
|
||||
@ -762,17 +760,10 @@ nsLineLayout::NewPerFrameData(PerFrameData** aResult)
|
||||
pfd->mNext = nsnull;
|
||||
pfd->mPrev = nsnull;
|
||||
pfd->mFrame = nsnull;
|
||||
pfd->mRelativePos = PR_FALSE;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
pfd->mIsNonWhitespaceTextFrame = PR_FALSE;
|
||||
pfd->mIsLetterFrame = PR_FALSE;
|
||||
pfd->mIsSticky = PR_FALSE;
|
||||
|
||||
pfd->mFlags = 0; // all flags default to false
|
||||
|
||||
#ifdef DEBUG
|
||||
pfd->mVerticalAlign = 0xFF;
|
||||
pfd->mRelativePos = PRBool(0xFF);
|
||||
mFramesAllocated++;
|
||||
#endif
|
||||
*aResult = pfd;
|
||||
@ -782,7 +773,7 @@ nsLineLayout::NewPerFrameData(PerFrameData** aResult)
|
||||
PRBool
|
||||
nsLineLayout::CanPlaceFloaterNow() const
|
||||
{
|
||||
return mCanPlaceFloater;
|
||||
return GetFlag(LL_CANPLACEFLOATER);
|
||||
}
|
||||
|
||||
PRBool
|
||||
@ -794,7 +785,7 @@ nsLineLayout::LineIsEmpty() const
|
||||
PRBool
|
||||
nsLineLayout::LineIsBreakable() const
|
||||
{
|
||||
if ((0 != mTotalPlacedFrames) || mImpactedByFloaters) {
|
||||
if ((0 != mTotalPlacedFrames) || GetFlag(LL_IMPACTEDBYFLOATERS)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
@ -903,9 +894,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
nsHTMLReflowState reflowState(mPresContext, *psd->mReflowState, aFrame,
|
||||
availSize, reason);
|
||||
reflowState.mLineLayout = this;
|
||||
reflowState.isTopOfPage = mIsTopOfPage;
|
||||
mUnderstandsWhiteSpace = PR_FALSE;
|
||||
mTextStartsWithNBSP = PR_FALSE;
|
||||
reflowState.isTopOfPage = GetFlag(LL_ISTOPOFPAGE);
|
||||
SetFlag(LL_UNDERSTANDSNWHITESPACE, PR_FALSE);
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, PR_FALSE);
|
||||
mTextJustificationNumSpaces = 0;
|
||||
mTextJustificationNumLetters = 0;
|
||||
|
||||
// Stash copies of some of the computed state away for later
|
||||
// (vertical alignment, for example)
|
||||
@ -913,9 +906,9 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
pfd->mMargin = reflowState.mComputedMargin;
|
||||
pfd->mBorderPadding = reflowState.mComputedBorderPadding;
|
||||
pfd->mFrameType = reflowState.mFrameType;
|
||||
pfd->mRelativePos =
|
||||
reflowState.mStylePosition->mPosition == NS_STYLE_POSITION_RELATIVE;
|
||||
if (pfd->mRelativePos) {
|
||||
pfd->SetFlag(PFD_RELATIVEPOS,
|
||||
(reflowState.mStylePosition->mPosition == NS_STYLE_POSITION_RELATIVE));
|
||||
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
||||
pfd->mOffsets = reflowState.mComputedOffsets;
|
||||
}
|
||||
|
||||
@ -969,14 +962,18 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
nscoord ty = y - psd->mReflowState->mComputedBorderPadding.top;
|
||||
mSpaceManager->Translate(tx, ty);
|
||||
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsLetterFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
pfd->mIsNonWhitespaceTextFrame = PR_FALSE;
|
||||
pfd->mIsSticky = PR_FALSE;
|
||||
pfd->SetFlag(PFD_ISTEXTFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISLETTERFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISNONEMPTYTEXTFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISNONWHITESPACETEXTFRAME, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_FALSE);
|
||||
pfd->SetFlag(PFD_ISBULLET, PR_FALSE);
|
||||
|
||||
aFrame->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
||||
|
||||
pfd->mJustificationNumSpaces = mTextJustificationNumSpaces;
|
||||
pfd->mJustificationNumLetters = mTextJustificationNumLetters;
|
||||
|
||||
// XXX See if the frame is a placeholderFrame and if it is process
|
||||
// the floater.
|
||||
nsIAtom* frameType;
|
||||
@ -1000,7 +997,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
outOfFlowFrame->GetFrameType(&oofft);
|
||||
if (oofft) {
|
||||
if (oofft == nsLayoutAtoms::letterFrame) {
|
||||
mFirstLetterStyleOK = PR_FALSE;
|
||||
SetFlag(LL_FIRSTLETTERSTYLEOK, PR_FALSE);
|
||||
}
|
||||
NS_RELEASE(oofft);
|
||||
}
|
||||
@ -1009,11 +1006,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
}
|
||||
else if (frameType == nsLayoutAtoms::textFrame) {
|
||||
// Note non-empty text-frames for inline frame compatability hackery
|
||||
pfd->mIsTextFrame = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISTEXTFRAME, PR_TRUE);
|
||||
// XXX An empty text frame at the end of the line seems not
|
||||
// to have zero width.
|
||||
if (metrics.width) {
|
||||
pfd->mIsNonEmptyTextFrame = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISNONEMPTYTEXTFRAME, PR_TRUE);
|
||||
nsCOMPtr<nsIContent> content;
|
||||
nsresult result = pfd->mFrame->GetContent(getter_AddRefs(content));
|
||||
if ((NS_SUCCEEDED(result)) && content) {
|
||||
@ -1023,14 +1020,14 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
PRBool isWhitespace;
|
||||
result = textContent->IsOnlyWhitespace(&isWhitespace);
|
||||
if (NS_SUCCEEDED(result)) {
|
||||
pfd->mIsNonWhitespaceTextFrame = !isWhitespace;
|
||||
pfd->SetFlag(PFD_ISNONWHITESPACETEXTFRAME, !isWhitespace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (frameType == nsLayoutAtoms::letterFrame) {
|
||||
pfd->mIsLetterFrame = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISLETTERFRAME, PR_TRUE);
|
||||
}
|
||||
NS_RELEASE(frameType);
|
||||
}
|
||||
@ -1170,7 +1167,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||
else {
|
||||
PushFrame(aFrame);
|
||||
}
|
||||
mTextStartsWithNBSP = PR_FALSE; // reset for next time
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, PR_FALSE); // reset for next time
|
||||
|
||||
#ifdef REALLY_NOISY_REFLOW
|
||||
nsFrame::IndentBy(stdout, mSpanDepth);
|
||||
@ -1330,7 +1327,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
// There are no frames on the line or we are in the first word on
|
||||
// the line. If the line isn't impacted by a floater then the
|
||||
// current frame fits.
|
||||
if (!mImpactedByFloaters) {
|
||||
if (!GetFlag(LL_IMPACTEDBYFLOATERS)) {
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> not-safe and not-impacted fits: ");
|
||||
while (nsnull != psd) {
|
||||
@ -1341,28 +1338,28 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
#endif
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (mLastFloaterWasLetterFrame) {
|
||||
else if (GetFlag(LL_LASTFLOATERWASLETTERFRAME)) {
|
||||
// Another special case: see if the floater is a letter
|
||||
// frame. If it is, then allow the frame next to it to fit.
|
||||
if (pfd->mIsNonEmptyTextFrame) {
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
// This must be the first piece of non-empty text (because
|
||||
// aNotSafeToBreak is true) or its a piece of text that is
|
||||
// part of a larger word.
|
||||
pfd->mIsSticky = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
||||
}
|
||||
else if (pfd->mSpan) {
|
||||
PerFrameData* pf = pfd->mSpan->mFirstFrame;
|
||||
while (pf) {
|
||||
if (pf->mIsSticky) {
|
||||
if (pf->GetFlag(PFD_ISSTICKY)) {
|
||||
// If one of the spans children was sticky then the span
|
||||
// itself is sticky.
|
||||
pfd->mIsSticky = PR_TRUE;
|
||||
pfd->SetFlag(PFD_ISSTICKY, PR_TRUE);
|
||||
}
|
||||
pf = pf->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
if (pfd->mIsSticky) {
|
||||
if (pfd->GetFlag(PFD_ISSTICKY)) {
|
||||
#ifdef NOISY_CAN_PLACE_FRAME
|
||||
printf(" ==> last floater was letter frame && frame is sticky\n");
|
||||
#endif
|
||||
@ -1372,8 +1369,8 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
}
|
||||
|
||||
// If this is a piece of text inside a letter frame...
|
||||
if (pfd->mIsNonEmptyTextFrame) {
|
||||
if (psd->mFrame && psd->mFrame->mIsLetterFrame) {
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
if (psd->mFrame && psd->mFrame->GetFlag(PFD_ISLETTERFRAME)) {
|
||||
nsIFrame* prevInFlow;
|
||||
psd->mFrame->mFrame->GetPrevInFlow(&prevInFlow);
|
||||
if (prevInFlow) {
|
||||
@ -1387,7 +1384,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pfd->mIsLetterFrame) {
|
||||
else if (pfd->GetFlag(PFD_ISLETTERFRAME)) {
|
||||
// If this is the first continuation of the letter frame...
|
||||
nsIFrame* prevInFlow;
|
||||
pfd->mFrame->GetPrevInFlow(&prevInFlow);
|
||||
@ -1433,7 +1430,7 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
||||
// edge...Which means that whatever piece of text we just formatted
|
||||
// will be the piece that fits (the text frame logic knows to stop
|
||||
// when it runs out of room).
|
||||
if (pfd->mIsNonEmptyTextFrame && mTextStartsWithNBSP) {
|
||||
if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME) && GetFlag(LL_TEXTSTARTSWITHNBSP)) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -1467,9 +1464,9 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
||||
|
||||
// If the band was updated during the reflow of that frame then we
|
||||
// need to adjust any prior frames that were reflowed.
|
||||
if (mUpdatedBand && InBlockContext()) {
|
||||
if (GetFlag(LL_UPDATEDBAND) && InBlockContext()) {
|
||||
UpdateFrames();
|
||||
mUpdatedBand = PR_FALSE;
|
||||
SetFlag(LL_UPDATEDBAND, PR_FALSE);
|
||||
}
|
||||
|
||||
// Advance to next X coordinate
|
||||
@ -1478,8 +1475,8 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
||||
// If the frame is a not aware of white-space and it takes up some
|
||||
// width, disable leading white-space compression for the next frame
|
||||
// to be reflowed.
|
||||
if (!mUnderstandsWhiteSpace && pfd->mBounds.width) {
|
||||
mEndsInWhiteSpace = PR_FALSE;
|
||||
if ((!GetFlag(LL_UNDERSTANDSNWHITESPACE)) && pfd->mBounds.width) {
|
||||
SetFlag(LL_ENDSINWHITESPACE, PR_FALSE);
|
||||
}
|
||||
|
||||
// Count the number of frames on the line...
|
||||
@ -1487,7 +1484,7 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
||||
if (psd->mX != psd->mLeftEdge) {
|
||||
// As soon as a frame placed on the line advances an X coordinate
|
||||
// of any span we can no longer place a floater on the line.
|
||||
mCanPlaceFloater = PR_FALSE;
|
||||
SetFlag(LL_CANPLACEFLOATER, PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1505,14 +1502,10 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
||||
pfd->mMargin.SizeTo(0, 0, 0, 0);
|
||||
pfd->mBorderPadding.SizeTo(0, 0, 0, 0);
|
||||
pfd->mFrameType = NS_CSS_FRAME_TYPE_INLINE|NS_FRAME_REPLACED_ELEMENT;
|
||||
pfd->mRelativePos = PR_FALSE;
|
||||
pfd->mFlags = 0; // all flags default to false
|
||||
pfd->SetFlag(PFD_ISBULLET, PR_TRUE);
|
||||
pfd->mAscent = aMetrics.ascent;
|
||||
pfd->mDescent = aMetrics.descent;
|
||||
pfd->mIsTextFrame = PR_FALSE;
|
||||
pfd->mIsNonEmptyTextFrame = PR_FALSE;
|
||||
pfd->mIsNonWhitespaceTextFrame = PR_FALSE;
|
||||
pfd->mIsLetterFrame = PR_FALSE;
|
||||
pfd->mIsSticky = PR_FALSE;
|
||||
|
||||
// Note: y value will be updated during vertical alignment
|
||||
aFrame->GetRect(pfd->mBounds);
|
||||
@ -1857,7 +1850,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
||||
zeroEffectiveSpanBox = PR_TRUE;
|
||||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
while (nsnull != pfd) {
|
||||
if (preMode?pfd->mIsTextFrame:pfd->mIsNonWhitespaceTextFrame) {
|
||||
if (preMode?pfd->GetFlag(PFD_ISTEXTFRAME):pfd->GetFlag(PFD_ISNONWHITESPACETEXTFRAME)) {
|
||||
zeroEffectiveSpanBox = PR_FALSE;
|
||||
break;
|
||||
}
|
||||
@ -2154,7 +2147,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
||||
if (pfd->mVerticalAlign == VALIGN_OTHER) {
|
||||
// Text frames do not contribute to the min/max Y values for the
|
||||
// line (instead their parent frame's font-size contributes).
|
||||
if (!pfd->mIsTextFrame) {
|
||||
if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
nscoord yTop, yBottom;
|
||||
if (frameSpan) {
|
||||
// For spans that were are now placing, use their position
|
||||
@ -2212,7 +2205,7 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
||||
// BR) (NN4/IE5 quirk)
|
||||
PRBool applyMinLH = !(psd->mZeroEffectiveSpanBox); // (1) above
|
||||
PRBool isFirstLine = !mLineNumber; // if the line number is 0
|
||||
PRBool isLastLine = (!mLineBox->IsLineWrapped() && !mLineEndsInBR);
|
||||
PRBool isLastLine = (!mLineBox->IsLineWrapped() && !GetFlag(LL_LINEENDSINBR));
|
||||
//PRBool isLastLine = mBlockRS->mCurLine->IsLineWrapped();
|
||||
if (!applyMinLH && (isFirstLine || isLastLine)) {
|
||||
nsCOMPtr<nsIContent> blockContent;
|
||||
@ -2412,13 +2405,13 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
else if (!pfd->mIsTextFrame) {
|
||||
else if (!pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
// If we hit a frame on the end that's not text, then there is
|
||||
// no trailing whitespace to trim. Stop the search.
|
||||
*aDeltaWidth = 0;
|
||||
return PR_TRUE;
|
||||
}
|
||||
else if (pfd->mIsNonEmptyTextFrame) {
|
||||
else if (pfd->GetFlag(PFD_ISNONEMPTYTEXTFRAME)) {
|
||||
nscoord deltaWidth = 0;
|
||||
pfd->mFrame->TrimTrailingWhiteSpace(mPresContext,
|
||||
*mBlockReflowState->rendContext,
|
||||
@ -2432,6 +2425,10 @@ nsLineLayout::TrimTrailingWhiteSpaceIn(PerSpanData* psd,
|
||||
printf(" returned %d\n", deltaWidth);
|
||||
#endif
|
||||
if (deltaWidth) {
|
||||
if (pfd->mJustificationNumSpaces > 0) {
|
||||
pfd->mJustificationNumSpaces--;
|
||||
}
|
||||
|
||||
pfd->mBounds.width -= deltaWidth;
|
||||
pfd->mCombinedArea.width -= deltaWidth;
|
||||
if (0 == pfd->mBounds.width) {
|
||||
@ -2479,6 +2476,95 @@ nsLineLayout::TrimTrailingWhiteSpace()
|
||||
return 0 != deltaWidth;
|
||||
}
|
||||
|
||||
void
|
||||
nsLineLayout::ComputeJustificationWeights(PerSpanData* aPSD,
|
||||
PRInt32* aNumSpaces,
|
||||
PRInt32* aNumLetters)
|
||||
{
|
||||
NS_ASSERTION(aPSD, "null arg");
|
||||
NS_ASSERTION(aNumSpaces, "null arg");
|
||||
NS_ASSERTION(aNumLetters, "null arg");
|
||||
PRInt32 numSpaces = 0;
|
||||
PRInt32 numLetters = 0;
|
||||
|
||||
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
|
||||
nscoord dw = 0;
|
||||
|
||||
if (PR_TRUE == pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
numSpaces += pfd->mJustificationNumSpaces;
|
||||
numLetters += pfd->mJustificationNumLetters;
|
||||
}
|
||||
else if (pfd->mSpan != nsnull) {
|
||||
PRInt32 spanSpaces;
|
||||
PRInt32 spanLetters;
|
||||
|
||||
ComputeJustificationWeights(pfd->mSpan, &spanSpaces, &spanLetters);
|
||||
|
||||
numSpaces += spanSpaces;
|
||||
numLetters += spanLetters;
|
||||
}
|
||||
}
|
||||
|
||||
*aNumSpaces = numSpaces;
|
||||
*aNumLetters = numLetters;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState* aState)
|
||||
{
|
||||
NS_ASSERTION(aPSD, "null arg");
|
||||
NS_ASSERTION(aState, "null arg");
|
||||
|
||||
nscoord deltaX = 0;
|
||||
for (PerFrameData* pfd = aPSD->mFirstFrame; pfd != nsnull; pfd = pfd->mNext) {
|
||||
// Don't reposition bullets (and other frames that occur out of X-order?)
|
||||
if (!pfd->GetFlag(PFD_ISBULLET)) {
|
||||
nscoord dw = 0;
|
||||
|
||||
pfd->mBounds.x += deltaX;
|
||||
|
||||
if (PR_TRUE == pfd->GetFlag(PFD_ISTEXTFRAME)) {
|
||||
if (aState->mTotalWidthForSpaces > 0 &&
|
||||
aState->mTotalNumSpaces > 0 && // we divide by this value, so must be non-zero
|
||||
aState->mTotalNumLetters >0 // we divide by this value, so must be non-zero
|
||||
) {
|
||||
aState->mNumSpacesProcessed += pfd->mJustificationNumSpaces;
|
||||
|
||||
nscoord newAllocatedWidthForSpaces =
|
||||
(aState->mTotalWidthForSpaces*aState->mNumSpacesProcessed)
|
||||
/aState->mTotalNumSpaces;
|
||||
|
||||
dw += newAllocatedWidthForSpaces - aState->mWidthForSpacesProcessed;
|
||||
|
||||
aState->mWidthForSpacesProcessed = newAllocatedWidthForSpaces;
|
||||
}
|
||||
|
||||
if (aState->mTotalWidthForLetters > 0) {
|
||||
aState->mNumLettersProcessed += pfd->mJustificationNumLetters;
|
||||
|
||||
nscoord newAllocatedWidthForLetters =
|
||||
(aState->mTotalWidthForLetters*aState->mNumLettersProcessed)
|
||||
/aState->mTotalNumLetters;
|
||||
|
||||
dw += newAllocatedWidthForLetters - aState->mWidthForLettersProcessed;
|
||||
|
||||
aState->mWidthForLettersProcessed = newAllocatedWidthForLetters;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (nsnull != pfd->mSpan) {
|
||||
dw += ApplyFrameJustification(pfd->mSpan, aState);
|
||||
}
|
||||
}
|
||||
|
||||
pfd->mBounds.width += dw;
|
||||
deltaX += dw;
|
||||
pfd->mFrame->SetRect(mPresContext, pfd->mBounds);
|
||||
}
|
||||
}
|
||||
return deltaX;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
|
||||
PRBool aAllowJustify,
|
||||
@ -2525,7 +2611,18 @@ nsLineLayout::HorizontalAlignFrames(nsRect& aLineBounds,
|
||||
// frames in the line. If it is the last line then if the
|
||||
// direction is right-to-left then we right-align the frames.
|
||||
if (aAllowJustify) {
|
||||
break;
|
||||
if (!aShrinkWrapWidth) {
|
||||
PRInt32 numSpaces;
|
||||
PRInt32 numLetters;
|
||||
|
||||
ComputeJustificationWeights(psd, &numSpaces, &numLetters);
|
||||
|
||||
if (numSpaces > 0) {
|
||||
FrameJustificationState state = { numSpaces, numLetters, remainingWidth, 0, 0, 0, 0, 0 };
|
||||
|
||||
ApplyFrameJustification(psd, &state);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NS_STYLE_DIRECTION_RTL == psd->mDirection) {
|
||||
// right align the frames
|
||||
@ -2617,7 +2714,7 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea)
|
||||
nscoord y = pfd->mBounds.y;
|
||||
|
||||
// Adjust the origin of the frame
|
||||
if (pfd->mRelativePos) {
|
||||
if (pfd->GetFlag(PFD_RELATIVEPOS)) {
|
||||
nsIFrame* frame = pfd->mFrame;
|
||||
frame->GetOrigin(origin);
|
||||
// XXX what about right and bottom?
|
||||
|
@ -18,6 +18,8 @@
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Steve Clark <buster@netscape.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
*/
|
||||
#ifndef nsLineLayout_h___
|
||||
#define nsLineLayout_h___
|
||||
@ -32,7 +34,7 @@ class nsBlockReflowState;
|
||||
class nsPlaceholderFrame;
|
||||
struct nsStyleText;
|
||||
|
||||
#define NS_LINELAYOUT_NUM_FRAMES 10
|
||||
#define NS_LINELAYOUT_NUM_FRAMES 5
|
||||
#define NS_LINELAYOUT_NUM_SPANS 5
|
||||
|
||||
class nsLineLayout {
|
||||
@ -122,23 +124,69 @@ public:
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// Supporting methods and data for flags
|
||||
protected:
|
||||
#define LL_ENDSINWHITESPACE 0x00000001
|
||||
#define LL_UNDERSTANDSNWHITESPACE 0x00000002
|
||||
#define LL_TEXTSTARTSWITHNBSP 0x00000004
|
||||
#define LL_FIRSTLETTERSTYLEOK 0x00000008
|
||||
#define LL_ISTOPOFPAGE 0x00000010
|
||||
#define LL_UPDATEDBAND 0x00000020
|
||||
#define LL_IMPACTEDBYFLOATERS 0x00000040
|
||||
#define LL_LASTFLOATERWASLETTERFRAME 0x00000080
|
||||
#define LL_CANPLACEFLOATER 0x00000100
|
||||
#define LL_KNOWSTRICTMODE 0x00000200
|
||||
#define LL_INSTRICTMODE 0x00000400
|
||||
#define LL_LINEENDSINBR 0x00000800
|
||||
#define LL_LASTFLAG LL_LINEENDSINBR
|
||||
|
||||
PRUint16 mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=LL_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=LL_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// Support methods for white-space compression and word-wrapping
|
||||
// during line reflow
|
||||
|
||||
void SetEndsInWhiteSpace(PRBool aState) {
|
||||
mEndsInWhiteSpace = aState;
|
||||
SetFlag(LL_ENDSINWHITESPACE, aState);
|
||||
}
|
||||
|
||||
PRBool GetEndsInWhiteSpace() const {
|
||||
return mEndsInWhiteSpace;
|
||||
return GetFlag(LL_ENDSINWHITESPACE);
|
||||
}
|
||||
|
||||
void SetUnderstandsWhiteSpace(PRBool aSetting) {
|
||||
mUnderstandsWhiteSpace = aSetting;
|
||||
SetFlag(LL_UNDERSTANDSNWHITESPACE, aSetting);
|
||||
}
|
||||
|
||||
void SetTextJustificationWeights(PRInt32 aNumSpaces, PRInt32 aNumLetters) {
|
||||
mTextJustificationNumSpaces = aNumSpaces;
|
||||
mTextJustificationNumLetters = aNumLetters;
|
||||
}
|
||||
|
||||
|
||||
void SetTextStartsWithNBSP(PRBool aYes) {
|
||||
mTextStartsWithNBSP = aYes;
|
||||
SetFlag(LL_TEXTSTARTSWITHNBSP, aYes);
|
||||
}
|
||||
|
||||
void RecordWordFrame(nsIFrame* aWordFrame) {
|
||||
@ -163,9 +211,15 @@ public:
|
||||
|
||||
PRBool LineIsBreakable() const;
|
||||
|
||||
PRBool GetLineEndsInBR() const { return mLineEndsInBR; }
|
||||
PRBool GetLineEndsInBR() const
|
||||
{
|
||||
return GetFlag(LL_LINEENDSINBR);
|
||||
}
|
||||
|
||||
void SetLineEndsInBR(PRBool aOn) { mLineEndsInBR = aOn; }
|
||||
void SetLineEndsInBR(PRBool aOn)
|
||||
{
|
||||
SetFlag(LL_LINEENDSINBR, aOn);
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Inform the line-layout about the presence of a floating frame
|
||||
@ -176,11 +230,11 @@ public:
|
||||
//----------------------------------------
|
||||
|
||||
PRBool GetFirstLetterStyleOK() const {
|
||||
return mFirstLetterStyleOK;
|
||||
return GetFlag(LL_FIRSTLETTERSTYLEOK);
|
||||
}
|
||||
|
||||
void SetFirstLetterStyleOK(PRBool aSetting) {
|
||||
mFirstLetterStyleOK = aSetting;
|
||||
SetFlag(LL_FIRSTLETTERSTYLEOK, aSetting);
|
||||
}
|
||||
|
||||
void SetFirstLetterFrame(nsIFrame* aFrame) {
|
||||
@ -233,19 +287,11 @@ protected:
|
||||
nsIFrame* mFirstLetterFrame;
|
||||
PRInt32 mLineNumber;
|
||||
PRInt32 mColumn;
|
||||
PRInt32 mTextJustificationNumSpaces;
|
||||
PRInt32 mTextJustificationNumLetters;
|
||||
|
||||
nsLineBox* mLineBox;
|
||||
PRPackedBool mEndsInWhiteSpace;
|
||||
PRPackedBool mUnderstandsWhiteSpace;
|
||||
PRPackedBool mTextStartsWithNBSP;
|
||||
PRPackedBool mFirstLetterStyleOK;
|
||||
PRPackedBool mIsTopOfPage;
|
||||
PRPackedBool mUpdatedBand;
|
||||
PRPackedBool mImpactedByFloaters;
|
||||
PRPackedBool mLastFloaterWasLetterFrame;
|
||||
PRPackedBool mCanPlaceFloater;
|
||||
PRPackedBool mKnowStrictMode;
|
||||
PRPackedBool mInStrictMode;
|
||||
PRPackedBool mLineEndsInBR;
|
||||
|
||||
PRUint8 mPlacedFloaters;
|
||||
PRInt32 mTotalPlacedFrames;
|
||||
nsVoidArray mWordFrames;
|
||||
@ -294,15 +340,47 @@ protected:
|
||||
nsMargin mMargin;
|
||||
nsMargin mBorderPadding;
|
||||
nsMargin mOffsets;
|
||||
PRPackedBool mRelativePos;
|
||||
|
||||
// Other state we use
|
||||
PRUint8 mVerticalAlign;
|
||||
PRPackedBool mIsTextFrame;
|
||||
PRPackedBool mIsNonEmptyTextFrame;
|
||||
PRPackedBool mIsNonWhitespaceTextFrame;
|
||||
PRPackedBool mIsLetterFrame;
|
||||
PRPackedBool mIsSticky;
|
||||
|
||||
// state for text justification
|
||||
PRInt32 mJustificationNumSpaces;
|
||||
PRInt32 mJustificationNumLetters;
|
||||
|
||||
|
||||
// PerFrameData flags
|
||||
#define PFD_RELATIVEPOS 0x00000001
|
||||
#define PFD_ISTEXTFRAME 0x00000002
|
||||
#define PFD_ISNONEMPTYTEXTFRAME 0x00000004
|
||||
#define PFD_ISNONWHITESPACETEXTFRAME 0x00000008
|
||||
#define PFD_ISLETTERFRAME 0x00000010
|
||||
#define PFD_ISSTICKY 0x00000020
|
||||
#define PFD_ISBULLET 0x00000040
|
||||
#define PFD_LASTFLAG PFD_ISBULLET
|
||||
|
||||
PRPackedBool mFlags;
|
||||
|
||||
void SetFlag(PRUint32 aFlag, PRBool aValue)
|
||||
{
|
||||
NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
|
||||
NS_ASSERTION(aValue==PR_FALSE || aValue==PR_TRUE, "bad value");
|
||||
if (aValue) { // set flag
|
||||
mFlags |= aFlag;
|
||||
}
|
||||
else { // unset flag
|
||||
mFlags &= ~aFlag;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool GetFlag(PRUint32 aFlag) const
|
||||
{
|
||||
NS_ASSERTION(aFlag<=PFD_LASTFLAG, "bad flag");
|
||||
PRBool result = (mFlags & aFlag);
|
||||
if (result) return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
PerFrameData* Last() {
|
||||
PerFrameData* pfd = this;
|
||||
@ -409,6 +487,22 @@ protected:
|
||||
|
||||
PRBool TrimTrailingWhiteSpaceIn(PerSpanData* psd, nscoord* aDeltaWidth);
|
||||
|
||||
|
||||
void ComputeJustificationWeights(PerSpanData* psd, PRInt32* numSpaces, PRInt32* numLetters);
|
||||
|
||||
struct FrameJustificationState {
|
||||
PRInt32 mTotalNumSpaces;
|
||||
PRInt32 mTotalNumLetters;
|
||||
nscoord mTotalWidthForSpaces;
|
||||
nscoord mTotalWidthForLetters;
|
||||
PRInt32 mNumSpacesProcessed;
|
||||
PRInt32 mNumLettersProcessed;
|
||||
nscoord mWidthForSpacesProcessed;
|
||||
nscoord mWidthForLettersProcessed;
|
||||
};
|
||||
nscoord ApplyFrameJustification(PerSpanData* aPSD, FrameJustificationState* aState);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
void DumpPerSpanData(PerSpanData* psd, PRInt32 aIndent);
|
||||
#endif
|
||||
|
@ -3874,6 +3874,9 @@ FindTopFrame(nsIFrame* aRoot)
|
||||
PRBool
|
||||
PresShell::VerifyIncrementalReflow()
|
||||
{
|
||||
if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
|
||||
printf("Building Verification Tree...\n");
|
||||
}
|
||||
// All the stuff we are creating that needs releasing
|
||||
nsIPresContext* cx;
|
||||
nsIViewManager* vm;
|
||||
@ -3976,6 +3979,9 @@ PresShell::VerifyIncrementalReflow()
|
||||
vm->SetViewObserver((nsIViewObserver *)((PresShell*)sh));
|
||||
sh->InitialReflow(r.width, r.height);
|
||||
sh->SetVerifyReflowEnable(PR_TRUE); // turn on verify reflow again now that we're done reflowing the test frame tree
|
||||
if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
|
||||
printf("Verification Tree built, comparing...\n");
|
||||
}
|
||||
|
||||
// Now that the document has been reflowed, use its frame tree to
|
||||
// compare against our frame tree.
|
||||
@ -3999,15 +4005,15 @@ PresShell::VerifyIncrementalReflow()
|
||||
}
|
||||
}
|
||||
|
||||
// printf("Incremental reflow doomed view tree:\n");
|
||||
// view->List(stdout, 1);
|
||||
// view->SetVisibility(nsViewVisibility_kHide);
|
||||
cx->Stop();
|
||||
cx->SetContainer(nsnull);
|
||||
NS_RELEASE(cx);
|
||||
sh->EndObservingDocument();
|
||||
NS_RELEASE(sh);
|
||||
NS_RELEASE(vm);
|
||||
if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) {
|
||||
printf("Finished Verifying Reflow...\n");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Robert O'Callahan <roc+moz@cs.cmu.edu>
|
||||
*/
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsHTMLParts.h"
|
||||
@ -458,9 +459,10 @@ public:
|
||||
nscoord mAveCharWidth;
|
||||
PRBool mJustifying;
|
||||
PRBool mPreformatted;
|
||||
PRIntn mNumSpaces;
|
||||
PRInt32 mNumSpacesToRender;
|
||||
PRInt32 mNumSpacesToMeasure;
|
||||
nscoord mExtraSpacePerSpace;
|
||||
nscoord mRemainingExtraSpace;
|
||||
PRInt32 mNumSpacesReceivingExtraJot;
|
||||
|
||||
TextStyle(nsIPresContext* aPresContext,
|
||||
nsIRenderingContext& aRenderingContext,
|
||||
@ -521,20 +523,25 @@ public:
|
||||
|
||||
// Get the word and letter spacing
|
||||
mWordSpacing = 0;
|
||||
mLetterSpacing = 0;
|
||||
PRIntn unit = mText->mWordSpacing.GetUnit();
|
||||
if (eStyleUnit_Coord == unit) {
|
||||
mWordSpacing = mText->mWordSpacing.GetCoordValue();
|
||||
}
|
||||
|
||||
mLetterSpacing = 0;
|
||||
unit = mText->mLetterSpacing.GetUnit();
|
||||
if (eStyleUnit_Coord == unit) {
|
||||
mLetterSpacing = mText->mLetterSpacing.GetCoordValue();
|
||||
}
|
||||
mNumSpaces = 0;
|
||||
mRemainingExtraSpace = 0;
|
||||
mNumSpacesToRender = 0;
|
||||
mNumSpacesToMeasure = 0;
|
||||
mNumSpacesReceivingExtraJot = 0;
|
||||
mExtraSpacePerSpace = 0;
|
||||
mPreformatted = (NS_STYLE_WHITESPACE_PRE == mText->mWhiteSpace) ||
|
||||
(NS_STYLE_WHITESPACE_MOZ_PRE_WRAP == mText->mWhiteSpace);
|
||||
|
||||
mJustifying = (NS_STYLE_TEXT_ALIGN_JUSTIFY == mText->mTextAlign) &&
|
||||
!mPreformatted;
|
||||
}
|
||||
|
||||
~TextStyle() {
|
||||
@ -590,6 +597,9 @@ public:
|
||||
nsAutoIndexBuffer* aIndexBuffer,
|
||||
nsAutoTextBuffer* aTextBuffer,
|
||||
PRInt32* aTextLen);
|
||||
void ComputeExtraJustificationSpacing(nsIRenderingContext& aRenderingContext,
|
||||
TextStyle& aTextStyle,
|
||||
PRUnichar* aBuffer, PRInt32 aLength, PRInt32 aNumSpaces);
|
||||
|
||||
void PaintTextDecorations(nsIRenderingContext& aRenderingContext,
|
||||
nsIStyleContext* aStyleContext,
|
||||
@ -1192,7 +1202,8 @@ nsTextFrame::Paint(nsIPresContext* aPresContext,
|
||||
sc->GetStyleData(eStyleStruct_Display);
|
||||
if (disp->IsVisible()) {
|
||||
TextStyle ts(aPresContext, aRenderingContext, mStyleContext);
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing)) {
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing)
|
||||
|| ts.mJustifying) {
|
||||
PaintTextSlowly(aPresContext, aRenderingContext, sc, ts, 0, 0);
|
||||
}
|
||||
else {
|
||||
@ -1261,7 +1272,9 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
PRBool isWhitespace, wasTransformed;
|
||||
PRInt32 wordLen, contentLen;
|
||||
aTX.GetNextWord(PR_FALSE, &wordLen, &contentLen, &isWhitespace, &wasTransformed);
|
||||
NS_ASSERTION(isWhitespace, "mState and content are out of sync");
|
||||
// we trip this assertion in bug 31053, but I think it's unnecessary
|
||||
//NS_ASSERTION(isWhitespace, "mState and content are out of sync");
|
||||
|
||||
if (isWhitespace) {
|
||||
if (nsnull != indexp) {
|
||||
// Point mapping indicies at the same content index since
|
||||
@ -1301,7 +1314,6 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
}
|
||||
inWord = PR_FALSE;
|
||||
if (isWhitespace) {
|
||||
numSpaces++;
|
||||
if ('\t' == bp[0]) {
|
||||
PRInt32 spaces = 8 - (7 & column);
|
||||
PRUnichar* tp = bp;
|
||||
@ -1339,20 +1351,30 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
}
|
||||
}
|
||||
}
|
||||
numSpaces += wordLen;
|
||||
}
|
||||
else {
|
||||
PRInt32 i;
|
||||
if (nsnull != indexp) {
|
||||
// Point mapping indicies at each content index in the word
|
||||
PRInt32 i = contentLen;
|
||||
i = contentLen;
|
||||
while (--i >= 0) {
|
||||
*indexp++ = strInx++;
|
||||
}
|
||||
}
|
||||
// Nonbreaking spaces count as spaces, not letters
|
||||
PRUnichar* tp = bp;
|
||||
i = wordLen;
|
||||
while (--i >= 0) {
|
||||
if (*tp++ == ' ') {
|
||||
numSpaces++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Grow the buffer before we run out of room. The only time this
|
||||
// happens is because of tab expansion.
|
||||
if (dstOffset + wordLen > aTextBuffer->mBufferLen) {
|
||||
if (aTextBuffer != nsnull && dstOffset + wordLen > aTextBuffer->mBufferLen) {
|
||||
nsresult rv = aTextBuffer->GrowBy(wordLen);
|
||||
if (NS_FAILED(rv)) {
|
||||
break;
|
||||
@ -1362,8 +1384,10 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
column += wordLen;
|
||||
textLength += wordLen;
|
||||
n -= contentLen;
|
||||
nsCRT::memcpy(aTextBuffer->mBuffer + dstOffset, bp,
|
||||
sizeof(PRUnichar)*wordLen);
|
||||
if (aTextBuffer != nsnull) {
|
||||
nsCRT::memcpy(aTextBuffer->mBuffer + dstOffset, bp,
|
||||
sizeof(PRUnichar)*wordLen);
|
||||
}
|
||||
dstOffset += wordLen;
|
||||
}
|
||||
|
||||
@ -1372,19 +1396,24 @@ nsTextFrame::PrepareUnicodeText(nsTextTransformer& aTX,
|
||||
NS_ASSERTION(indexp <= aIndexBuffer->mBuffer + aIndexBuffer->mBufferLen,
|
||||
"yikes - we just overwrote memory");
|
||||
}
|
||||
NS_ASSERTION(dstOffset <= aTextBuffer->mBufferLen,
|
||||
"yikes - we just overwrote memory");
|
||||
if (aTextBuffer) {
|
||||
NS_ASSERTION(dstOffset <= aTextBuffer->mBufferLen,
|
||||
"yikes - we just overwrote memory");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Remove trailing whitespace if it was trimmed after reflow
|
||||
if (TEXT_TRIMMED_WS & mState) {
|
||||
NS_ASSERTION(aTextBuffer != nsnull,
|
||||
"Nonexistent text buffer should only occur during reflow, i.e. before whitespace is trimmed");
|
||||
if (--dstOffset >= 0) {
|
||||
PRUnichar ch = aTextBuffer->mBuffer[dstOffset];
|
||||
if (XP_IS_SPACE(ch)) {
|
||||
textLength--;
|
||||
numSpaces--;
|
||||
}
|
||||
}
|
||||
numSpaces--;
|
||||
}
|
||||
|
||||
if (aIndexBuffer) {
|
||||
@ -1716,6 +1745,7 @@ nsTextFrame::PaintUnicodeText(nsIPresContext* aPresContext,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
// no need to worry about justification, that's always on the slow path
|
||||
PrepareUnicodeText(tx, (displaySelection ? &indexBuffer : nsnull),
|
||||
&paintBuffer, &textLength);
|
||||
|
||||
@ -1833,7 +1863,7 @@ nsTextFrame::GetPositionSlowly(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
TextStyle ts(aPresContext, *aRendContext, mStyleContext);
|
||||
if (!ts.mSmallCaps && !ts.mWordSpacing && !ts.mLetterSpacing) {
|
||||
if (!ts.mSmallCaps && !ts.mWordSpacing && !ts.mLetterSpacing && !ts.mJustifying) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
nsIView * view;
|
||||
@ -1861,12 +1891,16 @@ nsTextFrame::GetPositionSlowly(nsIPresContext* aPresContext,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
PRInt32 numSpaces;
|
||||
|
||||
numSpaces = PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
if (textLength <= 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
//IF STYLE SAYS TO SELCT TO END OF FRAME HERE...
|
||||
ComputeExtraJustificationSpacing(*aRendContext, ts, paintBuffer.mBuffer, textLength, numSpaces);
|
||||
|
||||
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
|
||||
nsCOMPtr<nsIPref> prefs;
|
||||
PRInt32 prefInt = 0;
|
||||
rv = nsServiceManager::GetService(kPrefCID,
|
||||
@ -1929,7 +1963,7 @@ nsTextFrame::RenderString(nsIRenderingContext& aRenderingContext,
|
||||
PRUnichar* bp = bp0;
|
||||
|
||||
PRBool spacing = (0 != aTextStyle.mLetterSpacing) ||
|
||||
(0 != aTextStyle.mWordSpacing);
|
||||
(0 != aTextStyle.mWordSpacing) || aTextStyle.mJustifying;
|
||||
nscoord spacingMem[TEXT_BUF_SIZE];
|
||||
PRIntn* sp0 = spacingMem;
|
||||
if (spacing && (aLength > TEXT_BUF_SIZE)) {
|
||||
@ -1977,12 +2011,12 @@ nsTextFrame::RenderString(nsIRenderingContext& aRenderingContext,
|
||||
else if (ch == ' ') {
|
||||
nextFont = aTextStyle.mNormalFont;
|
||||
nextY = aY;
|
||||
glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing;
|
||||
nscoord extra = aTextStyle.mExtraSpacePerSpace;
|
||||
if (--aTextStyle.mNumSpaces == 0) {
|
||||
extra += aTextStyle.mRemainingExtraSpace;
|
||||
glyphWidth = aTextStyle.mSpaceWidth + aTextStyle.mWordSpacing
|
||||
+ aTextStyle.mExtraSpacePerSpace;
|
||||
if ((PRUint32)--aTextStyle.mNumSpacesToRender <
|
||||
(PRUint32)aTextStyle.mNumSpacesReceivingExtraJot) {
|
||||
glyphWidth++;
|
||||
}
|
||||
glyphWidth += extra;
|
||||
}
|
||||
else {
|
||||
if (lastFont != aTextStyle.mNormalFont) {
|
||||
@ -2096,12 +2130,12 @@ nsTextFrame::GetWidthOrLength(nsIRenderingContext& aRenderingContext,
|
||||
glyphWidth = charWidth + aStyle.mLetterSpacing;
|
||||
}
|
||||
else if (ch == ' ') {
|
||||
glyphWidth = aStyle.mSpaceWidth + aStyle.mWordSpacing;
|
||||
nscoord extra = aStyle.mExtraSpacePerSpace;
|
||||
if (--aStyle.mNumSpaces == 0) {
|
||||
extra += aStyle.mRemainingExtraSpace;
|
||||
glyphWidth = aStyle.mSpaceWidth + aStyle.mWordSpacing
|
||||
+ aStyle.mExtraSpacePerSpace;
|
||||
if ((PRUint32)--aStyle.mNumSpacesToMeasure
|
||||
< (PRUint32)aStyle.mNumSpacesReceivingExtraJot) {
|
||||
glyphWidth++;
|
||||
}
|
||||
glyphWidth += extra;
|
||||
}
|
||||
else {
|
||||
if (lastFont != aStyle.mNormalFont) {
|
||||
@ -2147,6 +2181,45 @@ nsTextFrame::GetLengthSlowly(nsIRenderingContext& aRenderingContext,
|
||||
return GetWidthOrLength(aRenderingContext,aStyle,aBuffer,aLength,&aWidth,PR_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
nsTextFrame::ComputeExtraJustificationSpacing(nsIRenderingContext& aRenderingContext,
|
||||
TextStyle& aTextStyle,
|
||||
PRUnichar* aBuffer, PRInt32 aLength,
|
||||
PRInt32 aNumSpaces)
|
||||
{
|
||||
if (aTextStyle.mJustifying) {
|
||||
nscoord trueWidth;
|
||||
|
||||
// OK, so this is a bit ugly. The problem is that to get the right margin
|
||||
// nice and clean, we have to apply a little extra space to *some* of the
|
||||
// spaces. It has to be the same ones every time or things will go haywire.
|
||||
// This implies that the GetWidthOrLength and RenderString functions depend
|
||||
// on a little bit of secret state: which part of the prepared text they are
|
||||
// looking at. It turns out that they get called in a regular way: they look
|
||||
// at the text from the beginning to the end. So we just count which spaces
|
||||
// we're up to, for each context.
|
||||
// This is not a great solution, but a perfect solution requires much more
|
||||
// widespread changes, to explicitly annotate all the transformed text fragments
|
||||
// that are passed around with their position in the transformed text
|
||||
// for the entire frame.
|
||||
aTextStyle.mNumSpacesToMeasure = 0;
|
||||
aTextStyle.mExtraSpacePerSpace = 0;
|
||||
aTextStyle.mNumSpacesReceivingExtraJot = 0;
|
||||
|
||||
GetWidth(aRenderingContext, aTextStyle, aBuffer, aLength, &trueWidth);
|
||||
|
||||
aTextStyle.mNumSpacesToMeasure = aNumSpaces;
|
||||
aTextStyle.mNumSpacesToRender = aNumSpaces;
|
||||
|
||||
nscoord extraSpace = mRect.width - trueWidth;
|
||||
|
||||
if (extraSpace > 0 && aNumSpaces > 0) {
|
||||
aTextStyle.mExtraSpacePerSpace = extraSpace/aNumSpaces;
|
||||
aTextStyle.mNumSpacesReceivingExtraJot =
|
||||
extraSpace - aTextStyle.mExtraSpacePerSpace*aNumSpaces;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
|
||||
@ -2173,10 +2246,11 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
|
||||
nsCOMPtr<nsILineBreaker> lb;
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
aTextStyle.mNumSpaces = PrepareUnicodeText(tx,
|
||||
(displaySelection
|
||||
? &indexBuffer : nsnull),
|
||||
&paintBuffer, &textLength);
|
||||
PRInt32 numSpaces;
|
||||
|
||||
numSpaces = PrepareUnicodeText(tx, (displaySelection ? &indexBuffer : nsnull),
|
||||
&paintBuffer, &textLength);
|
||||
|
||||
|
||||
PRInt32* ip = indexBuffer.mBuffer;
|
||||
PRUnichar* text = paintBuffer.mBuffer;
|
||||
@ -2185,6 +2259,7 @@ nsTextFrame::PaintTextSlowly(nsIPresContext* aPresContext,
|
||||
GetFrameState(&frameState);
|
||||
isSelected = (frameState & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT;
|
||||
if (0 != textLength) {
|
||||
ComputeExtraJustificationSpacing(aRenderingContext, aTextStyle, text, textLength, numSpaces);
|
||||
if (!displaySelection || !isSelected) {
|
||||
// When there is no selection showing, use the fastest and
|
||||
// simplest rendering approach
|
||||
@ -2550,8 +2625,7 @@ nsTextFrame::GetPosition(nsIPresContext* aCX,
|
||||
rv = shell->CreateRenderingContext(this, getter_AddRefs(acx));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
TextStyle ts(aCX, *acx, mStyleContext);
|
||||
if (ts.mSmallCaps || ts.mWordSpacing || ts.mLetterSpacing) {
|
||||
|
||||
if (ts.mSmallCaps || ts.mWordSpacing || ts.mLetterSpacing || ts.mJustifying) {
|
||||
nsresult result = GetPositionSlowly(aCX, acx, aPoint, aNewContent,
|
||||
aContentOffset);
|
||||
aContentOffsetEnd = aContentOffset;
|
||||
@ -2582,6 +2656,7 @@ nsTextFrame::GetPosition(nsIPresContext* aCX,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
// no need to worry about justification, that's always on the slow path
|
||||
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
|
||||
if (textLength <=0) {
|
||||
@ -2593,7 +2668,7 @@ nsTextFrame::GetPosition(nsIPresContext* aCX,
|
||||
nsIView * view;
|
||||
GetOffsetFromView(aCX, origin, &view);
|
||||
|
||||
//IF SYLE SAYS TO SELCT TO END OF FRAME HERE...
|
||||
//IF STYLE SAYS TO SELECT TO END OF FRAME HERE...
|
||||
nsCOMPtr<nsIPref> prefs;
|
||||
PRInt32 prefInt = 0;
|
||||
rv = nsServiceManager::GetService(kPrefCID,
|
||||
@ -2880,7 +2955,12 @@ nsTextFrame::GetPointFromOffset(nsIPresContext* aPresContext,
|
||||
doc->GetLineBreaker(getter_AddRefs(lb));
|
||||
nsTextTransformer tx(lb, nsnull);
|
||||
PRInt32 textLength;
|
||||
PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
PRInt32 numSpaces;
|
||||
|
||||
numSpaces = PrepareUnicodeText(tx, &indexBuffer, &paintBuffer, &textLength);
|
||||
|
||||
ComputeExtraJustificationSpacing(*inRendContext, ts, paintBuffer.mBuffer, textLength, numSpaces);
|
||||
|
||||
|
||||
PRInt32* ip = indexBuffer.mBuffer;
|
||||
if (inOffset > mContentLength){
|
||||
@ -2889,7 +2969,7 @@ nsTextFrame::GetPointFromOffset(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
nscoord width = mRect.width;
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing))
|
||||
if (ts.mSmallCaps || (0 != ts.mWordSpacing) || (0 != ts.mLetterSpacing) || ts.mJustifying)
|
||||
{
|
||||
GetWidth(*inRendContext, ts,
|
||||
paintBuffer.mBuffer, ip[inOffset]-mContentOffset,
|
||||
@ -2907,7 +2987,8 @@ nsTextFrame::GetPointFromOffset(nsIPresContext* aPresContext,
|
||||
// to the total width, so the caret appears
|
||||
// in the proper place!
|
||||
//
|
||||
width += ts.mSpaceWidth;
|
||||
// NOTE: the trailing whitespace includes the word spacing!!
|
||||
width += ts.mSpaceWidth + ts.mWordSpacing;
|
||||
}
|
||||
|
||||
outPoint->x = width;
|
||||
@ -3502,6 +3583,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
#ifdef _WIN32
|
||||
PRBool measureTextRuns = !aTextData.mComputeMaxWordWidth && !aTs.mPreformatted &&
|
||||
!aTs.mSmallCaps && !aTs.mWordSpacing && !aTs.mLetterSpacing;
|
||||
// Don't measure text runs with letter spacing active, it doesn't work
|
||||
#else
|
||||
PRBool measureTextRuns = PR_FALSE;
|
||||
#endif
|
||||
@ -3579,10 +3661,17 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
mState |= TEXT_SKIP_LEADING_WS;
|
||||
continue;
|
||||
}
|
||||
|
||||
// NOTE: Even if the textRun absorbs the whitespace below, we still
|
||||
// want to remember that we're breakable.
|
||||
aTextData.mIsBreakable = PR_TRUE;
|
||||
aTextData.mFirstLetterOK = PR_FALSE;
|
||||
|
||||
if ('\t' == firstChar) {
|
||||
// Expand tabs to the proper width
|
||||
wordLen = 8 - (7 & column);
|
||||
width = aTs.mSpaceWidth * wordLen;
|
||||
// Apply word spacing to every space derived from a tab
|
||||
width = (aTs.mSpaceWidth + aTs.mWordSpacing)*wordLen;
|
||||
|
||||
// Because we have to expand the tab when rendering consider that
|
||||
// a transformation of the text
|
||||
@ -3594,10 +3683,9 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
width = (wordLen * aTs.mSpaceWidth) + aTs.mWordSpacing;// XXX simplistic
|
||||
// Apply word spacing to every space, if there's more than one
|
||||
width = wordLen*(aTs.mWordSpacing + aTs.mSpaceWidth);// XXX simplistic
|
||||
}
|
||||
aTextData.mIsBreakable = PR_TRUE;
|
||||
aTextData.mFirstLetterOK = PR_FALSE;
|
||||
|
||||
if (aTextData.mMeasureText) {
|
||||
// See if there is room for the text
|
||||
@ -3612,7 +3700,6 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
endsInWhitespace = PR_TRUE;
|
||||
prevOffset = aTextData.mOffset;
|
||||
aTextData.mOffset += contentLen;
|
||||
|
||||
} else {
|
||||
// See if the first thing in the section of text is a
|
||||
// non-breaking space (html nbsp entity). If it is then make
|
||||
@ -3704,6 +3791,7 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
MeasureTextRun:
|
||||
#ifdef _WIN32
|
||||
PRInt32 numCharsFit;
|
||||
// These calls can return numCharsFit not positioned at a break in the textRun. Beware.
|
||||
if (aTx.TransformedTextIsAscii()) {
|
||||
aReflowState.rendContext->GetWidth((char*)aTx.GetWordBuffer(), textRun.mTotalNumChars,
|
||||
maxWidth - aTextData.mX,
|
||||
@ -3722,22 +3810,43 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
}
|
||||
|
||||
// Find the index of the last segment that fit
|
||||
PRInt32 lastSegment = textRun.mNumSegments - 1;
|
||||
if (numCharsFit != textRun.mTotalNumChars) {
|
||||
PRInt32 lastSegment;
|
||||
if (numCharsFit == textRun.mTotalNumChars) { // fast path, normal case
|
||||
lastSegment = textRun.mNumSegments - 1;
|
||||
} else {
|
||||
for (lastSegment = 0; textRun.mBreaks[lastSegment] < numCharsFit; lastSegment++) ;
|
||||
NS_ASSERTION(lastSegment < textRun.mNumSegments, "failed to find segment");
|
||||
// now we have textRun.mBreaks[lastSegment] >= numCharsFit
|
||||
/* O'Callahan XXX: This snippet together with the snippet below prevents mail from loading
|
||||
Justification seems to work just fine without these changes.
|
||||
We get into trouble in a case where lastSegment gets set to -1
|
||||
|
||||
if (textRun.mBreaks[lastSegment] > numCharsFit) {
|
||||
// NOTE: this segment did not actually fit!
|
||||
lastSegment--;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/* O'Callahan XXX: This snippet together with the snippet above prevents mail from loading
|
||||
|
||||
if (lastSegment < 0) {
|
||||
// no segments fit
|
||||
break;
|
||||
} else */
|
||||
if (lastSegment == 0) {
|
||||
// Only one segment fit
|
||||
prevColumn = column;
|
||||
prevOffset = aTextData.mOffset;
|
||||
|
||||
} else {
|
||||
// The previous state is for the next to last word
|
||||
prevColumn = textRun.mBreaks[lastSegment - 1];
|
||||
prevOffset = textRun.mSegments[lastSegment - 1].ContentLen();
|
||||
// NOTE: The textRun data are relative to the last updated column and offset!
|
||||
prevColumn = column + textRun.mBreaks[lastSegment - 1];
|
||||
prevOffset = aTextData.mOffset + textRun.mSegments[lastSegment - 1].ContentLen();
|
||||
}
|
||||
|
||||
aTextData.mX += width;
|
||||
column += numCharsFit;
|
||||
aTextData.mOffset += textRun.mSegments[lastSegment].ContentLen();
|
||||
@ -3775,7 +3884,8 @@ nsTextFrame::MeasureText(nsIPresContext* aPresContext,
|
||||
aTextData.mX = mRect.width;
|
||||
if (mState & TEXT_TRIMMED_WS) {
|
||||
// Add back in the width of a space since it was trimmed away last time
|
||||
aTextData.mX += aTs.mSpaceWidth;
|
||||
// NOTE: Trailing whitespace includes word spacing!
|
||||
aTextData.mX += aTs.mSpaceWidth + aTs.mWordSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4056,19 +4166,22 @@ nsTextFrame::Reflow(nsIPresContext* aPresContext,
|
||||
// current frame width -or-
|
||||
// we're not wrapping text and we're at the same column as before (this is
|
||||
// an issue for preformatted tabbed text only)
|
||||
// - AND we aren't justified (in which case the frame width has already been tweaked and can't be used)
|
||||
if ((eReflowReason_Resize == aReflowState.reason) &&
|
||||
(0 == (mState & NS_FRAME_IS_DIRTY))) {
|
||||
|
||||
nscoord realWidth = mRect.width;
|
||||
if (mState & TEXT_TRIMMED_WS) {
|
||||
realWidth += ts.mSpaceWidth;
|
||||
// NOTE: Trailing whitespace includes word spacing!
|
||||
realWidth += ts.mSpaceWidth + ts.mWordSpacing;
|
||||
}
|
||||
if (!mNextInFlow &&
|
||||
(mState & TEXT_OPTIMIZE_RESIZE) &&
|
||||
!aMetrics.maxElementSize &&
|
||||
(lastTimeWeSkippedLeadingWS == skipWhitespace) &&
|
||||
((wrapping && (maxWidth >= realWidth)) ||
|
||||
(!wrapping && (prevColumn == column)))) {
|
||||
(!wrapping && (prevColumn == column))) &&
|
||||
!ts.mJustifying) {
|
||||
// We can skip measuring of text and use the value from our
|
||||
// previous reflow
|
||||
measureText = PR_FALSE;
|
||||
@ -4120,6 +4233,23 @@ nsTextFrame::Reflow(nsIPresContext* aPresContext,
|
||||
mContentOffset = startingOffset;
|
||||
mContentLength = textData.mOffset - startingOffset;
|
||||
|
||||
// Compute space and letter counts for justification, if required
|
||||
if (ts.mJustifying) {
|
||||
PRInt32 numSpaces;
|
||||
PRInt32 textLength;
|
||||
|
||||
// This will include a space for trailing whitespace, if any is present.
|
||||
// This is corrected for in nsLineLayout::TrimWhiteSpaceIn.
|
||||
|
||||
// This work could be done in MeasureText, but it's complex to do accurately
|
||||
// there because of the need to repair counts when wrapped words are backed out.
|
||||
// So I do it via PrepareUnicodeText ... a little slower perhaps, but a lot saner,
|
||||
// and it localizes the counting logic to one place.
|
||||
numSpaces = PrepareUnicodeText(tx, nsnull, nsnull, &textLength);
|
||||
lineLayout.SetTextJustificationWeights(numSpaces, textLength - numSpaces);
|
||||
}
|
||||
|
||||
|
||||
#ifdef MOZ_MATHML
|
||||
// Simple minded code to also return the bounding metrics if the caller wants it...
|
||||
// More consolidation is needed -- a better approach is to follow what is done by
|
||||
@ -4226,6 +4356,11 @@ nsTextFrame::TrimTrailingWhiteSpace(nsIPresContext* aPresContext,
|
||||
mStyleContext->GetStyleData(eStyleStruct_Font);
|
||||
aRC.SetFont(fontStyle->mFont);
|
||||
aRC.GetWidth(' ', dw);
|
||||
// NOTE: Trailing whitespace includes word spacing!
|
||||
PRIntn unit = textStyle->mWordSpacing.GetUnit();
|
||||
if (eStyleUnit_Coord == unit) {
|
||||
dw += textStyle->mWordSpacing.GetCoordValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4406,6 +4541,8 @@ nsTextFrame::ComputeWordFragmentWidth(nsIPresContext* aPresContext,
|
||||
}
|
||||
else {
|
||||
rc.GetWidth(bp, wordLen, width);
|
||||
// NOTE: Don't forget to add letter spacing for the word fragment!
|
||||
width += wordLen*ts.mLetterSpacing;
|
||||
}
|
||||
rc.SetFont(oldfm);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user