Fixed O(N^2) debug logic bug; speed up paint loop by avoiding painting too much now that we have combined-area (bug 7455, 12297)

git-svn-id: svn://10.0.0.236/trunk@51207 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
kipp%netscape.com
1999-10-19 23:04:19 +00:00
parent bbbab95269
commit 9c72c46de9
12 changed files with 1110 additions and 286 deletions

View File

@@ -56,10 +56,14 @@
#ifdef DEBUG
static PRBool gLamePaintMetrics;
static PRBool gLameReflowMetrics;
static PRBool gNoisy;
static PRBool gNoisyReflow;
static PRBool gNoisyDamageRepair;
static PRBool gNoisyMaxElementSize;
static PRBool gNoisyReflow;
static PRBool gNoisySpaceManager;
static PRBool gVerifyLines;
struct BlockDebugFlags {
const char* name;
@@ -70,6 +74,10 @@ static BlockDebugFlags gFlags[] = {
{ "reflow", &gNoisyReflow },
{ "max-element-size", &gNoisyMaxElementSize },
{ "space-manager", &gNoisySpaceManager },
{ "verify-lines", &gVerifyLines },
{ "damage-repair", &gNoisyDamageRepair },
{ "lame-paint-metrics", &gLamePaintMetrics },
{ "lame-reflow-metrics", &gLameReflowMetrics },
};
#define NUM_DEBUG_FLAGS (sizeof(gFlags) / sizeof(gFlags[0]))
@@ -132,7 +140,6 @@ InitDebugFlags()
#undef NOISY_FLOATER_CLEARING
#undef NOISY_FINAL_SIZE
#undef NOISY_REMOVE_FRAME
#undef NOISY_DAMAGE_REPAIR
#undef NOISY_COMBINED_AREA
#undef NOISY_VERTICAL_MARGINS
#undef NOISY_REFLOW_REASON
@@ -387,6 +394,10 @@ public:
return mBand.GetFloaterCount();
}
nsLineBox* NewLineBox(nsIFrame* aFrame, PRInt32 aCount, PRBool aIsBlock);
void FreeLineBox(nsLineBox* aLine);
//----------------------------------------
// This state is the "global" state computed once for the reflow of
@@ -485,6 +496,9 @@ public:
// The current band data for the current Y coordinate
nsBlockBandData mBand;
// List of free nsLineBox's
nsLineBox* mFreeLineList;
//----------------------------------------
// Temporary line-reflow state. This state is used during the reflow
@@ -536,6 +550,7 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
mApplyTopMargin(PR_FALSE),
mNextRCFrame(nsnull),
mPrevBottomMargin(0),
mFreeLineList(nsnull),
mLineNumber(0)
{
mSpaceManager = aReflowState.mSpaceManager;
@@ -631,6 +646,40 @@ nsBlockReflowState::~nsBlockReflowState()
// Restore the coordinate system
const nsMargin& borderPadding = BorderPadding();
mSpaceManager->Translate(-borderPadding.left, -borderPadding.top);
// Release any line box's that are laying around
nsLineBox* line = mFreeLineList;
while (line) {
nsLineBox* next = line->mNext;
delete line;
line = next;
}
}
nsLineBox*
nsBlockReflowState::NewLineBox(nsIFrame* aFrame,
PRInt32 aCount,
PRBool aIsBlock)
{
nsLineBox* newLine;
if (mFreeLineList) {
newLine = mFreeLineList;
mFreeLineList = newLine->mNext;
newLine->Reset(aFrame, aCount, aIsBlock);
}
else {
newLine = new nsLineBox(aFrame, aCount, aIsBlock);
}
return newLine;
}
void
nsBlockReflowState::FreeLineBox(nsLineBox* aLine)
{
if (aLine) {
aLine->mNext = mFreeLineList;
mFreeLineList = aLine;
}
}
// Compute the amount of available space for reflowing a block frame
@@ -1293,14 +1342,22 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
nsReflowStatus& aStatus)
{
#ifdef DEBUG
if (gNoisy) {
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
ListTag(stdout);
printf(": begin reflow availSize=%d,%d computedSize=%d,%d\n",
aReflowState.availableWidth, aReflowState.availableHeight,
aReflowState.mComputedWidth, aReflowState.mComputedHeight);
}
if (gNoisy) {
gNoiseIndent++;
}
PRTime start;
PRInt32 ctc;
if (gLameReflowMetrics) {
start = PR_Now();
ctc = nsLineBox::GetCtorCount();
}
#endif
if (IsFrameTreeTooDeep(aReflowState, aMetrics)) {
@@ -1530,6 +1587,8 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
#ifdef DEBUG
if (gNoisy) {
gNoiseIndent--;
}
if (gNoisyReflow) {
IndentBy(stdout, gNoiseIndent);
ListTag(stdout);
printf(": status=%x (%scomplete) metrics=%d,%d carriedMargin=%d",
@@ -1550,6 +1609,25 @@ nsBlockFrame::Reflow(nsIPresContext& aPresContext,
}
printf("\n");
}
if (gLameReflowMetrics) {
PRTime end = PR_Now();
PRInt32 ectc = nsLineBox::GetCtorCount();
PRInt32 numLines = nsLineBox::ListLength(mLines);
if (!numLines) numLines = 1;
PRTime delta, perLineDelta, lines;
LL_I2L(lines, numLines);
LL_SUB(delta, end, start);
LL_DIV(perLineDelta, delta, lines);
ListTag(stdout);
char buf[400];
PR_snprintf(buf, sizeof(buf),
": %lld elapsed (%lld per line) (%d lines; %d new lines)",
delta, perLineDelta, numLines, ectc - ctc);
printf("%s\n", buf);
}
#endif
return rv;
}
@@ -1962,7 +2040,7 @@ nsBlockFrame::PrepareChildIncrementalReflow(nsBlockReflowState& aState)
}
nsresult
nsBlockFrame::UpdateBulletPosition()
nsBlockFrame::UpdateBulletPosition(nsBlockReflowState& aState)
{
if (nsnull == mBullet) {
// Don't bother if there is no bullet
@@ -1974,7 +2052,7 @@ nsBlockFrame::UpdateBulletPosition()
if (HaveOutsideBullet()) {
// We now have an inside bullet, but used to have an outside
// bullet. Adjust the frame line list
nsLineBox* line = new nsLineBox(mBullet, 1, PR_FALSE);
nsLineBox* line = aState.NewLineBox(mBullet, 1, PR_FALSE);
if (!line) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -1997,7 +2075,7 @@ nsBlockFrame::UpdateBulletPosition()
mLines->SetChildCount(count);
if (0 == count) {
nsLineBox* nextLine = mLines->mNext;
delete mLines;
aState.FreeLineBox(mLines);
mLines = nextLine;
if (nsnull != nextLine) {
nextLine->MarkDirty();
@@ -2020,7 +2098,7 @@ nsBlockFrame::UpdateBulletPosition()
nsresult
nsBlockFrame::PrepareStyleChangedReflow(nsBlockReflowState& aState)
{
nsresult rv = UpdateBulletPosition();
nsresult rv = UpdateBulletPosition(aState);
// Mark everything dirty
nsLineBox* line = mLines;
@@ -2387,7 +2465,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
if (0 == line->GetChildCount()) {
// The line is empty. Try the next one.
NS_ASSERTION(nsnull == line->mFirstChild, "bad empty line");
delete line;
aState.FreeLineBox(line);
continue;
}
@@ -2478,7 +2556,7 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState,
NS_ASSERTION(aState.mPrevLine->mNext == aLine, "bad prev-line");
aState.mPrevLine->mNext = aLine->mNext;
}
delete aLine;
aState.FreeLineBox(aLine);
}
}
@@ -2663,7 +2741,7 @@ nsBlockFrame::PullFrame(nsBlockReflowState& aState,
else {
// Free up the fromLine now that it's empty
*aFromList = fromLine->mNext;
delete fromLine;
aState.FreeLineBox(fromLine);
}
// Change geometric parents
@@ -3181,7 +3259,7 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState,
// made one.
if (madeContinuation) {
frame->GetNextSibling(&frame);
nsLineBox* line = new nsLineBox(frame, 1, PR_TRUE);
nsLineBox* line = aState.NewLineBox(frame, 1, PR_TRUE);
if (nsnull == line) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -3465,7 +3543,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
// uses DoRemoveFrame?
aLine->mNext = nextLine->mNext;
NS_ASSERTION(nsnull == nextLine->mFirstChild, "bad empty line");
delete nextLine;
aState.FreeLineBox(nextLine);
nextLine = aLine->mNext;
}
break;
@@ -3736,7 +3814,7 @@ nsBlockFrame::SplitLine(nsBlockReflowState& aState,
NS_ABORT_IF_FALSE(nsnull != aFrame, "whoops");
// Put frames being split out into their own line
nsLineBox* newLine = new nsLineBox(aFrame, pushCount, PR_FALSE);
nsLineBox* newLine = aState.NewLineBox(aFrame, pushCount, PR_FALSE);
if (!newLine) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -5436,7 +5514,7 @@ nsBlockFrame::GetSkipSides() const
return skip;
}
#ifdef NOISY_DAMAGE_REPAIR
#ifdef DEBUG
static void ComputeCombinedArea(nsLineBox* aLine,
nscoord aWidth, nscoord aHeight,
nsRect& aResult)
@@ -5445,10 +5523,12 @@ static void ComputeCombinedArea(nsLineBox* aLine,
while (nsnull != aLine) {
// Compute min and max x/y values for the reflowed frame's
// combined areas
nscoord x = aLine->mCombinedArea.x;
nscoord y = aLine->mCombinedArea.y;
nscoord xmost = x + aLine->mCombinedArea.width;
nscoord ymost = y + aLine->mCombinedArea.height;
nsRect lineCombinedArea;
aLine->GetCombinedArea(&lineCombinedArea);
nscoord x = lineCombinedArea.x;
nscoord y = lineCombinedArea.y;
nscoord xmost = x + lineCombinedArea.width;
nscoord ymost = y + lineCombinedArea.height;
if (x < xa) {
xa = x;
}
@@ -5481,17 +5561,19 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
return NS_OK;
}
#ifdef NOISY_DAMAGE_REPAIR
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
PRInt32 depth = GetDepth();
nsRect ca;
ComputeCombinedArea(mLines, mRect.width, mRect.height, ca);
nsFrame::IndentBy(stdout, depth);
ListTag(stdout);
printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
mRect.x, mRect.y, mRect.width, mRect.height,
aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height,
ca.x, ca.y, ca.width, ca.height);
#ifdef DEBUG
if (gNoisyDamageRepair) {
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
PRInt32 depth = GetDepth();
nsRect ca;
ComputeCombinedArea(mLines, mRect.width, mRect.height, ca);
nsFrame::IndentBy(stdout, depth);
ListTag(stdout);
printf(": bounds=%d,%d,%d,%d dirty=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
mRect.x, mRect.y, mRect.width, mRect.height,
aDirtyRect.x, aDirtyRect.y, aDirtyRect.width, aDirtyRect.height,
ca.x, ca.y, ca.width, ca.height);
}
}
#endif
@@ -5514,16 +5596,15 @@ nsBlockFrame::Paint(nsIPresContext& aPresContext,
const nsStyleSpacing* spacing = (const nsStyleSpacing*)
mStyleContext->GetStyleData(eStyleStruct_Spacing);
// Paint background and border
// Paint background, border and outline
nsRect rect(0, 0, mRect.width, mRect.height);
nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this,
aDirtyRect, rect, *color, *spacing, 0, 0);
nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this,
aDirtyRect, rect, *spacing, mStyleContext,
skipSides);
nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
aDirtyRect, rect, *spacing, mStyleContext, 0);
nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, this,
aDirtyRect, rect, *spacing, mStyleContext, 0);
}
// Child elements have the opportunity to override the visibility
@@ -5614,22 +5695,31 @@ nsBlockFrame::PaintChildren(nsIPresContext& aPresContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer)
{
#ifdef NOISY_DAMAGE_REPAIR
#ifdef DEBUG
PRInt32 depth = 0;
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
depth = GetDepth();
if (gNoisyDamageRepair) {
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
depth = GetDepth();
}
}
PRTime start;
PRInt32 drawnLines;
if (gLamePaintMetrics) {
start = PR_Now();
drawnLines = 0;
}
#endif
for (nsLineBox* line = mLines; nsnull != line; line = line->mNext) {
// If the line has outside children or if the line intersects the
// dirty rect then paint the children in the line.
nsRect lineCombinedArea;
line->GetCombinedArea(&lineCombinedArea);
if ((NS_FRAME_OUTSIDE_CHILDREN & mState) ||
!((lineCombinedArea.YMost() <= aDirtyRect.y) ||
(lineCombinedArea.y >= aDirtyRect.YMost()))) {
#ifdef NOISY_DAMAGE_REPAIR
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
// If the line's combined area (which includes child frames that
// stick outside of the line's bounding box or our bounding box)
// intersects the dirty rect then paint the line.
if (line->CombinedAreaIntersects(aDirtyRect)) {
#ifdef DEBUG
if (gNoisyDamageRepair &&
(NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) {
nsRect lineCombinedArea;
line->GetCombinedArea(&lineCombinedArea);
nsFrame::IndentBy(stdout, depth+1);
printf("draw line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
line, line->mBounds.x, line->mBounds.y,
@@ -5637,6 +5727,9 @@ nsBlockFrame::PaintChildren(nsIPresContext& aPresContext,
lineCombinedArea.x, lineCombinedArea.y,
lineCombinedArea.width, lineCombinedArea.height);
}
if (gLamePaintMetrics) {
drawnLines++;
}
#endif
nsIFrame* kid = line->mFirstChild;
PRInt32 n = line->GetChildCount();
@@ -5646,9 +5739,12 @@ nsBlockFrame::PaintChildren(nsIPresContext& aPresContext,
kid->GetNextSibling(&kid);
}
}
#ifdef NOISY_DAMAGE_REPAIR
#ifdef DEBUG
else {
if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
if (gNoisyDamageRepair &&
(NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer)) {
nsRect lineCombinedArea;
line->GetCombinedArea(&lineCombinedArea);
nsFrame::IndentBy(stdout, depth+1);
printf("skip line=%p bounds=%d,%d,%d,%d ca=%d,%d,%d,%d\n",
line, line->mBounds.x, line->mBounds.y,
@@ -5667,6 +5763,27 @@ nsBlockFrame::PaintChildren(nsIPresContext& aPresContext,
aWhichLayer);
}
}
#ifdef DEBUG
if (gLamePaintMetrics) {
PRTime end = PR_Now();
PRInt32 numLines = nsLineBox::ListLength(mLines);
if (!numLines) numLines = 1;
PRTime lines, deltaPerLine, delta;
LL_I2L(lines, numLines);
LL_SUB(delta, end, start);
LL_DIV(deltaPerLine, delta, lines);
ListTag(stdout);
char buf[400];
PR_snprintf(buf, sizeof(buf),
": %lld elapsed (%lld per line) lines=%d drawn=%d skip=%d",
delta, deltaPerLine,
numLines, drawnLines, numLines - drawnLines);
printf("%s\n", buf);
}
#endif
}
@@ -6521,6 +6638,9 @@ nsAnonymousBlockFrame::RemoveFramesFrom(nsIFrame* aFrame)
void
nsBlockFrame::VerifyLines(PRBool aFinalCheckOK)
{
if (!gVerifyLines) {
return;
}
nsLineBox* line = mLines;
if (!line) {
return;