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:
buster%netscape.com 2000-04-17 14:40:46 +00:00
parent ee58499ab3
commit f40b76249a
22 changed files with 2222 additions and 1088 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -89,6 +89,10 @@ public:
nsIFrame* aFrame,
nsSize* aResult);
#ifdef DEBUG
void List();
#endif
protected:
/** utility method to calculate the band data at aY.

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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?

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -89,6 +89,10 @@ public:
nsIFrame* aFrame,
nsSize* aResult);
#ifdef DEBUG
void List();
#endif
protected:
/** utility method to calculate the band data at aY.

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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?

View File

@ -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

View File

@ -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;
}

View File

@ -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);