diff --git a/mozilla/content/shared/public/nsLayoutAtomList.h b/mozilla/content/shared/public/nsLayoutAtomList.h index 8a7f51c96b1..18e0e14ea04 100644 --- a/mozilla/content/shared/public/nsLayoutAtomList.h +++ b/mozilla/content/shared/public/nsLayoutAtomList.h @@ -117,6 +117,7 @@ LAYOUT_ATOM(maxElementSizeProperty, "MaxElementSizeProperty") // nsSize* LAYOUT_ATOM(overflowAreaProperty, "OverflowArea") // nsRect* LAYOUT_ATOM(overflowProperty, "OverflowProperty") // list of nsIFrame* LAYOUT_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox* +LAYOUT_ATOM(spaceManagerProperty, "SpaceManagerProperty") // the space manager for a block LAYOUT_ATOM(viewProperty, "ViewProperty") // nsView* // Alphabetical list of event handler names diff --git a/mozilla/layout/base/nsIPresShell.h b/mozilla/layout/base/nsIPresShell.h index d0e1235e663..8c66dfdec97 100644 --- a/mozilla/layout/base/nsIPresShell.h +++ b/mozilla/layout/base/nsIPresShell.h @@ -72,6 +72,16 @@ typedef enum SelectionRegion{SELECTION_ANCHOR_REGION = 0, SELECTION_FOCUS_REGION, NUM_SELECTION_REGIONS} SelectionRegion; +// debug VerifyReflow flags +#define VERIFY_REFLOW_ON 0x01 +#define VERIFY_REFLOW_NOISY 0x02 +#define VERIFY_REFLOW_ALL 0x04 +#define VERIFY_REFLOW_DUMP_COMMANDS 0x08 +#define VERIFY_REFLOW_NOISY_RC 0x10 +#define VERIFY_REFLOW_REALLY_NOISY_RC 0x20 +#define VERIFY_REFLOW_INCLUDE_SPACE_MANAGER 0x40 +#define VERIFY_REFLOW_DURING_RESIZE_REFLOW 0x80 + /** * Presentation shell interface. Presentation shells are the @@ -416,6 +426,10 @@ public: */ static NS_LAYOUT void SetVerifyReflowEnable(PRBool aEnabled); + /** + * Get the flags associated with the VerifyReflow debug tool + */ + static NS_LAYOUT PRInt32 GetVerifyReflowFlags(); }; /** diff --git a/mozilla/layout/base/nsLayoutAtomList.h b/mozilla/layout/base/nsLayoutAtomList.h index 8a7f51c96b1..18e0e14ea04 100644 --- a/mozilla/layout/base/nsLayoutAtomList.h +++ b/mozilla/layout/base/nsLayoutAtomList.h @@ -117,6 +117,7 @@ LAYOUT_ATOM(maxElementSizeProperty, "MaxElementSizeProperty") // nsSize* LAYOUT_ATOM(overflowAreaProperty, "OverflowArea") // nsRect* LAYOUT_ATOM(overflowProperty, "OverflowProperty") // list of nsIFrame* LAYOUT_ATOM(overflowLinesProperty, "OverflowLinesProperty") // list of nsLineBox* +LAYOUT_ATOM(spaceManagerProperty, "SpaceManagerProperty") // the space manager for a block LAYOUT_ATOM(viewProperty, "ViewProperty") // nsView* // Alphabetical list of event handler names diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index befd8272edf..119c924e5f3 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -22,6 +22,7 @@ #define PL_ARENA_CONST_ALIGN_MASK 3 #include "nsIPresShell.h" +#include "nsISpaceManager.h" #include "nsIPresContext.h" #include "nsIContent.h" #include "nsIDocument.h" @@ -48,6 +49,7 @@ #include "nsIDOMSelection.h" #include "nsISelectionController.h" #include "nsLayoutCID.h" +#include "nsLayoutAtoms.h" #include "nsIDOMRange.h" #include "nsIDOMDocument.h" #include "nsIDOMNode.h" @@ -573,15 +575,7 @@ VerifyStyleTree(nsIPresContext* aPresContext, nsIFrameManager* aFrameManager) * means that you cannot perform logging before then. */ static PRLogModuleInfo* gLogModule; - static PRUint32 gVerifyReflowFlags; - -#define VERIFY_REFLOW_ON 0x01 -#define VERIFY_REFLOW_NOISY 0x02 -#define VERIFY_REFLOW_ALL 0x04 -#define VERIFY_REFLOW_DUMP_COMMANDS 0x08 -#define VERIFY_REFLOW_NOISY_RC 0x10 -#define VERIFY_REFLOW_REALLY_NOISY_RC 0x20 #endif static PRBool gVerifyReflowEnabled; @@ -627,6 +621,12 @@ nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled) gVerifyReflowEnabled = aEnabled; } +NS_LAYOUT PRInt32 +nsIPresShell::GetVerifyReflowFlags() +{ + return gVerifyReflowFlags; +} + //---------------------------------------------------------------------- NS_LAYOUT nsresult @@ -1406,6 +1406,13 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) #endif } ExitReflowLock(PR_TRUE); + // if the proper flag is set, VerifyReflow now + if (GetVerifyReflowEnable() && (VERIFY_REFLOW_DURING_RESIZE_REFLOW & gVerifyReflowFlags)) + { + mInVerifyReflow = PR_TRUE; + PRBool ok = VerifyIncrementalReflow(); + mInVerifyReflow = PR_FALSE; + } return NS_OK; //XXX this needs to be real. MMP } @@ -3231,6 +3238,8 @@ static PRBool CompareTrees(nsIPresContext* aFirstPresContext, nsIFrame* aFirstFrame, nsIPresContext* aSecondPresContext, nsIFrame* aSecondFrame) { + if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame) + return PR_TRUE; PRBool ok = PR_TRUE; nsIAtom* listName = nsnull; PRInt32 listIndex = 0; @@ -3305,6 +3314,115 @@ CompareTrees(nsIPresContext* aFirstPresContext, nsIFrame* aFirstFrame, break; } + // verify that neither frame has a space manager, + // or they both do and the space managers are equivalent + nsCOMPtrfm1; + nsCOMPtr ps1; + nsISpaceManager *sm1; // note, no ref counting here + aFirstPresContext->GetShell(getter_AddRefs(ps1)); + NS_ASSERTION(ps1, "no pres shell for primary tree!"); + ps1->GetFrameManager(getter_AddRefs(fm1)); + NS_ASSERTION(fm1, "no frame manager for primary tree!"); + fm1->GetFrameProperty((nsIFrame*)k1, nsLayoutAtoms::spaceManagerProperty, + 0, (void **)&sm1); + // look at the test frame + nsCOMPtrfm2; + nsCOMPtr ps2; + nsISpaceManager *sm2; // note, no ref counting here + aSecondPresContext->GetShell(getter_AddRefs(ps2)); + NS_ASSERTION(ps2, "no pres shell for test tree!"); + ps2->GetFrameManager(getter_AddRefs(fm2)); + NS_ASSERTION(fm2, "no frame manager for test tree!"); + fm2->GetFrameProperty((nsIFrame*)k2, nsLayoutAtoms::spaceManagerProperty, + 0, (void **)&sm2); + // now compare the space managers + if (((nsnull == sm1) && (nsnull != sm2)) || + ((nsnull != sm1) && (nsnull == sm2))) { // one is null, and the other is not + ok = PR_FALSE; + LogVerifyMessage(k1, k2, "space managers are not matched\n"); + } + else if (sm1 && sm2) { // both are not null, compare them + // first, compare yMost + nscoord yMost1, yMost2; + nsresult smresult = sm1->YMost(yMost1); + if (NS_ERROR_ABORT != smresult) + { + NS_ASSERTION(NS_SUCCEEDED(smresult), "bad result"); + smresult = sm2->YMost(yMost2); + NS_ASSERTION(NS_SUCCEEDED(smresult), "bad result"); + if (yMost1 != yMost2) { + LogVerifyMessage(k1, k2, "yMost of space managers differs\n"); + } + // now compare bands by sampling + PRInt32 yIncrement = yMost1/100; + if (0==yIncrement) { + yIncrement = 1; // guarantee we make progress in the loop below + } + nscoord yOffset = 0; + for ( ; ok && yOffset < yMost1; yOffset += yIncrement) + { + nscoord small=5, large=100; + nsBandData band1, band2; + nsBandTrapezoid trap1[20], trap2[20]; + band1.mSize = band2.mSize = 20; + band1.mTrapezoids = trap1; + band2.mTrapezoids = trap2; + sm1->GetBandData(yOffset, nsSize(small,small), band1); + sm2->GetBandData(yOffset, nsSize(small,small), band2); + if (band1.mCount != band2.mCount) + { // count mismatch, stop comparing + LogVerifyMessage(k1, k2, "band.mCount of space managers differs\n"); + printf("count1= %d, count2=%d, yOffset = %d, size=%d\n", + band1.mCount, band2.mCount, yOffset, small); + ok = PR_FALSE; + + } + else // band counts match, compare individual traps + { + PRInt32 trapIndex=0; + for ( ;trapIndexGetBandData(yOffset, nsSize(large,large), band1); + sm2->GetBandData(yOffset, nsSize(large,large), band2); + if (band1.mCount != band2.mCount) + { // count mismatch, stop comparing + LogVerifyMessage(k1, k2, "band.mCount of space managers differs\n"); + printf("count1= %d, count2=%d, yOffset = %d, size=%d\n", + band1.mCount, band2.mCount, yOffset, small); + ok = PR_FALSE; + + } + else // band counts match, compare individual traps + { + PRInt32 trapIndex=0; + for ( ; trapIndexmState != nsBandTrapezoid::Available) { +#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT + printf("band %p checking !Avail trap %p with frame %p\n", this, trapezoid, trapezoid->mFrame); +#endif const nsStyleDisplay* display; if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) { PRInt32 j, numFrames = trapezoid->mFrames->Count(); @@ -195,6 +201,9 @@ nsBlockBandData::ComputeAvailSpaceRect() // We have a floater using up all the available space leftFloaters = 1; } +#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT + printf("band %p has floaters %d, %d\n", this, leftFloaters, rightFloaters); +#endif mLeftFloaters = leftFloaters; mRightFloaters = rightFloaters; diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index f9f15b1328c..fd976566eb7 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -146,7 +146,7 @@ InitDebugFlags() } #undef NOISY_FIRST_LINE -#undef REALLY_NOISY_FIRST_LINE +#undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE #undef NOISY_FLOATER_CLEARING @@ -410,6 +410,10 @@ public: } PRBool IsImpactedByFloater() { +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", + this, mBand.GetFloaterCount()); +#endif return mBand.GetFloaterCount(); } @@ -741,16 +745,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, (const nsStyleStruct*&) spacing); switch (spacing->mFloatEdge) { default: - case NS_STYLE_FLOAT_EDGE_CONTENT: + case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floaters // The child block will flow around the floater. Therefore // give it all of the available space. aResult.x = borderPadding.left; aResult.width = mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mContentArea.width; - break; - - case NS_STYLE_FLOAT_EDGE_BORDER: + break; + case NS_STYLE_FLOAT_EDGE_BORDER: case NS_STYLE_FLOAT_EDGE_PADDING: { // The child block's border should be placed adjacent to, @@ -819,6 +822,9 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, aResult.x = mAvailSpaceRect.x + borderPadding.left; aResult.width = mAvailSpaceRect.width; } +#ifdef REALLY_NOISY_REFLOW + printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height); +#endif } PRBool @@ -1069,7 +1075,11 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine, mSpaceManager->AddRectRegion(floater, fc->mRegion); fc = fc->Next(); } - +#ifdef DEBUG + if (gNoisyReflow || gNoisySpaceManager) { + mSpaceManager->List(stdout); + } +#endif // And then put the translation back again mSpaceManager->Translate(bp.left, bp.top); } @@ -1394,8 +1404,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", - aReflowState.availableWidth, aReflowState.availableHeight, + printf(": begin reflow type %d availSize=%d,%d computedSize=%d,%d\n", + aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.mComputedWidth, aReflowState.mComputedHeight); } if (gNoisy) { @@ -1437,6 +1447,9 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Set the space manager in the existing reflow state nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; reflowState.mSpaceManager = spaceManager.get(); +#ifdef NOISY_SPACEMANAGER + printf("constructed new space manager %p\n", reflowState.mSpaceManager); +#endif } nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, @@ -1621,23 +1634,45 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } } + // see if verifyReflow is enabled, and if so store off the space manager pointer +#ifdef DEBUG + PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags(); + if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags) + { + // this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + nsISpaceManager *spaceManager = reflowState.mSpaceManager; + NS_ADDREF(spaceManager); + rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::spaceManagerProperty, + reflowState.mSpaceManager, nsnull /* should be nsSpaceManagerDestroyer*/); + } + } + } +#endif + // If we set the space manager, then restore the old space manager now that we're // going out of scope if (NS_BLOCK_SPACE_MGR & mState) { nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; +#ifdef NOISY_SPACEMANAGER + printf("restoring old space manager %p\n", oldSpaceManager); +#endif reflowState.mSpaceManager = oldSpaceManager; } -#if 0 #ifdef NOISY_SPACEMANAGER - if (eReflowReason_Incremental == aReflowState.reason) { - if (mSpaceManager) { - ListTag(stdout); - printf(": space-manager after reflow\n"); - mSpaceManager->List(stdout); - } + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + if (reflowState.mSpaceManager) { + ListTag(stdout); + printf(": space-manager %p after reflow\n", reflowState.mSpaceManager); + reflowState.mSpaceManager->List(stdout); } -#endif #endif // If this is an incremental reflow and we changed size, then make sure our @@ -2364,6 +2399,12 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) } else { // We can avoid reflowing *some* inline lines in some cases. +#ifdef REALLY_NOISY_REFLOW + 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 @@ -2525,7 +2566,11 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, //then we don't need to mark the line dirty. aState.GetAvailableSpace(next->mBounds.y + aDeltaY); PRBool wasImpactedByFloater = next->IsImpactedByFloater(); - PRBool isImpactedByFloater = aState.IsImpactedByFloater(); + PRBool isImpactedByFloater = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::PropogateReflowDamage %p was = %d, is=%d\n", + this, wasImpactedByFloater, isImpactedByFloater); +#endif if (wasImpactedByFloater != isImpactedByFloater) { next->MarkDirty(); } @@ -2659,10 +2704,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } - if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) - { - printf("line %p is not complete\n", line); - } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -2826,7 +2867,7 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, /** * Reflow a line. The line will either contain a single block frame - * or contain 1 or more inline frames. aLineReflowStatus indicates + * or contain 1 or more inline frames. aKeepReflowGoing indicates * whether or not the caller should continue to reflow more lines. */ nsresult @@ -3512,7 +3553,11 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Compute the available space for the block aState.GetAvailableSpace(); - aLine->SetLineIsImpactedByFloater(aState.IsImpactedByFloater()); +#ifdef REALLY_NOISY_REFLOW + printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false"); +#endif + PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; + aLine->SetLineIsImpactedByFloater(isImpacted); nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE; frame->IsSplittable(splitType); nsRect availSpace; @@ -3855,8 +3900,12 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // into. Apply a previous block frame's bottom margin first. aState.mY += aState.mPrevBottomMargin; aState.GetAvailableSpace(); - PRBool impactedByFloaters = aState.IsImpactedByFloater(); + PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; aLine->SetLineIsImpactedByFloater(impactedByFloaters); +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", + this, impactedByFloaters); +#endif const nsMargin& borderPadding = aState.BorderPadding(); nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; @@ -4697,10 +4746,10 @@ nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext) // we are told to reflow again before a next-in-flow is created // and reflows. nsLineBox* lastLine = nsLineBox::LastLine(mLines); - if (nsnull == lastLine) { - mLines = overflowLines; + if (nsnull == lastLine) { // if we had no lines before the drain operation + mLines = overflowLines; // set our mLines to the overflow } - else { + else { // otherwise, append the overflow to the mLines list lastLine->mNext = overflowLines; nsIFrame* lastFrame = lastLine->LastChild(); lastFrame->SetNextSibling(overflowLines->mFirstChild); diff --git a/mozilla/layout/generic/nsBlockFrame.h b/mozilla/layout/generic/nsBlockFrame.h index f1eb767329e..a89e747829e 100644 --- a/mozilla/layout/generic/nsBlockFrame.h +++ b/mozilla/layout/generic/nsBlockFrame.h @@ -140,8 +140,15 @@ public: virtual void DeleteChildsNextInFlow(nsIPresContext* aPresContext, nsIFrame* aNextInFlow); + /** return the topmost block child based on y-index. + * almost always the first or second line, if there is one. + * accounts for lines that hold only compressed white space, etc. + */ nsIFrame* GetTopBlockChild(); + /** Place the floaters in the spacemanager for all lines in this block. + * recursively adds floaters in child blocks of this frame. + */ nsresult UpdateSpaceManager(nsIPresContext* aPresContext, nsISpaceManager* aSpaceManager); @@ -160,9 +167,16 @@ protected: return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); } + /** move the frames contained by aLine by aDY + * if aLine is a block, it's child floaters are added to the state manager + */ void SlideLine(nsBlockReflowState& aState, nsLineBox* aLine, nscoord aDY); + /** grab overflow lines from this block's prevInFlow, and make them + * part of this block's mLines list. + * @return PR_TRUE if any lines were drained. + */ PRBool DrainOverflowLines(nsIPresContext* aPresContext); virtual PRIntn GetSkipSides() const; @@ -171,26 +185,51 @@ protected: nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); + /** add the frames in aFrameList to this block after aPrevSibling + * this block thinks in terms of lines, but the frame construction code + * knows nothing about lines at all. So we need to find the line that + * contains aPrevSibling and add aFrameList after aPrevSibling on that line. + * new lines are created as necessary to handle block data in aFrameList. + */ nsresult AddFrames(nsIPresContext* aPresContext, nsIFrame* aFrameList, nsIFrame* aPrevSibling); + /** move the frame list rooted at aFrame into this as a child + * assumes prev/next sibling pointers will be or have been set elsewhere + * changes aFrame's parent to be this, and reparents aFrame's view and stylecontext. + */ void FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame); + /** does all the real work for removing aDeletedFrame from this + * finds the line containing aFrame. + * handled continued frames + * marks lines dirty as needed + */ nsresult DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame); + /** set up the conditions necessary for an initial reflow */ nsresult PrepareInitialReflow(nsBlockReflowState& aState); + /** set up the conditions necessary for an styleChanged reflow */ nsresult PrepareStyleChangedReflow(nsBlockReflowState& aState); + /** set up the conditions necessary for an incremental reflow. + * the primary task is to mark the minimumly sufficient lines dirty. + */ nsresult PrepareChildIncrementalReflow(nsBlockReflowState& aState); + /** set up the conditions necessary for an resize reflow + * the primary task is to mark the minimumly sufficient lines dirty. + */ nsresult PrepareResizeReflow(nsBlockReflowState& aState); + /** reflow all lines that have been marked dirty */ nsresult ReflowDirtyLines(nsBlockReflowState& aState); + /** set aState to what it would be if we had done a full reflow to this point. */ void RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, nscoord aDeltaY, @@ -198,8 +237,15 @@ protected: //---------------------------------------- // Methods for line reflow - // XXX nuke em - + /** + * Reflow a line. + * @param aState the current reflow state + * @param aLine the line to reflow. can contain a single block frame + * or contain 1 or more inline frames. + * @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines + * @param aDamageDirtyArea if PR_TRUE, do extra work to mark the changed areas as damaged for painting + * this indicates that frames may have changed size, for example + */ nsresult ReflowLine(nsBlockReflowState& aState, nsLineBox* aLine, PRBool* aKeepReflowGoing, diff --git a/mozilla/layout/generic/nsBlockReflowState.cpp b/mozilla/layout/generic/nsBlockReflowState.cpp index f9f15b1328c..fd976566eb7 100644 --- a/mozilla/layout/generic/nsBlockReflowState.cpp +++ b/mozilla/layout/generic/nsBlockReflowState.cpp @@ -146,7 +146,7 @@ InitDebugFlags() } #undef NOISY_FIRST_LINE -#undef REALLY_NOISY_FIRST_LINE +#undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE #undef NOISY_FLOATER_CLEARING @@ -410,6 +410,10 @@ public: } PRBool IsImpactedByFloater() { +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", + this, mBand.GetFloaterCount()); +#endif return mBand.GetFloaterCount(); } @@ -741,16 +745,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, (const nsStyleStruct*&) spacing); switch (spacing->mFloatEdge) { default: - case NS_STYLE_FLOAT_EDGE_CONTENT: + case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floaters // The child block will flow around the floater. Therefore // give it all of the available space. aResult.x = borderPadding.left; aResult.width = mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mContentArea.width; - break; - - case NS_STYLE_FLOAT_EDGE_BORDER: + break; + case NS_STYLE_FLOAT_EDGE_BORDER: case NS_STYLE_FLOAT_EDGE_PADDING: { // The child block's border should be placed adjacent to, @@ -819,6 +822,9 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, aResult.x = mAvailSpaceRect.x + borderPadding.left; aResult.width = mAvailSpaceRect.width; } +#ifdef REALLY_NOISY_REFLOW + printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height); +#endif } PRBool @@ -1069,7 +1075,11 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine, mSpaceManager->AddRectRegion(floater, fc->mRegion); fc = fc->Next(); } - +#ifdef DEBUG + if (gNoisyReflow || gNoisySpaceManager) { + mSpaceManager->List(stdout); + } +#endif // And then put the translation back again mSpaceManager->Translate(bp.left, bp.top); } @@ -1394,8 +1404,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", - aReflowState.availableWidth, aReflowState.availableHeight, + printf(": begin reflow type %d availSize=%d,%d computedSize=%d,%d\n", + aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.mComputedWidth, aReflowState.mComputedHeight); } if (gNoisy) { @@ -1437,6 +1447,9 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Set the space manager in the existing reflow state nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; reflowState.mSpaceManager = spaceManager.get(); +#ifdef NOISY_SPACEMANAGER + printf("constructed new space manager %p\n", reflowState.mSpaceManager); +#endif } nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, @@ -1621,23 +1634,45 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } } + // see if verifyReflow is enabled, and if so store off the space manager pointer +#ifdef DEBUG + PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags(); + if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags) + { + // this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + nsISpaceManager *spaceManager = reflowState.mSpaceManager; + NS_ADDREF(spaceManager); + rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::spaceManagerProperty, + reflowState.mSpaceManager, nsnull /* should be nsSpaceManagerDestroyer*/); + } + } + } +#endif + // If we set the space manager, then restore the old space manager now that we're // going out of scope if (NS_BLOCK_SPACE_MGR & mState) { nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; +#ifdef NOISY_SPACEMANAGER + printf("restoring old space manager %p\n", oldSpaceManager); +#endif reflowState.mSpaceManager = oldSpaceManager; } -#if 0 #ifdef NOISY_SPACEMANAGER - if (eReflowReason_Incremental == aReflowState.reason) { - if (mSpaceManager) { - ListTag(stdout); - printf(": space-manager after reflow\n"); - mSpaceManager->List(stdout); - } + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + if (reflowState.mSpaceManager) { + ListTag(stdout); + printf(": space-manager %p after reflow\n", reflowState.mSpaceManager); + reflowState.mSpaceManager->List(stdout); } -#endif #endif // If this is an incremental reflow and we changed size, then make sure our @@ -2364,6 +2399,12 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) } else { // We can avoid reflowing *some* inline lines in some cases. +#ifdef REALLY_NOISY_REFLOW + 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 @@ -2525,7 +2566,11 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, //then we don't need to mark the line dirty. aState.GetAvailableSpace(next->mBounds.y + aDeltaY); PRBool wasImpactedByFloater = next->IsImpactedByFloater(); - PRBool isImpactedByFloater = aState.IsImpactedByFloater(); + PRBool isImpactedByFloater = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::PropogateReflowDamage %p was = %d, is=%d\n", + this, wasImpactedByFloater, isImpactedByFloater); +#endif if (wasImpactedByFloater != isImpactedByFloater) { next->MarkDirty(); } @@ -2659,10 +2704,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } - if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) - { - printf("line %p is not complete\n", line); - } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -2826,7 +2867,7 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, /** * Reflow a line. The line will either contain a single block frame - * or contain 1 or more inline frames. aLineReflowStatus indicates + * or contain 1 or more inline frames. aKeepReflowGoing indicates * whether or not the caller should continue to reflow more lines. */ nsresult @@ -3512,7 +3553,11 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Compute the available space for the block aState.GetAvailableSpace(); - aLine->SetLineIsImpactedByFloater(aState.IsImpactedByFloater()); +#ifdef REALLY_NOISY_REFLOW + printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false"); +#endif + PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; + aLine->SetLineIsImpactedByFloater(isImpacted); nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE; frame->IsSplittable(splitType); nsRect availSpace; @@ -3855,8 +3900,12 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // into. Apply a previous block frame's bottom margin first. aState.mY += aState.mPrevBottomMargin; aState.GetAvailableSpace(); - PRBool impactedByFloaters = aState.IsImpactedByFloater(); + PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; aLine->SetLineIsImpactedByFloater(impactedByFloaters); +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", + this, impactedByFloaters); +#endif const nsMargin& borderPadding = aState.BorderPadding(); nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; @@ -4697,10 +4746,10 @@ nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext) // we are told to reflow again before a next-in-flow is created // and reflows. nsLineBox* lastLine = nsLineBox::LastLine(mLines); - if (nsnull == lastLine) { - mLines = overflowLines; + if (nsnull == lastLine) { // if we had no lines before the drain operation + mLines = overflowLines; // set our mLines to the overflow } - else { + else { // otherwise, append the overflow to the mLines list lastLine->mNext = overflowLines; nsIFrame* lastFrame = lastLine->LastChild(); lastFrame->SetNextSibling(overflowLines->mFirstChild); diff --git a/mozilla/layout/generic/nsBlockReflowState.h b/mozilla/layout/generic/nsBlockReflowState.h index f9f15b1328c..fd976566eb7 100644 --- a/mozilla/layout/generic/nsBlockReflowState.h +++ b/mozilla/layout/generic/nsBlockReflowState.h @@ -146,7 +146,7 @@ InitDebugFlags() } #undef NOISY_FIRST_LINE -#undef REALLY_NOISY_FIRST_LINE +#undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE #undef NOISY_FLOATER_CLEARING @@ -410,6 +410,10 @@ public: } PRBool IsImpactedByFloater() { +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", + this, mBand.GetFloaterCount()); +#endif return mBand.GetFloaterCount(); } @@ -741,16 +745,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, (const nsStyleStruct*&) spacing); switch (spacing->mFloatEdge) { default: - case NS_STYLE_FLOAT_EDGE_CONTENT: + case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floaters // The child block will flow around the floater. Therefore // give it all of the available space. aResult.x = borderPadding.left; aResult.width = mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mContentArea.width; - break; - - case NS_STYLE_FLOAT_EDGE_BORDER: + break; + case NS_STYLE_FLOAT_EDGE_BORDER: case NS_STYLE_FLOAT_EDGE_PADDING: { // The child block's border should be placed adjacent to, @@ -819,6 +822,9 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, aResult.x = mAvailSpaceRect.x + borderPadding.left; aResult.width = mAvailSpaceRect.width; } +#ifdef REALLY_NOISY_REFLOW + printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height); +#endif } PRBool @@ -1069,7 +1075,11 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine, mSpaceManager->AddRectRegion(floater, fc->mRegion); fc = fc->Next(); } - +#ifdef DEBUG + if (gNoisyReflow || gNoisySpaceManager) { + mSpaceManager->List(stdout); + } +#endif // And then put the translation back again mSpaceManager->Translate(bp.left, bp.top); } @@ -1394,8 +1404,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", - aReflowState.availableWidth, aReflowState.availableHeight, + printf(": begin reflow type %d availSize=%d,%d computedSize=%d,%d\n", + aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.mComputedWidth, aReflowState.mComputedHeight); } if (gNoisy) { @@ -1437,6 +1447,9 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Set the space manager in the existing reflow state nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; reflowState.mSpaceManager = spaceManager.get(); +#ifdef NOISY_SPACEMANAGER + printf("constructed new space manager %p\n", reflowState.mSpaceManager); +#endif } nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, @@ -1621,23 +1634,45 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } } + // see if verifyReflow is enabled, and if so store off the space manager pointer +#ifdef DEBUG + PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags(); + if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags) + { + // this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + nsISpaceManager *spaceManager = reflowState.mSpaceManager; + NS_ADDREF(spaceManager); + rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::spaceManagerProperty, + reflowState.mSpaceManager, nsnull /* should be nsSpaceManagerDestroyer*/); + } + } + } +#endif + // If we set the space manager, then restore the old space manager now that we're // going out of scope if (NS_BLOCK_SPACE_MGR & mState) { nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; +#ifdef NOISY_SPACEMANAGER + printf("restoring old space manager %p\n", oldSpaceManager); +#endif reflowState.mSpaceManager = oldSpaceManager; } -#if 0 #ifdef NOISY_SPACEMANAGER - if (eReflowReason_Incremental == aReflowState.reason) { - if (mSpaceManager) { - ListTag(stdout); - printf(": space-manager after reflow\n"); - mSpaceManager->List(stdout); - } + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + if (reflowState.mSpaceManager) { + ListTag(stdout); + printf(": space-manager %p after reflow\n", reflowState.mSpaceManager); + reflowState.mSpaceManager->List(stdout); } -#endif #endif // If this is an incremental reflow and we changed size, then make sure our @@ -2364,6 +2399,12 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) } else { // We can avoid reflowing *some* inline lines in some cases. +#ifdef REALLY_NOISY_REFLOW + 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 @@ -2525,7 +2566,11 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, //then we don't need to mark the line dirty. aState.GetAvailableSpace(next->mBounds.y + aDeltaY); PRBool wasImpactedByFloater = next->IsImpactedByFloater(); - PRBool isImpactedByFloater = aState.IsImpactedByFloater(); + PRBool isImpactedByFloater = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::PropogateReflowDamage %p was = %d, is=%d\n", + this, wasImpactedByFloater, isImpactedByFloater); +#endif if (wasImpactedByFloater != isImpactedByFloater) { next->MarkDirty(); } @@ -2659,10 +2704,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } - if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) - { - printf("line %p is not complete\n", line); - } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -2826,7 +2867,7 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, /** * Reflow a line. The line will either contain a single block frame - * or contain 1 or more inline frames. aLineReflowStatus indicates + * or contain 1 or more inline frames. aKeepReflowGoing indicates * whether or not the caller should continue to reflow more lines. */ nsresult @@ -3512,7 +3553,11 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Compute the available space for the block aState.GetAvailableSpace(); - aLine->SetLineIsImpactedByFloater(aState.IsImpactedByFloater()); +#ifdef REALLY_NOISY_REFLOW + printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false"); +#endif + PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; + aLine->SetLineIsImpactedByFloater(isImpacted); nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE; frame->IsSplittable(splitType); nsRect availSpace; @@ -3855,8 +3900,12 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // into. Apply a previous block frame's bottom margin first. aState.mY += aState.mPrevBottomMargin; aState.GetAvailableSpace(); - PRBool impactedByFloaters = aState.IsImpactedByFloater(); + PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; aLine->SetLineIsImpactedByFloater(impactedByFloaters); +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", + this, impactedByFloaters); +#endif const nsMargin& borderPadding = aState.BorderPadding(); nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; @@ -4697,10 +4746,10 @@ nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext) // we are told to reflow again before a next-in-flow is created // and reflows. nsLineBox* lastLine = nsLineBox::LastLine(mLines); - if (nsnull == lastLine) { - mLines = overflowLines; + if (nsnull == lastLine) { // if we had no lines before the drain operation + mLines = overflowLines; // set our mLines to the overflow } - else { + else { // otherwise, append the overflow to the mLines list lastLine->mNext = overflowLines; nsIFrame* lastFrame = lastLine->LastChild(); lastFrame->SetNextSibling(overflowLines->mFirstChild); diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index 635fe300cee..79614a0d7e3 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -32,10 +32,16 @@ #include "nsAbsoluteContainingBlock.h" #include "nsLayoutAtoms.h" -#undef NOISY_FINAL_SIZE +#ifdef DEBUG +#undef NOISY_PUSHING +#endif nsIID nsInlineFrame::kInlineFrameCID = NS_INLINE_FRAME_CID; + + + + ////////////////////////////////////////////////////////////////////// // Basic nsInlineFrame methods @@ -426,6 +432,9 @@ nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext, PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); PRBool isComplete; frame = PullOneFrame(aPresContext, irs, &isComplete); +#ifdef NOISY_PUSHING + printf("%p pulled up %p\n", this, frame); +#endif if (nsnull == frame) { if (!isComplete) { aStatus = NS_FRAME_NOT_COMPLETE; @@ -668,6 +677,10 @@ nsInlineFrame::PushFrames(nsIPresContext* aPresContext, NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); #endif +#ifdef NOISY_PUSHING + printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n", + this, aFromChild, aPrevSibling); +#endif // Disconnect aFromChild from its previous sibling aPrevSibling->SetNextSibling(nsnull); diff --git a/mozilla/layout/generic/nsLineBox.cpp b/mozilla/layout/generic/nsLineBox.cpp index b56e89d224b..ede4ae9ca90 100644 --- a/mozilla/layout/generic/nsLineBox.cpp +++ b/mozilla/layout/generic/nsLineBox.cpp @@ -153,8 +153,8 @@ nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const { PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s[0x%x]", IsBlock() ? "block" : "inline", - IsDirty() ? "dirty" : "", - IsImpactedByFloater() ? "impacted" : "", + IsDirty() ? "dirty" : "clean", + IsImpactedByFloater() ? "IMPACTED" : "NOT Impacted", IsTrimmed() ? "trimmed" : "", mAllFlags); return aBuf; @@ -353,16 +353,15 @@ nsLineBox::FreeFloaters(nsFloaterCacheFreeList& aFreeList) void nsLineBox::RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager) -{ +{ if (IsInline()) { if (mInlineData) { nsFloaterCache* floaterCache = mInlineData->mFloaters.Head(); while (floaterCache) { nsIFrame* floater = floaterCache->mPlaceholder->GetOutOfFlowFrame(); - aSpaceManager->RemoveRegion(floater); - floaterCache = floaterCache->Next(); + floaterCache = floaterCache->Next(); } } } @@ -370,7 +369,7 @@ nsLineBox::RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager) void nsLineBox::AppendFloaters(nsFloaterCacheFreeList& aFreeList) -{ +{ NS_ABORT_IF_FALSE(IsInline(), "block line can't have floaters"); if (IsInline()) { if (aFreeList.NotEmpty()) { @@ -404,7 +403,7 @@ nsLineBox::RemoveFloater(nsIFrame* aFrame) void nsLineBox::SetCombinedArea(const nsRect& aCombinedArea) -{ +{ NS_ASSERTION(aCombinedArea.width >= 0, "illegal width for combined area"); NS_ASSERTION(aCombinedArea.height >= 0, "illegal height for combined area"); if (aCombinedArea != mBounds) { @@ -428,13 +427,22 @@ nsLineBox::SetCombinedArea(const nsRect& aCombinedArea) } MaybeFreeData(); } +#ifdef VERY_NOISY_REFLOW + printf("nsLB::SetCombinedArea(1) %p (%d, %d, %d, %d)\n", + this, aCombinedArea.x, aCombinedArea.y, aCombinedArea.width, aCombinedArea.height); +#endif } void nsLineBox::GetCombinedArea(nsRect* aResult) { + NS_ASSERTION(aResult, "null arg"); if (aResult) { *aResult = mData ? mData->mCombinedArea : mBounds; +#ifdef VERY_NOISY_REFLOW + printf("nsLB::SetCombinedArea(1) %p (%d, %d, %d, %d)\n", + this, aResult->x, aResult->y, aResult->width, aResult->height); +#endif } } diff --git a/mozilla/layout/generic/nsLineBox.h b/mozilla/layout/generic/nsLineBox.h index 190eece891a..e01460eafd4 100644 --- a/mozilla/layout/generic/nsLineBox.h +++ b/mozilla/layout/generic/nsLineBox.h @@ -189,6 +189,7 @@ public: // mImpactedByFloater bit void SetLineIsImpactedByFloater(PRBool aValue) { + NS_ASSERTION((PR_FALSE==aValue || PR_TRUE==aValue), "somebody is playing fast and loose with bools and bits!"); mFlags.mImpactedByFloater = aValue; } PRBool IsImpactedByFloater() const { @@ -197,6 +198,7 @@ public: // mTrimmed bit void SetTrimmed(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); mFlags.mTrimmed = aOn; } PRBool IsTrimmed() const { @@ -205,6 +207,7 @@ public: // mHasPercentageChild bit void SetHasPercentageChild(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); mFlags.mHasPercentageChild = aOn; } PRBool HasPercentageChild() const { @@ -213,6 +216,7 @@ public: // mLineWrapped bit void SetLineWrapped(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); mFlags.mLineWrapped = aOn; } PRBool IsLineWrapped() const { diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index 1ffea794f96..6f5e6816e70 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -235,6 +235,10 @@ 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)) { @@ -350,6 +354,10 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY, PRBool aPlacedLeftFloater, nsIFrame* aFloaterFrame) { +#ifdef REALLY_NOISY_REFLOW + printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p placedLeft=%s\n will set mImpacted to PR_TRUE", + aX, aY, aWidth, aHeight, aFloaterFrame, aPlacedLeftFloater?"true":"false"); +#endif PerSpanData* psd = mRootSpan; NS_PRECONDITION(psd->mX == psd->mLeftEdge, "update-band called late"); #ifdef DEBUG diff --git a/mozilla/layout/html/base/src/nsBlockBandData.cpp b/mozilla/layout/html/base/src/nsBlockBandData.cpp index ce7514a0ce1..32b93fc1478 100644 --- a/mozilla/layout/html/base/src/nsBlockBandData.cpp +++ b/mozilla/layout/html/base/src/nsBlockBandData.cpp @@ -133,6 +133,9 @@ nsBlockBandData::GetBandData(nscoord aY) void nsBlockBandData::ComputeAvailSpaceRect() { +#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT + printf("nsBlockBandData::ComputeAvailSpaceRect %p \n", this); +#endif if (0 == mCount) { mAvailSpace.x = 0; mAvailSpace.y = 0; @@ -157,6 +160,9 @@ nsBlockBandData::ComputeAvailSpaceRect() for (i = 0; i < mCount; i++) { trapezoid = &mTrapezoids[i]; if (trapezoid->mState != nsBandTrapezoid::Available) { +#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT + printf("band %p checking !Avail trap %p with frame %p\n", this, trapezoid, trapezoid->mFrame); +#endif const nsStyleDisplay* display; if (nsBandTrapezoid::OccupiedMultiple == trapezoid->mState) { PRInt32 j, numFrames = trapezoid->mFrames->Count(); @@ -195,6 +201,9 @@ nsBlockBandData::ComputeAvailSpaceRect() // We have a floater using up all the available space leftFloaters = 1; } +#ifdef REALLY_NOISY_COMPUTEAVAILSPACERECT + printf("band %p has floaters %d, %d\n", this, leftFloaters, rightFloaters); +#endif mLeftFloaters = leftFloaters; mRightFloaters = rightFloaters; diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index f9f15b1328c..fd976566eb7 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -146,7 +146,7 @@ InitDebugFlags() } #undef NOISY_FIRST_LINE -#undef REALLY_NOISY_FIRST_LINE +#undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE #undef NOISY_FLOATER_CLEARING @@ -410,6 +410,10 @@ public: } PRBool IsImpactedByFloater() { +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", + this, mBand.GetFloaterCount()); +#endif return mBand.GetFloaterCount(); } @@ -741,16 +745,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, (const nsStyleStruct*&) spacing); switch (spacing->mFloatEdge) { default: - case NS_STYLE_FLOAT_EDGE_CONTENT: + case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floaters // The child block will flow around the floater. Therefore // give it all of the available space. aResult.x = borderPadding.left; aResult.width = mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mContentArea.width; - break; - - case NS_STYLE_FLOAT_EDGE_BORDER: + break; + case NS_STYLE_FLOAT_EDGE_BORDER: case NS_STYLE_FLOAT_EDGE_PADDING: { // The child block's border should be placed adjacent to, @@ -819,6 +822,9 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, aResult.x = mAvailSpaceRect.x + borderPadding.left; aResult.width = mAvailSpaceRect.width; } +#ifdef REALLY_NOISY_REFLOW + printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height); +#endif } PRBool @@ -1069,7 +1075,11 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine, mSpaceManager->AddRectRegion(floater, fc->mRegion); fc = fc->Next(); } - +#ifdef DEBUG + if (gNoisyReflow || gNoisySpaceManager) { + mSpaceManager->List(stdout); + } +#endif // And then put the translation back again mSpaceManager->Translate(bp.left, bp.top); } @@ -1394,8 +1404,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", - aReflowState.availableWidth, aReflowState.availableHeight, + printf(": begin reflow type %d availSize=%d,%d computedSize=%d,%d\n", + aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.mComputedWidth, aReflowState.mComputedHeight); } if (gNoisy) { @@ -1437,6 +1447,9 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Set the space manager in the existing reflow state nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; reflowState.mSpaceManager = spaceManager.get(); +#ifdef NOISY_SPACEMANAGER + printf("constructed new space manager %p\n", reflowState.mSpaceManager); +#endif } nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, @@ -1621,23 +1634,45 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } } + // see if verifyReflow is enabled, and if so store off the space manager pointer +#ifdef DEBUG + PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags(); + if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags) + { + // this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + nsISpaceManager *spaceManager = reflowState.mSpaceManager; + NS_ADDREF(spaceManager); + rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::spaceManagerProperty, + reflowState.mSpaceManager, nsnull /* should be nsSpaceManagerDestroyer*/); + } + } + } +#endif + // If we set the space manager, then restore the old space manager now that we're // going out of scope if (NS_BLOCK_SPACE_MGR & mState) { nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; +#ifdef NOISY_SPACEMANAGER + printf("restoring old space manager %p\n", oldSpaceManager); +#endif reflowState.mSpaceManager = oldSpaceManager; } -#if 0 #ifdef NOISY_SPACEMANAGER - if (eReflowReason_Incremental == aReflowState.reason) { - if (mSpaceManager) { - ListTag(stdout); - printf(": space-manager after reflow\n"); - mSpaceManager->List(stdout); - } + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + if (reflowState.mSpaceManager) { + ListTag(stdout); + printf(": space-manager %p after reflow\n", reflowState.mSpaceManager); + reflowState.mSpaceManager->List(stdout); } -#endif #endif // If this is an incremental reflow and we changed size, then make sure our @@ -2364,6 +2399,12 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) } else { // We can avoid reflowing *some* inline lines in some cases. +#ifdef REALLY_NOISY_REFLOW + 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 @@ -2525,7 +2566,11 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, //then we don't need to mark the line dirty. aState.GetAvailableSpace(next->mBounds.y + aDeltaY); PRBool wasImpactedByFloater = next->IsImpactedByFloater(); - PRBool isImpactedByFloater = aState.IsImpactedByFloater(); + PRBool isImpactedByFloater = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::PropogateReflowDamage %p was = %d, is=%d\n", + this, wasImpactedByFloater, isImpactedByFloater); +#endif if (wasImpactedByFloater != isImpactedByFloater) { next->MarkDirty(); } @@ -2659,10 +2704,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } - if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) - { - printf("line %p is not complete\n", line); - } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -2826,7 +2867,7 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, /** * Reflow a line. The line will either contain a single block frame - * or contain 1 or more inline frames. aLineReflowStatus indicates + * or contain 1 or more inline frames. aKeepReflowGoing indicates * whether or not the caller should continue to reflow more lines. */ nsresult @@ -3512,7 +3553,11 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Compute the available space for the block aState.GetAvailableSpace(); - aLine->SetLineIsImpactedByFloater(aState.IsImpactedByFloater()); +#ifdef REALLY_NOISY_REFLOW + printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false"); +#endif + PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; + aLine->SetLineIsImpactedByFloater(isImpacted); nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE; frame->IsSplittable(splitType); nsRect availSpace; @@ -3855,8 +3900,12 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // into. Apply a previous block frame's bottom margin first. aState.mY += aState.mPrevBottomMargin; aState.GetAvailableSpace(); - PRBool impactedByFloaters = aState.IsImpactedByFloater(); + PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; aLine->SetLineIsImpactedByFloater(impactedByFloaters); +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", + this, impactedByFloaters); +#endif const nsMargin& borderPadding = aState.BorderPadding(); nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; @@ -4697,10 +4746,10 @@ nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext) // we are told to reflow again before a next-in-flow is created // and reflows. nsLineBox* lastLine = nsLineBox::LastLine(mLines); - if (nsnull == lastLine) { - mLines = overflowLines; + if (nsnull == lastLine) { // if we had no lines before the drain operation + mLines = overflowLines; // set our mLines to the overflow } - else { + else { // otherwise, append the overflow to the mLines list lastLine->mNext = overflowLines; nsIFrame* lastFrame = lastLine->LastChild(); lastFrame->SetNextSibling(overflowLines->mFirstChild); diff --git a/mozilla/layout/html/base/src/nsBlockFrame.h b/mozilla/layout/html/base/src/nsBlockFrame.h index f1eb767329e..a89e747829e 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.h +++ b/mozilla/layout/html/base/src/nsBlockFrame.h @@ -140,8 +140,15 @@ public: virtual void DeleteChildsNextInFlow(nsIPresContext* aPresContext, nsIFrame* aNextInFlow); + /** return the topmost block child based on y-index. + * almost always the first or second line, if there is one. + * accounts for lines that hold only compressed white space, etc. + */ nsIFrame* GetTopBlockChild(); + /** Place the floaters in the spacemanager for all lines in this block. + * recursively adds floaters in child blocks of this frame. + */ nsresult UpdateSpaceManager(nsIPresContext* aPresContext, nsISpaceManager* aSpaceManager); @@ -160,9 +167,16 @@ protected: return 0 != (mState & NS_BLOCK_FRAME_HAS_OUTSIDE_BULLET); } + /** move the frames contained by aLine by aDY + * if aLine is a block, it's child floaters are added to the state manager + */ void SlideLine(nsBlockReflowState& aState, nsLineBox* aLine, nscoord aDY); + /** grab overflow lines from this block's prevInFlow, and make them + * part of this block's mLines list. + * @return PR_TRUE if any lines were drained. + */ PRBool DrainOverflowLines(nsIPresContext* aPresContext); virtual PRIntn GetSkipSides() const; @@ -171,26 +185,51 @@ protected: nsBlockReflowState& aState, nsHTMLReflowMetrics& aMetrics); + /** add the frames in aFrameList to this block after aPrevSibling + * this block thinks in terms of lines, but the frame construction code + * knows nothing about lines at all. So we need to find the line that + * contains aPrevSibling and add aFrameList after aPrevSibling on that line. + * new lines are created as necessary to handle block data in aFrameList. + */ nsresult AddFrames(nsIPresContext* aPresContext, nsIFrame* aFrameList, nsIFrame* aPrevSibling); + /** move the frame list rooted at aFrame into this as a child + * assumes prev/next sibling pointers will be or have been set elsewhere + * changes aFrame's parent to be this, and reparents aFrame's view and stylecontext. + */ void FixParentAndView(nsIPresContext* aPresContext, nsIFrame* aFrame); + /** does all the real work for removing aDeletedFrame from this + * finds the line containing aFrame. + * handled continued frames + * marks lines dirty as needed + */ nsresult DoRemoveFrame(nsIPresContext* aPresContext, nsIFrame* aDeletedFrame); + /** set up the conditions necessary for an initial reflow */ nsresult PrepareInitialReflow(nsBlockReflowState& aState); + /** set up the conditions necessary for an styleChanged reflow */ nsresult PrepareStyleChangedReflow(nsBlockReflowState& aState); + /** set up the conditions necessary for an incremental reflow. + * the primary task is to mark the minimumly sufficient lines dirty. + */ nsresult PrepareChildIncrementalReflow(nsBlockReflowState& aState); + /** set up the conditions necessary for an resize reflow + * the primary task is to mark the minimumly sufficient lines dirty. + */ nsresult PrepareResizeReflow(nsBlockReflowState& aState); + /** reflow all lines that have been marked dirty */ nsresult ReflowDirtyLines(nsBlockReflowState& aState); + /** set aState to what it would be if we had done a full reflow to this point. */ void RecoverStateFrom(nsBlockReflowState& aState, nsLineBox* aLine, nscoord aDeltaY, @@ -198,8 +237,15 @@ protected: //---------------------------------------- // Methods for line reflow - // XXX nuke em - + /** + * Reflow a line. + * @param aState the current reflow state + * @param aLine the line to reflow. can contain a single block frame + * or contain 1 or more inline frames. + * @param aKeepReflowGoing [OUT] indicates whether the caller should continue to reflow more lines + * @param aDamageDirtyArea if PR_TRUE, do extra work to mark the changed areas as damaged for painting + * this indicates that frames may have changed size, for example + */ nsresult ReflowLine(nsBlockReflowState& aState, nsLineBox* aLine, PRBool* aKeepReflowGoing, diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.cpp b/mozilla/layout/html/base/src/nsBlockReflowState.cpp index f9f15b1328c..fd976566eb7 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.cpp +++ b/mozilla/layout/html/base/src/nsBlockReflowState.cpp @@ -146,7 +146,7 @@ InitDebugFlags() } #undef NOISY_FIRST_LINE -#undef REALLY_NOISY_FIRST_LINE +#undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE #undef NOISY_FLOATER_CLEARING @@ -410,6 +410,10 @@ public: } PRBool IsImpactedByFloater() { +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", + this, mBand.GetFloaterCount()); +#endif return mBand.GetFloaterCount(); } @@ -741,16 +745,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, (const nsStyleStruct*&) spacing); switch (spacing->mFloatEdge) { default: - case NS_STYLE_FLOAT_EDGE_CONTENT: + case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floaters // The child block will flow around the floater. Therefore // give it all of the available space. aResult.x = borderPadding.left; aResult.width = mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mContentArea.width; - break; - - case NS_STYLE_FLOAT_EDGE_BORDER: + break; + case NS_STYLE_FLOAT_EDGE_BORDER: case NS_STYLE_FLOAT_EDGE_PADDING: { // The child block's border should be placed adjacent to, @@ -819,6 +822,9 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, aResult.x = mAvailSpaceRect.x + borderPadding.left; aResult.width = mAvailSpaceRect.width; } +#ifdef REALLY_NOISY_REFLOW + printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height); +#endif } PRBool @@ -1069,7 +1075,11 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine, mSpaceManager->AddRectRegion(floater, fc->mRegion); fc = fc->Next(); } - +#ifdef DEBUG + if (gNoisyReflow || gNoisySpaceManager) { + mSpaceManager->List(stdout); + } +#endif // And then put the translation back again mSpaceManager->Translate(bp.left, bp.top); } @@ -1394,8 +1404,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", - aReflowState.availableWidth, aReflowState.availableHeight, + printf(": begin reflow type %d availSize=%d,%d computedSize=%d,%d\n", + aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.mComputedWidth, aReflowState.mComputedHeight); } if (gNoisy) { @@ -1437,6 +1447,9 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Set the space manager in the existing reflow state nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; reflowState.mSpaceManager = spaceManager.get(); +#ifdef NOISY_SPACEMANAGER + printf("constructed new space manager %p\n", reflowState.mSpaceManager); +#endif } nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, @@ -1621,23 +1634,45 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } } + // see if verifyReflow is enabled, and if so store off the space manager pointer +#ifdef DEBUG + PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags(); + if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags) + { + // this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + nsISpaceManager *spaceManager = reflowState.mSpaceManager; + NS_ADDREF(spaceManager); + rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::spaceManagerProperty, + reflowState.mSpaceManager, nsnull /* should be nsSpaceManagerDestroyer*/); + } + } + } +#endif + // If we set the space manager, then restore the old space manager now that we're // going out of scope if (NS_BLOCK_SPACE_MGR & mState) { nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; +#ifdef NOISY_SPACEMANAGER + printf("restoring old space manager %p\n", oldSpaceManager); +#endif reflowState.mSpaceManager = oldSpaceManager; } -#if 0 #ifdef NOISY_SPACEMANAGER - if (eReflowReason_Incremental == aReflowState.reason) { - if (mSpaceManager) { - ListTag(stdout); - printf(": space-manager after reflow\n"); - mSpaceManager->List(stdout); - } + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + if (reflowState.mSpaceManager) { + ListTag(stdout); + printf(": space-manager %p after reflow\n", reflowState.mSpaceManager); + reflowState.mSpaceManager->List(stdout); } -#endif #endif // If this is an incremental reflow and we changed size, then make sure our @@ -2364,6 +2399,12 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) } else { // We can avoid reflowing *some* inline lines in some cases. +#ifdef REALLY_NOISY_REFLOW + 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 @@ -2525,7 +2566,11 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, //then we don't need to mark the line dirty. aState.GetAvailableSpace(next->mBounds.y + aDeltaY); PRBool wasImpactedByFloater = next->IsImpactedByFloater(); - PRBool isImpactedByFloater = aState.IsImpactedByFloater(); + PRBool isImpactedByFloater = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::PropogateReflowDamage %p was = %d, is=%d\n", + this, wasImpactedByFloater, isImpactedByFloater); +#endif if (wasImpactedByFloater != isImpactedByFloater) { next->MarkDirty(); } @@ -2659,10 +2704,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } - if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) - { - printf("line %p is not complete\n", line); - } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -2826,7 +2867,7 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, /** * Reflow a line. The line will either contain a single block frame - * or contain 1 or more inline frames. aLineReflowStatus indicates + * or contain 1 or more inline frames. aKeepReflowGoing indicates * whether or not the caller should continue to reflow more lines. */ nsresult @@ -3512,7 +3553,11 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Compute the available space for the block aState.GetAvailableSpace(); - aLine->SetLineIsImpactedByFloater(aState.IsImpactedByFloater()); +#ifdef REALLY_NOISY_REFLOW + printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false"); +#endif + PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; + aLine->SetLineIsImpactedByFloater(isImpacted); nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE; frame->IsSplittable(splitType); nsRect availSpace; @@ -3855,8 +3900,12 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // into. Apply a previous block frame's bottom margin first. aState.mY += aState.mPrevBottomMargin; aState.GetAvailableSpace(); - PRBool impactedByFloaters = aState.IsImpactedByFloater(); + PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; aLine->SetLineIsImpactedByFloater(impactedByFloaters); +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", + this, impactedByFloaters); +#endif const nsMargin& borderPadding = aState.BorderPadding(); nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; @@ -4697,10 +4746,10 @@ nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext) // we are told to reflow again before a next-in-flow is created // and reflows. nsLineBox* lastLine = nsLineBox::LastLine(mLines); - if (nsnull == lastLine) { - mLines = overflowLines; + if (nsnull == lastLine) { // if we had no lines before the drain operation + mLines = overflowLines; // set our mLines to the overflow } - else { + else { // otherwise, append the overflow to the mLines list lastLine->mNext = overflowLines; nsIFrame* lastFrame = lastLine->LastChild(); lastFrame->SetNextSibling(overflowLines->mFirstChild); diff --git a/mozilla/layout/html/base/src/nsBlockReflowState.h b/mozilla/layout/html/base/src/nsBlockReflowState.h index f9f15b1328c..fd976566eb7 100644 --- a/mozilla/layout/html/base/src/nsBlockReflowState.h +++ b/mozilla/layout/html/base/src/nsBlockReflowState.h @@ -146,7 +146,7 @@ InitDebugFlags() } #undef NOISY_FIRST_LINE -#undef REALLY_NOISY_FIRST_LINE +#undef REALLY_NOISY_FIRST_LINE #undef NOISY_FIRST_LETTER #undef NOISY_MAX_ELEMENT_SIZE #undef NOISY_FLOATER_CLEARING @@ -410,6 +410,10 @@ public: } PRBool IsImpactedByFloater() { +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockReflowState::IsImpactedByFloater %p returned %d\n", + this, mBand.GetFloaterCount()); +#endif return mBand.GetFloaterCount(); } @@ -741,16 +745,15 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, (const nsStyleStruct*&) spacing); switch (spacing->mFloatEdge) { default: - case NS_STYLE_FLOAT_EDGE_CONTENT: + case NS_STYLE_FLOAT_EDGE_CONTENT: // content and only content does runaround of floaters // The child block will flow around the floater. Therefore // give it all of the available space. aResult.x = borderPadding.left; aResult.width = mUnconstrainedWidth ? NS_UNCONSTRAINEDSIZE : mContentArea.width; - break; - - case NS_STYLE_FLOAT_EDGE_BORDER: + break; + case NS_STYLE_FLOAT_EDGE_BORDER: case NS_STYLE_FLOAT_EDGE_PADDING: { // The child block's border should be placed adjacent to, @@ -819,6 +822,9 @@ nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame, aResult.x = mAvailSpaceRect.x + borderPadding.left; aResult.width = mAvailSpaceRect.width; } +#ifdef REALLY_NOISY_REFLOW + printf(" CBAS: result %d %d %d %d\n", aResult.x, aResult.y, aResult.width, aResult.height); +#endif } PRBool @@ -1069,7 +1075,11 @@ nsBlockReflowState::RecoverStateFrom(nsLineBox* aLine, mSpaceManager->AddRectRegion(floater, fc->mRegion); fc = fc->Next(); } - +#ifdef DEBUG + if (gNoisyReflow || gNoisySpaceManager) { + mSpaceManager->List(stdout); + } +#endif // And then put the translation back again mSpaceManager->Translate(bp.left, bp.top); } @@ -1394,8 +1404,8 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, if (gNoisyReflow) { IndentBy(stdout, gNoiseIndent); ListTag(stdout); - printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n", - aReflowState.availableWidth, aReflowState.availableHeight, + printf(": begin reflow type %d availSize=%d,%d computedSize=%d,%d\n", + aReflowState.reason, aReflowState.availableWidth, aReflowState.availableHeight, aReflowState.mComputedWidth, aReflowState.mComputedHeight); } if (gNoisy) { @@ -1437,6 +1447,9 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Set the space manager in the existing reflow state nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; reflowState.mSpaceManager = spaceManager.get(); +#ifdef NOISY_SPACEMANAGER + printf("constructed new space manager %p\n", reflowState.mSpaceManager); +#endif } nsBlockReflowState state(aReflowState, aPresContext, this, aMetrics, @@ -1621,23 +1634,45 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } } + // see if verifyReflow is enabled, and if so store off the space manager pointer +#ifdef DEBUG + PRInt32 verifyReflowFlags = nsIPresShell::GetVerifyReflowFlags(); + if (VERIFY_REFLOW_INCLUDE_SPACE_MANAGER & verifyReflowFlags) + { + // this is a leak of the space manager, but it's only in debug if verify reflow is enabled, so not a big deal + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (shell) { + nsCOMPtr frameManager; + shell->GetFrameManager(getter_AddRefs(frameManager)); + if (frameManager) { + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + nsISpaceManager *spaceManager = reflowState.mSpaceManager; + NS_ADDREF(spaceManager); + rv = frameManager->SetFrameProperty(this, nsLayoutAtoms::spaceManagerProperty, + reflowState.mSpaceManager, nsnull /* should be nsSpaceManagerDestroyer*/); + } + } + } +#endif + // If we set the space manager, then restore the old space manager now that we're // going out of scope if (NS_BLOCK_SPACE_MGR & mState) { nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; +#ifdef NOISY_SPACEMANAGER + printf("restoring old space manager %p\n", oldSpaceManager); +#endif reflowState.mSpaceManager = oldSpaceManager; } -#if 0 #ifdef NOISY_SPACEMANAGER - if (eReflowReason_Incremental == aReflowState.reason) { - if (mSpaceManager) { - ListTag(stdout); - printf(": space-manager after reflow\n"); - mSpaceManager->List(stdout); - } + nsHTMLReflowState& reflowState = (nsHTMLReflowState&)aReflowState; + if (reflowState.mSpaceManager) { + ListTag(stdout); + printf(": space-manager %p after reflow\n", reflowState.mSpaceManager); + reflowState.mSpaceManager->List(stdout); } -#endif #endif // If this is an incremental reflow and we changed size, then make sure our @@ -2364,6 +2399,12 @@ nsBlockFrame::PrepareResizeReflow(nsBlockReflowState& aState) } else { // We can avoid reflowing *some* inline lines in some cases. +#ifdef REALLY_NOISY_REFLOW + 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 @@ -2525,7 +2566,11 @@ nsBlockFrame::PropogateReflowDamage(nsBlockReflowState& aState, //then we don't need to mark the line dirty. aState.GetAvailableSpace(next->mBounds.y + aDeltaY); PRBool wasImpactedByFloater = next->IsImpactedByFloater(); - PRBool isImpactedByFloater = aState.IsImpactedByFloater(); + PRBool isImpactedByFloater = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::PropogateReflowDamage %p was = %d, is=%d\n", + this, wasImpactedByFloater, isImpactedByFloater); +#endif if (wasImpactedByFloater != isImpactedByFloater) { next->MarkDirty(); } @@ -2659,10 +2704,6 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState) if (NS_FAILED(rv)) { return rv; } - if (!(NS_FRAME_IS_COMPLETE(aState.mReflowStatus))) - { - printf("line %p is not complete\n", line); - } if (!keepGoing) { if (0 == line->GetChildCount()) { DeleteLine(aState, line); @@ -2826,7 +2867,7 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, /** * Reflow a line. The line will either contain a single block frame - * or contain 1 or more inline frames. aLineReflowStatus indicates + * or contain 1 or more inline frames. aKeepReflowGoing indicates * whether or not the caller should continue to reflow more lines. */ nsresult @@ -3512,7 +3553,11 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // Compute the available space for the block aState.GetAvailableSpace(); - aLine->SetLineIsImpactedByFloater(aState.IsImpactedByFloater()); +#ifdef REALLY_NOISY_REFLOW + printf("setting line %p isImpacted to %s\n", aLine, aState.IsImpactedByFloater()?"true":"false"); +#endif + PRBool isImpacted = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; + aLine->SetLineIsImpactedByFloater(isImpacted); nsSplittableType splitType = NS_FRAME_NOT_SPLITTABLE; frame->IsSplittable(splitType); nsRect availSpace; @@ -3855,8 +3900,12 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState, // into. Apply a previous block frame's bottom margin first. aState.mY += aState.mPrevBottomMargin; aState.GetAvailableSpace(); - PRBool impactedByFloaters = aState.IsImpactedByFloater(); + PRBool impactedByFloaters = aState.IsImpactedByFloater() ? PR_TRUE : PR_FALSE; aLine->SetLineIsImpactedByFloater(impactedByFloaters); +#ifdef REALLY_NOISY_REFLOW + printf("nsBlockFrame::DoReflowInlineFrames %p impacted = %d\n", + this, impactedByFloaters); +#endif const nsMargin& borderPadding = aState.BorderPadding(); nscoord x = aState.mAvailSpaceRect.x + borderPadding.left; @@ -4697,10 +4746,10 @@ nsBlockFrame::DrainOverflowLines(nsIPresContext* aPresContext) // we are told to reflow again before a next-in-flow is created // and reflows. nsLineBox* lastLine = nsLineBox::LastLine(mLines); - if (nsnull == lastLine) { - mLines = overflowLines; + if (nsnull == lastLine) { // if we had no lines before the drain operation + mLines = overflowLines; // set our mLines to the overflow } - else { + else { // otherwise, append the overflow to the mLines list lastLine->mNext = overflowLines; nsIFrame* lastFrame = lastLine->LastChild(); lastFrame->SetNextSibling(overflowLines->mFirstChild); diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index 635fe300cee..79614a0d7e3 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -32,10 +32,16 @@ #include "nsAbsoluteContainingBlock.h" #include "nsLayoutAtoms.h" -#undef NOISY_FINAL_SIZE +#ifdef DEBUG +#undef NOISY_PUSHING +#endif nsIID nsInlineFrame::kInlineFrameCID = NS_INLINE_FRAME_CID; + + + + ////////////////////////////////////////////////////////////////////// // Basic nsInlineFrame methods @@ -426,6 +432,9 @@ nsInlineFrame::ReflowFrames(nsIPresContext* aPresContext, PRBool reflowingFirstLetter = lineLayout->GetFirstLetterStyleOK(); PRBool isComplete; frame = PullOneFrame(aPresContext, irs, &isComplete); +#ifdef NOISY_PUSHING + printf("%p pulled up %p\n", this, frame); +#endif if (nsnull == frame) { if (!isComplete) { aStatus = NS_FRAME_NOT_COMPLETE; @@ -668,6 +677,10 @@ nsInlineFrame::PushFrames(nsIPresContext* aPresContext, NS_PRECONDITION(prevNextSibling == aFromChild, "bad prev sibling"); #endif +#ifdef NOISY_PUSHING + printf("%p pushing aFromChild %p, disconnecting from prev sib %p\n", + this, aFromChild, aPrevSibling); +#endif // Disconnect aFromChild from its previous sibling aPrevSibling->SetNextSibling(nsnull); diff --git a/mozilla/layout/html/base/src/nsLineBox.cpp b/mozilla/layout/html/base/src/nsLineBox.cpp index b56e89d224b..ede4ae9ca90 100644 --- a/mozilla/layout/html/base/src/nsLineBox.cpp +++ b/mozilla/layout/html/base/src/nsLineBox.cpp @@ -153,8 +153,8 @@ nsLineBox::StateToString(char* aBuf, PRInt32 aBufSize) const { PR_snprintf(aBuf, aBufSize, "%s,%s,%s,%s[0x%x]", IsBlock() ? "block" : "inline", - IsDirty() ? "dirty" : "", - IsImpactedByFloater() ? "impacted" : "", + IsDirty() ? "dirty" : "clean", + IsImpactedByFloater() ? "IMPACTED" : "NOT Impacted", IsTrimmed() ? "trimmed" : "", mAllFlags); return aBuf; @@ -353,16 +353,15 @@ nsLineBox::FreeFloaters(nsFloaterCacheFreeList& aFreeList) void nsLineBox::RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager) -{ +{ if (IsInline()) { if (mInlineData) { nsFloaterCache* floaterCache = mInlineData->mFloaters.Head(); while (floaterCache) { nsIFrame* floater = floaterCache->mPlaceholder->GetOutOfFlowFrame(); - aSpaceManager->RemoveRegion(floater); - floaterCache = floaterCache->Next(); + floaterCache = floaterCache->Next(); } } } @@ -370,7 +369,7 @@ nsLineBox::RemoveFloatersFromSpaceManager(nsISpaceManager* aSpaceManager) void nsLineBox::AppendFloaters(nsFloaterCacheFreeList& aFreeList) -{ +{ NS_ABORT_IF_FALSE(IsInline(), "block line can't have floaters"); if (IsInline()) { if (aFreeList.NotEmpty()) { @@ -404,7 +403,7 @@ nsLineBox::RemoveFloater(nsIFrame* aFrame) void nsLineBox::SetCombinedArea(const nsRect& aCombinedArea) -{ +{ NS_ASSERTION(aCombinedArea.width >= 0, "illegal width for combined area"); NS_ASSERTION(aCombinedArea.height >= 0, "illegal height for combined area"); if (aCombinedArea != mBounds) { @@ -428,13 +427,22 @@ nsLineBox::SetCombinedArea(const nsRect& aCombinedArea) } MaybeFreeData(); } +#ifdef VERY_NOISY_REFLOW + printf("nsLB::SetCombinedArea(1) %p (%d, %d, %d, %d)\n", + this, aCombinedArea.x, aCombinedArea.y, aCombinedArea.width, aCombinedArea.height); +#endif } void nsLineBox::GetCombinedArea(nsRect* aResult) { + NS_ASSERTION(aResult, "null arg"); if (aResult) { *aResult = mData ? mData->mCombinedArea : mBounds; +#ifdef VERY_NOISY_REFLOW + printf("nsLB::SetCombinedArea(1) %p (%d, %d, %d, %d)\n", + this, aResult->x, aResult->y, aResult->width, aResult->height); +#endif } } diff --git a/mozilla/layout/html/base/src/nsLineBox.h b/mozilla/layout/html/base/src/nsLineBox.h index 190eece891a..e01460eafd4 100644 --- a/mozilla/layout/html/base/src/nsLineBox.h +++ b/mozilla/layout/html/base/src/nsLineBox.h @@ -189,6 +189,7 @@ public: // mImpactedByFloater bit void SetLineIsImpactedByFloater(PRBool aValue) { + NS_ASSERTION((PR_FALSE==aValue || PR_TRUE==aValue), "somebody is playing fast and loose with bools and bits!"); mFlags.mImpactedByFloater = aValue; } PRBool IsImpactedByFloater() const { @@ -197,6 +198,7 @@ public: // mTrimmed bit void SetTrimmed(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); mFlags.mTrimmed = aOn; } PRBool IsTrimmed() const { @@ -205,6 +207,7 @@ public: // mHasPercentageChild bit void SetHasPercentageChild(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); mFlags.mHasPercentageChild = aOn; } PRBool HasPercentageChild() const { @@ -213,6 +216,7 @@ public: // mLineWrapped bit void SetLineWrapped(PRBool aOn) { + NS_ASSERTION((PR_FALSE==aOn || PR_TRUE==aOn), "somebody is playing fast and loose with bools and bits!"); mFlags.mLineWrapped = aOn; } PRBool IsLineWrapped() const { diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp index 1ffea794f96..6f5e6816e70 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ b/mozilla/layout/html/base/src/nsLineLayout.cpp @@ -235,6 +235,10 @@ 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)) { @@ -350,6 +354,10 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY, PRBool aPlacedLeftFloater, nsIFrame* aFloaterFrame) { +#ifdef REALLY_NOISY_REFLOW + printf("nsLL::UpdateBand %d, %d, %d, %d, frame=%p placedLeft=%s\n will set mImpacted to PR_TRUE", + aX, aY, aWidth, aHeight, aFloaterFrame, aPlacedLeftFloater?"true":"false"); +#endif PerSpanData* psd = mRootSpan; NS_PRECONDITION(psd->mX == psd->mLeftEdge, "update-band called late"); #ifdef DEBUG diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index befd8272edf..119c924e5f3 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -22,6 +22,7 @@ #define PL_ARENA_CONST_ALIGN_MASK 3 #include "nsIPresShell.h" +#include "nsISpaceManager.h" #include "nsIPresContext.h" #include "nsIContent.h" #include "nsIDocument.h" @@ -48,6 +49,7 @@ #include "nsIDOMSelection.h" #include "nsISelectionController.h" #include "nsLayoutCID.h" +#include "nsLayoutAtoms.h" #include "nsIDOMRange.h" #include "nsIDOMDocument.h" #include "nsIDOMNode.h" @@ -573,15 +575,7 @@ VerifyStyleTree(nsIPresContext* aPresContext, nsIFrameManager* aFrameManager) * means that you cannot perform logging before then. */ static PRLogModuleInfo* gLogModule; - static PRUint32 gVerifyReflowFlags; - -#define VERIFY_REFLOW_ON 0x01 -#define VERIFY_REFLOW_NOISY 0x02 -#define VERIFY_REFLOW_ALL 0x04 -#define VERIFY_REFLOW_DUMP_COMMANDS 0x08 -#define VERIFY_REFLOW_NOISY_RC 0x10 -#define VERIFY_REFLOW_REALLY_NOISY_RC 0x20 #endif static PRBool gVerifyReflowEnabled; @@ -627,6 +621,12 @@ nsIPresShell::SetVerifyReflowEnable(PRBool aEnabled) gVerifyReflowEnabled = aEnabled; } +NS_LAYOUT PRInt32 +nsIPresShell::GetVerifyReflowFlags() +{ + return gVerifyReflowFlags; +} + //---------------------------------------------------------------------- NS_LAYOUT nsresult @@ -1406,6 +1406,13 @@ PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) #endif } ExitReflowLock(PR_TRUE); + // if the proper flag is set, VerifyReflow now + if (GetVerifyReflowEnable() && (VERIFY_REFLOW_DURING_RESIZE_REFLOW & gVerifyReflowFlags)) + { + mInVerifyReflow = PR_TRUE; + PRBool ok = VerifyIncrementalReflow(); + mInVerifyReflow = PR_FALSE; + } return NS_OK; //XXX this needs to be real. MMP } @@ -3231,6 +3238,8 @@ static PRBool CompareTrees(nsIPresContext* aFirstPresContext, nsIFrame* aFirstFrame, nsIPresContext* aSecondPresContext, nsIFrame* aSecondFrame) { + if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame) + return PR_TRUE; PRBool ok = PR_TRUE; nsIAtom* listName = nsnull; PRInt32 listIndex = 0; @@ -3305,6 +3314,115 @@ CompareTrees(nsIPresContext* aFirstPresContext, nsIFrame* aFirstFrame, break; } + // verify that neither frame has a space manager, + // or they both do and the space managers are equivalent + nsCOMPtrfm1; + nsCOMPtr ps1; + nsISpaceManager *sm1; // note, no ref counting here + aFirstPresContext->GetShell(getter_AddRefs(ps1)); + NS_ASSERTION(ps1, "no pres shell for primary tree!"); + ps1->GetFrameManager(getter_AddRefs(fm1)); + NS_ASSERTION(fm1, "no frame manager for primary tree!"); + fm1->GetFrameProperty((nsIFrame*)k1, nsLayoutAtoms::spaceManagerProperty, + 0, (void **)&sm1); + // look at the test frame + nsCOMPtrfm2; + nsCOMPtr ps2; + nsISpaceManager *sm2; // note, no ref counting here + aSecondPresContext->GetShell(getter_AddRefs(ps2)); + NS_ASSERTION(ps2, "no pres shell for test tree!"); + ps2->GetFrameManager(getter_AddRefs(fm2)); + NS_ASSERTION(fm2, "no frame manager for test tree!"); + fm2->GetFrameProperty((nsIFrame*)k2, nsLayoutAtoms::spaceManagerProperty, + 0, (void **)&sm2); + // now compare the space managers + if (((nsnull == sm1) && (nsnull != sm2)) || + ((nsnull != sm1) && (nsnull == sm2))) { // one is null, and the other is not + ok = PR_FALSE; + LogVerifyMessage(k1, k2, "space managers are not matched\n"); + } + else if (sm1 && sm2) { // both are not null, compare them + // first, compare yMost + nscoord yMost1, yMost2; + nsresult smresult = sm1->YMost(yMost1); + if (NS_ERROR_ABORT != smresult) + { + NS_ASSERTION(NS_SUCCEEDED(smresult), "bad result"); + smresult = sm2->YMost(yMost2); + NS_ASSERTION(NS_SUCCEEDED(smresult), "bad result"); + if (yMost1 != yMost2) { + LogVerifyMessage(k1, k2, "yMost of space managers differs\n"); + } + // now compare bands by sampling + PRInt32 yIncrement = yMost1/100; + if (0==yIncrement) { + yIncrement = 1; // guarantee we make progress in the loop below + } + nscoord yOffset = 0; + for ( ; ok && yOffset < yMost1; yOffset += yIncrement) + { + nscoord small=5, large=100; + nsBandData band1, band2; + nsBandTrapezoid trap1[20], trap2[20]; + band1.mSize = band2.mSize = 20; + band1.mTrapezoids = trap1; + band2.mTrapezoids = trap2; + sm1->GetBandData(yOffset, nsSize(small,small), band1); + sm2->GetBandData(yOffset, nsSize(small,small), band2); + if (band1.mCount != band2.mCount) + { // count mismatch, stop comparing + LogVerifyMessage(k1, k2, "band.mCount of space managers differs\n"); + printf("count1= %d, count2=%d, yOffset = %d, size=%d\n", + band1.mCount, band2.mCount, yOffset, small); + ok = PR_FALSE; + + } + else // band counts match, compare individual traps + { + PRInt32 trapIndex=0; + for ( ;trapIndexGetBandData(yOffset, nsSize(large,large), band1); + sm2->GetBandData(yOffset, nsSize(large,large), band2); + if (band1.mCount != band2.mCount) + { // count mismatch, stop comparing + LogVerifyMessage(k1, k2, "band.mCount of space managers differs\n"); + printf("count1= %d, count2=%d, yOffset = %d, size=%d\n", + band1.mCount, band2.mCount, yOffset, small); + ok = PR_FALSE; + + } + else // band counts match, compare individual traps + { + PRInt32 trapIndex=0; + for ( ; trapIndex