Tweaked the line-breaking logic so that certain floater situations don't trigger crashes
This commit is contained in:
@@ -38,6 +38,8 @@
|
|||||||
#undef REALLY_NOISY_PUSHING
|
#undef REALLY_NOISY_PUSHING
|
||||||
#define DEBUG_ADD_TEXT
|
#define DEBUG_ADD_TEXT
|
||||||
#undef NOISY_MAX_ELEMENT_SIZE
|
#undef NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef NOISY_CAN_PLACE_FRAME
|
||||||
#else
|
#else
|
||||||
#undef NOISY_HORIZONTAL_ALIGN
|
#undef NOISY_HORIZONTAL_ALIGN
|
||||||
#undef REALLY_NOISY_HORIZONTAL_ALIGN
|
#undef REALLY_NOISY_HORIZONTAL_ALIGN
|
||||||
@@ -49,6 +51,8 @@
|
|||||||
#undef REALLY_NOISY_PUSHING
|
#undef REALLY_NOISY_PUSHING
|
||||||
#undef DEBUG_ADD_TEXT
|
#undef DEBUG_ADD_TEXT
|
||||||
#undef NOISY_MAX_ELEMENT_SIZE
|
#undef NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef NOISY_CAN_PLACE_FRAME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsTextRun::nsTextRun()
|
nsTextRun::nsTextRun()
|
||||||
@@ -228,6 +232,7 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
|||||||
mPlacedFloaters = 0;
|
mPlacedFloaters = 0;
|
||||||
mImpactedByFloaters = aImpactedByFloaters;
|
mImpactedByFloaters = aImpactedByFloaters;
|
||||||
mTotalPlacedFrames = 0;
|
mTotalPlacedFrames = 0;
|
||||||
|
mCanPlaceFloater = PR_TRUE;
|
||||||
mSpanDepth = 0;
|
mSpanDepth = 0;
|
||||||
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
||||||
|
|
||||||
@@ -294,6 +299,13 @@ nsLineLayout::EndLineReflow()
|
|||||||
mCurrentSpan = mRootSpan = mLastSpan = nsnull;
|
mCurrentSpan = mRootSpan = mLastSpan = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX swtich to a single mAvailLineWidth that we adjust as each frame
|
||||||
|
// on the line is placed. Each span can still have a per-span mX that
|
||||||
|
// tracks where a child frame is going in its span; they don't need a
|
||||||
|
// per-span mLeftEdge?
|
||||||
|
|
||||||
|
// XXX currently broken because it doesn't recurse through the nested
|
||||||
|
// spans that are currently open to update their right edge.
|
||||||
void
|
void
|
||||||
nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
||||||
nscoord aWidth, nscoord aHeight,
|
nscoord aWidth, nscoord aHeight,
|
||||||
@@ -315,11 +327,19 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
|||||||
aHeight = NS_UNCONSTRAINEDSIZE;
|
aHeight = NS_UNCONSTRAINEDSIZE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Compute the difference between last times width and the new width
|
||||||
|
nscoord deltaWidth = 0;
|
||||||
|
if (NS_UNCONSTRAINEDSIZE != psd->mRightEdge) {
|
||||||
|
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aWidth, "switched constraints");
|
||||||
|
nscoord oldWidth = psd->mRightEdge - psd->mLeftEdge;
|
||||||
|
deltaWidth = aWidth - oldWidth;
|
||||||
|
}
|
||||||
#ifdef NOISY_REFLOW
|
#ifdef NOISY_REFLOW
|
||||||
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
||||||
printf(": UpdateBand: %d,%d,%d,%d %s\n",
|
printf(": UpdateBand: %d,%d,%d,%d deltaWidth=%d %s floater\n",
|
||||||
aX, aY, aWidth, aHeight,
|
aX, aY, aWidth, aHeight, deltaWidth,
|
||||||
aPlacedLeftFloater ? "placed-left-floater" : "");
|
aPlacedLeftFloater ? "left" : "right");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
psd->mLeftEdge = aX;
|
psd->mLeftEdge = aX;
|
||||||
@@ -340,6 +360,27 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
|||||||
mUpdatedBand = PR_TRUE;
|
mUpdatedBand = PR_TRUE;
|
||||||
mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT);
|
mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT);
|
||||||
mImpactedByFloaters = PR_TRUE;
|
mImpactedByFloaters = PR_TRUE;
|
||||||
|
|
||||||
|
// Now update all of the open spans...
|
||||||
|
psd = mCurrentSpan;
|
||||||
|
while (psd != mRootSpan) {
|
||||||
|
NS_ASSERTION(nsnull != psd, "null ptr");
|
||||||
|
if (nsnull == psd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NS_ASSERTION(psd->mX == psd->mLeftEdge, "bad floater placement");
|
||||||
|
if (NS_UNCONSTRAINEDSIZE == aWidth) {
|
||||||
|
psd->mRightEdge = NS_UNCONSTRAINEDSIZE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
psd->mRightEdge += deltaWidth;
|
||||||
|
}
|
||||||
|
#ifdef NOISY_REFLOW
|
||||||
|
printf(" span %p: oldRightEdge=%d newRightEdge=%d\n",
|
||||||
|
psd->mRightEdge - deltaWidth, psd->mRightEdge);
|
||||||
|
#endif
|
||||||
|
psd = psd->mParent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Only adjust the outermost frames (the ones that are direct
|
// Note: Only adjust the outermost frames (the ones that are direct
|
||||||
@@ -648,6 +689,27 @@ nsLineLayout::NewPerFrameData(PerFrameData** aResult)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsLineLayout::CanPlaceFloaterNow() const
|
||||||
|
{
|
||||||
|
return mCanPlaceFloater;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsLineLayout::LineIsEmpty() const
|
||||||
|
{
|
||||||
|
return 0 == mTotalPlacedFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsLineLayout::LineIsBreakable() const
|
||||||
|
{
|
||||||
|
if ((0 != mTotalPlacedFrames) || mImpactedByFloaters) {
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||||
nsIFrame** aNextRCFrame,
|
nsIFrame** aNextRCFrame,
|
||||||
@@ -737,7 +799,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||||||
// Capture this state *before* we reflow the frame in case it clears
|
// Capture this state *before* we reflow the frame in case it clears
|
||||||
// the state out. We need to know how to treat the current frame
|
// the state out. We need to know how to treat the current frame
|
||||||
// when breaking.
|
// when breaking.
|
||||||
PRBool notSafeToBreak = (mTotalPlacedFrames == 0) || InWord();
|
PRBool notSafeToBreak = CanPlaceFloaterNow() || InWord();
|
||||||
|
|
||||||
// Apply left margins (as appropriate) to the frame computing the
|
// Apply left margins (as appropriate) to the frame computing the
|
||||||
// new starting x,y coordinates for the frame.
|
// new starting x,y coordinates for the frame.
|
||||||
@@ -778,49 +840,60 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||||||
htmlReflow->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
htmlReflow->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
||||||
mSpaceManager->Translate(-tx, -ty);
|
mSpaceManager->Translate(-tx, -ty);
|
||||||
|
|
||||||
#ifdef DEBUG_kipp
|
#ifdef DEBUG
|
||||||
if (CRAZY_WIDTH(metrics.width) || CRAZY_HEIGHT(metrics.height)) {
|
// Note: break-before means ignore the reflow metrics since the
|
||||||
printf("nsBlockReflowContext: ");
|
// frame will be reflowed another time.
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
||||||
printf(" metrics=%d,%d!\n", metrics.width, metrics.height);
|
if (CRAZY_WIDTH(metrics.width) || CRAZY_HEIGHT(metrics.height)) {
|
||||||
}
|
printf("nsLineLayout: ");
|
||||||
if (mComputeMaxElementSize &&
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
((nscoord(0xdeadbeef) == metrics.maxElementSize->width) ||
|
printf(" metrics=%d,%d!\n", metrics.width, metrics.height);
|
||||||
(nscoord(0xdeadbeef) == metrics.maxElementSize->height))) {
|
}
|
||||||
printf("nsLineLayout: ");
|
if (mComputeMaxElementSize &&
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
((nscoord(0xdeadbeef) == metrics.maxElementSize->width) ||
|
||||||
printf(" didn't set max-element-size!\n");
|
(nscoord(0xdeadbeef) == metrics.maxElementSize->height))) {
|
||||||
metrics.maxElementSize->width = 0;
|
printf("nsLineLayout: ");
|
||||||
metrics.maxElementSize->height = 0;
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
}
|
printf(" didn't set max-element-size!\n");
|
||||||
if (mComputeMaxElementSize &&
|
metrics.maxElementSize->width = 0;
|
||||||
((metrics.maxElementSize->width > metrics.width) ||
|
metrics.maxElementSize->height = 0;
|
||||||
(metrics.maxElementSize->height > metrics.height))) {
|
}
|
||||||
printf("nsLineLayout: ");
|
#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
// Note: there are common reflow situations where this *correctly*
|
||||||
printf(": WARNING: maxElementSize=%d,%d > metrics=%d,%d\n",
|
// occurs; so only enable this debug noise when you really need to
|
||||||
metrics.maxElementSize->width,
|
// analyze in detail.
|
||||||
metrics.maxElementSize->height,
|
if (mComputeMaxElementSize &&
|
||||||
metrics.width, metrics.height);
|
((metrics.maxElementSize->width > metrics.width) ||
|
||||||
}
|
(metrics.maxElementSize->height > metrics.height))) {
|
||||||
if ((metrics.width == nscoord(0xdeadbeef)) ||
|
printf("nsLineLayout: ");
|
||||||
(metrics.height == nscoord(0xdeadbeef)) ||
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
(metrics.ascent == nscoord(0xdeadbeef)) ||
|
printf(": WARNING: maxElementSize=%d,%d > metrics=%d,%d\n",
|
||||||
(metrics.descent == nscoord(0xdeadbeef))) {
|
metrics.maxElementSize->width,
|
||||||
printf("nsLineLayout: ");
|
metrics.maxElementSize->height,
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
metrics.width, metrics.height);
|
||||||
printf(" didn't set whad %d,%d,%d,%d!\n", metrics.width, metrics.height,
|
}
|
||||||
metrics.ascent, metrics.descent);
|
#endif
|
||||||
|
if ((metrics.width == nscoord(0xdeadbeef)) ||
|
||||||
|
(metrics.height == nscoord(0xdeadbeef)) ||
|
||||||
|
(metrics.ascent == nscoord(0xdeadbeef)) ||
|
||||||
|
(metrics.descent == nscoord(0xdeadbeef))) {
|
||||||
|
printf("nsLineLayout: ");
|
||||||
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
|
printf(" didn't set whad %d,%d,%d,%d!\n", metrics.width, metrics.height,
|
||||||
|
metrics.ascent, metrics.descent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||||
if (mComputeMaxElementSize) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
||||||
printf(" ");
|
if (mComputeMaxElementSize) {
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
printf(" ");
|
||||||
printf(": maxElementSize=%d,%d wh=%d,%d,\n",
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
metrics.maxElementSize->width,
|
printf(": maxElementSize=%d,%d wh=%d,%d,\n",
|
||||||
metrics.maxElementSize->height,
|
metrics.maxElementSize->width,
|
||||||
metrics.width, metrics.height);
|
metrics.maxElementSize->height,
|
||||||
|
metrics.width, metrics.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -907,8 +980,7 @@ nsLineLayout::ApplyLeftMargin(PerFrameData* pfd,
|
|||||||
// of a block then see if the text-indent property amounts to
|
// of a block then see if the text-indent property amounts to
|
||||||
// anything.
|
// anything.
|
||||||
nscoord indent = 0;
|
nscoord indent = 0;
|
||||||
if (InBlockContext() && (0 == mLineNumber) &&
|
if (InBlockContext() && (0 == mLineNumber) && CanPlaceFloaterNow()) {
|
||||||
(0 == mTotalPlacedFrames)) {
|
|
||||||
nsStyleUnit unit = mStyleText->mTextIndent.GetUnit();
|
nsStyleUnit unit = mStyleText->mTextIndent.GetUnit();
|
||||||
if (eStyleUnit_Coord == unit) {
|
if (eStyleUnit_Coord == unit) {
|
||||||
indent = mStyleText->mTextIndent.GetCoordValue();
|
indent = mStyleText->mTextIndent.GetCoordValue();
|
||||||
@@ -1012,11 +1084,26 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
if (nsnull != psd->mFrame) {
|
||||||
|
nsFrame::ListTag(stdout, psd->mFrame->mFrame);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
||||||
|
}
|
||||||
|
printf(": aNotSafeToBreak=%s frame=", aNotSafeToBreak ? "true" : "false");
|
||||||
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
||||||
|
printf(" frameWidth=%d\n", pfd->mBounds.XMost() + rightMargin - psd->mX);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set outside to PR_TRUE if the result of the reflow leads to the
|
// Set outside to PR_TRUE if the result of the reflow leads to the
|
||||||
// frame sticking outside of our available area.
|
// frame sticking outside of our available area.
|
||||||
PRBool outside = pfd->mBounds.XMost() + rightMargin > psd->mRightEdge;
|
PRBool outside = pfd->mBounds.XMost() + rightMargin > psd->mRightEdge;
|
||||||
if (!outside) {
|
if (!outside) {
|
||||||
// If it fits, it fits
|
// If it fits, it fits
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> inside\n");
|
||||||
|
#endif
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1024,6 +1111,9 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||||||
// allow it to fit anyway.
|
// allow it to fit anyway.
|
||||||
if (0 == pfd->mMargin.left + pfd->mBounds.width + rightMargin) {
|
if (0 == pfd->mMargin.left + pfd->mBounds.width + rightMargin) {
|
||||||
// Empty frames always fit right where they are
|
// Empty frames always fit right where they are
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> empty frame fits\n");
|
||||||
|
#endif
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1032,10 +1122,22 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||||||
// the line. If the line isn't impacted by a floater then the
|
// the line. If the line isn't impacted by a floater then the
|
||||||
// current frame fits.
|
// current frame fits.
|
||||||
if (!mImpactedByFloaters) {
|
if (!mImpactedByFloaters) {
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> not-safe and not-impacted fits: ");
|
||||||
|
PerSpanData* psd = mCurrentSpan;
|
||||||
|
while (nsnull != psd) {
|
||||||
|
printf("<psd=%p x=%d left=%d> ", psd, psd->mX, psd->mLeftEdge);
|
||||||
|
psd = psd->mParent;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> didn't fit\n");
|
||||||
|
#endif
|
||||||
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
@@ -1078,11 +1180,12 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
|||||||
mEndsInWhiteSpace = PR_FALSE;
|
mEndsInWhiteSpace = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the bottom margin to apply. Note that the margin only
|
// Count the number of frames on the line...
|
||||||
// applies if the frame ends up with a non-zero height.
|
mTotalPlacedFrames++;
|
||||||
if (!emptyFrame) {
|
if (0 != psd->mX) {
|
||||||
// Inform line layout that we have placed a non-empty frame
|
// As soon as a frame placed on the line advances an X coordinate
|
||||||
mTotalPlacedFrames++;
|
// of any span we can no longer place a floater on the line.
|
||||||
|
mCanPlaceFloater = PR_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
#undef REALLY_NOISY_PUSHING
|
#undef REALLY_NOISY_PUSHING
|
||||||
#define DEBUG_ADD_TEXT
|
#define DEBUG_ADD_TEXT
|
||||||
#undef NOISY_MAX_ELEMENT_SIZE
|
#undef NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef NOISY_CAN_PLACE_FRAME
|
||||||
#else
|
#else
|
||||||
#undef NOISY_HORIZONTAL_ALIGN
|
#undef NOISY_HORIZONTAL_ALIGN
|
||||||
#undef REALLY_NOISY_HORIZONTAL_ALIGN
|
#undef REALLY_NOISY_HORIZONTAL_ALIGN
|
||||||
@@ -49,6 +51,8 @@
|
|||||||
#undef REALLY_NOISY_PUSHING
|
#undef REALLY_NOISY_PUSHING
|
||||||
#undef DEBUG_ADD_TEXT
|
#undef DEBUG_ADD_TEXT
|
||||||
#undef NOISY_MAX_ELEMENT_SIZE
|
#undef NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||||
|
#undef NOISY_CAN_PLACE_FRAME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nsTextRun::nsTextRun()
|
nsTextRun::nsTextRun()
|
||||||
@@ -228,6 +232,7 @@ nsLineLayout::BeginLineReflow(nscoord aX, nscoord aY,
|
|||||||
mPlacedFloaters = 0;
|
mPlacedFloaters = 0;
|
||||||
mImpactedByFloaters = aImpactedByFloaters;
|
mImpactedByFloaters = aImpactedByFloaters;
|
||||||
mTotalPlacedFrames = 0;
|
mTotalPlacedFrames = 0;
|
||||||
|
mCanPlaceFloater = PR_TRUE;
|
||||||
mSpanDepth = 0;
|
mSpanDepth = 0;
|
||||||
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
mMaxTopBoxHeight = mMaxBottomBoxHeight = 0;
|
||||||
|
|
||||||
@@ -294,6 +299,13 @@ nsLineLayout::EndLineReflow()
|
|||||||
mCurrentSpan = mRootSpan = mLastSpan = nsnull;
|
mCurrentSpan = mRootSpan = mLastSpan = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX swtich to a single mAvailLineWidth that we adjust as each frame
|
||||||
|
// on the line is placed. Each span can still have a per-span mX that
|
||||||
|
// tracks where a child frame is going in its span; they don't need a
|
||||||
|
// per-span mLeftEdge?
|
||||||
|
|
||||||
|
// XXX currently broken because it doesn't recurse through the nested
|
||||||
|
// spans that are currently open to update their right edge.
|
||||||
void
|
void
|
||||||
nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
||||||
nscoord aWidth, nscoord aHeight,
|
nscoord aWidth, nscoord aHeight,
|
||||||
@@ -315,11 +327,19 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
|||||||
aHeight = NS_UNCONSTRAINEDSIZE;
|
aHeight = NS_UNCONSTRAINEDSIZE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Compute the difference between last times width and the new width
|
||||||
|
nscoord deltaWidth = 0;
|
||||||
|
if (NS_UNCONSTRAINEDSIZE != psd->mRightEdge) {
|
||||||
|
NS_ASSERTION(NS_UNCONSTRAINEDSIZE != aWidth, "switched constraints");
|
||||||
|
nscoord oldWidth = psd->mRightEdge - psd->mLeftEdge;
|
||||||
|
deltaWidth = aWidth - oldWidth;
|
||||||
|
}
|
||||||
#ifdef NOISY_REFLOW
|
#ifdef NOISY_REFLOW
|
||||||
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
||||||
printf(": UpdateBand: %d,%d,%d,%d %s\n",
|
printf(": UpdateBand: %d,%d,%d,%d deltaWidth=%d %s floater\n",
|
||||||
aX, aY, aWidth, aHeight,
|
aX, aY, aWidth, aHeight, deltaWidth,
|
||||||
aPlacedLeftFloater ? "placed-left-floater" : "");
|
aPlacedLeftFloater ? "left" : "right");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
psd->mLeftEdge = aX;
|
psd->mLeftEdge = aX;
|
||||||
@@ -340,6 +360,27 @@ nsLineLayout::UpdateBand(nscoord aX, nscoord aY,
|
|||||||
mUpdatedBand = PR_TRUE;
|
mUpdatedBand = PR_TRUE;
|
||||||
mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT);
|
mPlacedFloaters |= (aPlacedLeftFloater ? PLACED_LEFT : PLACED_RIGHT);
|
||||||
mImpactedByFloaters = PR_TRUE;
|
mImpactedByFloaters = PR_TRUE;
|
||||||
|
|
||||||
|
// Now update all of the open spans...
|
||||||
|
psd = mCurrentSpan;
|
||||||
|
while (psd != mRootSpan) {
|
||||||
|
NS_ASSERTION(nsnull != psd, "null ptr");
|
||||||
|
if (nsnull == psd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
NS_ASSERTION(psd->mX == psd->mLeftEdge, "bad floater placement");
|
||||||
|
if (NS_UNCONSTRAINEDSIZE == aWidth) {
|
||||||
|
psd->mRightEdge = NS_UNCONSTRAINEDSIZE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
psd->mRightEdge += deltaWidth;
|
||||||
|
}
|
||||||
|
#ifdef NOISY_REFLOW
|
||||||
|
printf(" span %p: oldRightEdge=%d newRightEdge=%d\n",
|
||||||
|
psd->mRightEdge - deltaWidth, psd->mRightEdge);
|
||||||
|
#endif
|
||||||
|
psd = psd->mParent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Only adjust the outermost frames (the ones that are direct
|
// Note: Only adjust the outermost frames (the ones that are direct
|
||||||
@@ -648,6 +689,27 @@ nsLineLayout::NewPerFrameData(PerFrameData** aResult)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsLineLayout::CanPlaceFloaterNow() const
|
||||||
|
{
|
||||||
|
return mCanPlaceFloater;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsLineLayout::LineIsEmpty() const
|
||||||
|
{
|
||||||
|
return 0 == mTotalPlacedFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsLineLayout::LineIsBreakable() const
|
||||||
|
{
|
||||||
|
if ((0 != mTotalPlacedFrames) || mImpactedByFloaters) {
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
||||||
nsIFrame** aNextRCFrame,
|
nsIFrame** aNextRCFrame,
|
||||||
@@ -737,7 +799,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||||||
// Capture this state *before* we reflow the frame in case it clears
|
// Capture this state *before* we reflow the frame in case it clears
|
||||||
// the state out. We need to know how to treat the current frame
|
// the state out. We need to know how to treat the current frame
|
||||||
// when breaking.
|
// when breaking.
|
||||||
PRBool notSafeToBreak = (mTotalPlacedFrames == 0) || InWord();
|
PRBool notSafeToBreak = CanPlaceFloaterNow() || InWord();
|
||||||
|
|
||||||
// Apply left margins (as appropriate) to the frame computing the
|
// Apply left margins (as appropriate) to the frame computing the
|
||||||
// new starting x,y coordinates for the frame.
|
// new starting x,y coordinates for the frame.
|
||||||
@@ -778,49 +840,60 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||||||
htmlReflow->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
htmlReflow->Reflow(mPresContext, metrics, reflowState, aReflowStatus);
|
||||||
mSpaceManager->Translate(-tx, -ty);
|
mSpaceManager->Translate(-tx, -ty);
|
||||||
|
|
||||||
#ifdef DEBUG_kipp
|
#ifdef DEBUG
|
||||||
if (CRAZY_WIDTH(metrics.width) || CRAZY_HEIGHT(metrics.height)) {
|
// Note: break-before means ignore the reflow metrics since the
|
||||||
printf("nsBlockReflowContext: ");
|
// frame will be reflowed another time.
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
||||||
printf(" metrics=%d,%d!\n", metrics.width, metrics.height);
|
if (CRAZY_WIDTH(metrics.width) || CRAZY_HEIGHT(metrics.height)) {
|
||||||
}
|
printf("nsLineLayout: ");
|
||||||
if (mComputeMaxElementSize &&
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
((nscoord(0xdeadbeef) == metrics.maxElementSize->width) ||
|
printf(" metrics=%d,%d!\n", metrics.width, metrics.height);
|
||||||
(nscoord(0xdeadbeef) == metrics.maxElementSize->height))) {
|
}
|
||||||
printf("nsLineLayout: ");
|
if (mComputeMaxElementSize &&
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
((nscoord(0xdeadbeef) == metrics.maxElementSize->width) ||
|
||||||
printf(" didn't set max-element-size!\n");
|
(nscoord(0xdeadbeef) == metrics.maxElementSize->height))) {
|
||||||
metrics.maxElementSize->width = 0;
|
printf("nsLineLayout: ");
|
||||||
metrics.maxElementSize->height = 0;
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
}
|
printf(" didn't set max-element-size!\n");
|
||||||
if (mComputeMaxElementSize &&
|
metrics.maxElementSize->width = 0;
|
||||||
((metrics.maxElementSize->width > metrics.width) ||
|
metrics.maxElementSize->height = 0;
|
||||||
(metrics.maxElementSize->height > metrics.height))) {
|
}
|
||||||
printf("nsLineLayout: ");
|
#ifdef REALLY_NOISY_MAX_ELEMENT_SIZE
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
// Note: there are common reflow situations where this *correctly*
|
||||||
printf(": WARNING: maxElementSize=%d,%d > metrics=%d,%d\n",
|
// occurs; so only enable this debug noise when you really need to
|
||||||
metrics.maxElementSize->width,
|
// analyze in detail.
|
||||||
metrics.maxElementSize->height,
|
if (mComputeMaxElementSize &&
|
||||||
metrics.width, metrics.height);
|
((metrics.maxElementSize->width > metrics.width) ||
|
||||||
}
|
(metrics.maxElementSize->height > metrics.height))) {
|
||||||
if ((metrics.width == nscoord(0xdeadbeef)) ||
|
printf("nsLineLayout: ");
|
||||||
(metrics.height == nscoord(0xdeadbeef)) ||
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
(metrics.ascent == nscoord(0xdeadbeef)) ||
|
printf(": WARNING: maxElementSize=%d,%d > metrics=%d,%d\n",
|
||||||
(metrics.descent == nscoord(0xdeadbeef))) {
|
metrics.maxElementSize->width,
|
||||||
printf("nsLineLayout: ");
|
metrics.maxElementSize->height,
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
metrics.width, metrics.height);
|
||||||
printf(" didn't set whad %d,%d,%d,%d!\n", metrics.width, metrics.height,
|
}
|
||||||
metrics.ascent, metrics.descent);
|
#endif
|
||||||
|
if ((metrics.width == nscoord(0xdeadbeef)) ||
|
||||||
|
(metrics.height == nscoord(0xdeadbeef)) ||
|
||||||
|
(metrics.ascent == nscoord(0xdeadbeef)) ||
|
||||||
|
(metrics.descent == nscoord(0xdeadbeef))) {
|
||||||
|
printf("nsLineLayout: ");
|
||||||
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
|
printf(" didn't set whad %d,%d,%d,%d!\n", metrics.width, metrics.height,
|
||||||
|
metrics.ascent, metrics.descent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef NOISY_MAX_ELEMENT_SIZE
|
#ifdef NOISY_MAX_ELEMENT_SIZE
|
||||||
if (mComputeMaxElementSize) {
|
if (!NS_INLINE_IS_BREAK_BEFORE(aReflowStatus)) {
|
||||||
printf(" ");
|
if (mComputeMaxElementSize) {
|
||||||
nsFrame::ListTag(stdout, aFrame);
|
printf(" ");
|
||||||
printf(": maxElementSize=%d,%d wh=%d,%d,\n",
|
nsFrame::ListTag(stdout, aFrame);
|
||||||
metrics.maxElementSize->width,
|
printf(": maxElementSize=%d,%d wh=%d,%d,\n",
|
||||||
metrics.maxElementSize->height,
|
metrics.maxElementSize->width,
|
||||||
metrics.width, metrics.height);
|
metrics.maxElementSize->height,
|
||||||
|
metrics.width, metrics.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -907,8 +980,7 @@ nsLineLayout::ApplyLeftMargin(PerFrameData* pfd,
|
|||||||
// of a block then see if the text-indent property amounts to
|
// of a block then see if the text-indent property amounts to
|
||||||
// anything.
|
// anything.
|
||||||
nscoord indent = 0;
|
nscoord indent = 0;
|
||||||
if (InBlockContext() && (0 == mLineNumber) &&
|
if (InBlockContext() && (0 == mLineNumber) && CanPlaceFloaterNow()) {
|
||||||
(0 == mTotalPlacedFrames)) {
|
|
||||||
nsStyleUnit unit = mStyleText->mTextIndent.GetUnit();
|
nsStyleUnit unit = mStyleText->mTextIndent.GetUnit();
|
||||||
if (eStyleUnit_Coord == unit) {
|
if (eStyleUnit_Coord == unit) {
|
||||||
indent = mStyleText->mTextIndent.GetCoordValue();
|
indent = mStyleText->mTextIndent.GetCoordValue();
|
||||||
@@ -1012,11 +1084,26 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
if (nsnull != psd->mFrame) {
|
||||||
|
nsFrame::ListTag(stdout, psd->mFrame->mFrame);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nsFrame::ListTag(stdout, mBlockReflowState->frame);
|
||||||
|
}
|
||||||
|
printf(": aNotSafeToBreak=%s frame=", aNotSafeToBreak ? "true" : "false");
|
||||||
|
nsFrame::ListTag(stdout, pfd->mFrame);
|
||||||
|
printf(" frameWidth=%d\n", pfd->mBounds.XMost() + rightMargin - psd->mX);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Set outside to PR_TRUE if the result of the reflow leads to the
|
// Set outside to PR_TRUE if the result of the reflow leads to the
|
||||||
// frame sticking outside of our available area.
|
// frame sticking outside of our available area.
|
||||||
PRBool outside = pfd->mBounds.XMost() + rightMargin > psd->mRightEdge;
|
PRBool outside = pfd->mBounds.XMost() + rightMargin > psd->mRightEdge;
|
||||||
if (!outside) {
|
if (!outside) {
|
||||||
// If it fits, it fits
|
// If it fits, it fits
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> inside\n");
|
||||||
|
#endif
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1024,6 +1111,9 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||||||
// allow it to fit anyway.
|
// allow it to fit anyway.
|
||||||
if (0 == pfd->mMargin.left + pfd->mBounds.width + rightMargin) {
|
if (0 == pfd->mMargin.left + pfd->mBounds.width + rightMargin) {
|
||||||
// Empty frames always fit right where they are
|
// Empty frames always fit right where they are
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> empty frame fits\n");
|
||||||
|
#endif
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1032,10 +1122,22 @@ nsLineLayout::CanPlaceFrame(PerFrameData* pfd,
|
|||||||
// the line. If the line isn't impacted by a floater then the
|
// the line. If the line isn't impacted by a floater then the
|
||||||
// current frame fits.
|
// current frame fits.
|
||||||
if (!mImpactedByFloaters) {
|
if (!mImpactedByFloaters) {
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> not-safe and not-impacted fits: ");
|
||||||
|
PerSpanData* psd = mCurrentSpan;
|
||||||
|
while (nsnull != psd) {
|
||||||
|
printf("<psd=%p x=%d left=%d> ", psd, psd->mX, psd->mLeftEdge);
|
||||||
|
psd = psd->mParent;
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NOISY_CAN_PLACE_FRAME
|
||||||
|
printf(" ==> didn't fit\n");
|
||||||
|
#endif
|
||||||
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
}
|
}
|
||||||
@@ -1078,11 +1180,12 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, nsHTMLReflowMetrics& aMetrics)
|
|||||||
mEndsInWhiteSpace = PR_FALSE;
|
mEndsInWhiteSpace = PR_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the bottom margin to apply. Note that the margin only
|
// Count the number of frames on the line...
|
||||||
// applies if the frame ends up with a non-zero height.
|
mTotalPlacedFrames++;
|
||||||
if (!emptyFrame) {
|
if (0 != psd->mX) {
|
||||||
// Inform line layout that we have placed a non-empty frame
|
// As soon as a frame placed on the line advances an X coordinate
|
||||||
mTotalPlacedFrames++;
|
// of any span we can no longer place a floater on the line.
|
||||||
|
mCanPlaceFloater = PR_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user