From b997358c68314140999812583e042cd34154e318 Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Sat, 21 Dec 2002 23:25:38 +0000 Subject: [PATCH] Bug 170330. Factor out overflowArea calculations and take into account overflow:hidden. Also improve calculations of clipping for invalidation in the view manager. r+sr=dbaron git-svn-id: svn://10.0.0.236/trunk@135555 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/base/public/nsIFrame.h | 7 +++ mozilla/layout/generic/nsBlockFrame.cpp | 46 ++++------------- mozilla/layout/generic/nsFrame.cpp | 49 +++++++++++++++++++ mozilla/layout/generic/nsFrame.h | 5 ++ mozilla/layout/generic/nsIFrame.h | 7 +++ mozilla/layout/generic/nsInlineFrame.cpp | 20 +------- mozilla/layout/generic/nsLineLayout.cpp | 39 ++++++++------- mozilla/layout/html/base/src/nsBlockFrame.cpp | 46 ++++------------- mozilla/layout/html/base/src/nsFrame.cpp | 49 +++++++++++++++++++ mozilla/layout/html/base/src/nsFrame.h | 5 ++ .../layout/html/base/src/nsInlineFrame.cpp | 20 +------- mozilla/layout/html/base/src/nsLineLayout.cpp | 39 ++++++++------- mozilla/view/public/nsIViewManager.h | 3 ++ mozilla/view/src/nsViewManager.cpp | 29 ++++++----- 14 files changed, 207 insertions(+), 157 deletions(-) diff --git a/mozilla/layout/base/public/nsIFrame.h b/mozilla/layout/base/public/nsIFrame.h index b9de9beb248..8ad5fb74517 100644 --- a/mozilla/layout/base/public/nsIFrame.h +++ b/mozilla/layout/base/public/nsIFrame.h @@ -794,6 +794,13 @@ public: PRInt32* outFrameContentOffset, nsIFrame* *outChildFrame) = 0; + /** + * Returns true iff the frame has a view (i.e., GetView() returns non-null) + */ + PRBool HasView() { + return (mState & NS_FRAME_HAS_VIEW) != 0; + } + /** * Get the current frame-state value for this frame. aResult is * filled in with the state bits. diff --git a/mozilla/layout/generic/nsBlockFrame.cpp b/mozilla/layout/generic/nsBlockFrame.cpp index 63f0c66833d..15c59f28a1f 100644 --- a/mozilla/layout/generic/nsBlockFrame.cpp +++ b/mozilla/layout/generic/nsBlockFrame.cpp @@ -771,21 +771,16 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Whether or not we're complete hasn't changed aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; - // Factor the absolutely positioned child bounds into the overflow area ComputeCombinedArea(aReflowState, aMetrics); + + // Factor the absolutely positioned child bounds into the overflow area nsRect childBounds; mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } + // Finish computing the overflow area, taking account of outline and + // overflow:hidden etc + ComputeOverflowArea(aMetrics.mOverflowArea, aMetrics.mOverflowArea); return NS_OK; } @@ -1095,18 +1090,13 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Factor the absolutely positioned child bounds into the overflow area aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); - - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } } + // Area of child content has been computed into mOverflowArea + // Finish computing the overflow area, taking account of outline and + // overflow:hidden etc + ComputeOverflowArea(aMetrics.mOverflowArea, aMetrics.mOverflowArea); + // Clear the space manager pointer in the block reflow state so we // don't waste time translating the coordinate system back on a dead // space manager. @@ -1169,10 +1159,6 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } #endif -#ifdef DEBUG_roc - printf("*** Metrics width/height on the way out=%d,%d\n", aMetrics.width, aMetrics.height); -#endif - NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); return rv; } @@ -1546,18 +1532,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, } ComputeCombinedArea(aReflowState, aMetrics); - - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } } void diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index 0aa50ae6c53..4338f6d4739 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -754,6 +754,55 @@ nsFrame::DisplaySelection(nsIPresContext* aPresContext, PRBool isOkToTurnOn) return selType; } +void +nsFrame::ComputeOverflowArea(nsRect& aOverflowArea, + const nsRect& aCombinedChildren) +{ + // the frame's rect in its own coordinate system + nsRect r(0, 0, mRect.width, mRect.height); + // Make the default combined area: frame U children + aOverflowArea.UnionRect(aCombinedChildren, r); + // WARNING: aCombinedChildren might be the same rect as aOverflowArea. + // It may have been destroyed now. Don't use it below. + + // Don't do the following mildly expensive stuff unless we have a view; + // any block frame with overflow:hidden will have a view + // (see nsContainerFrame::FrameNeedsView). + // HasView() is very cheap; it just checks a bit on mState. + if (HasView()) { + // The following code is temporarily disabled. We'll turn it on + // when proper support for 'outline' lands. Note that it assumes + // any frame with 'outline' has a view. --- roc +#if 0 + // Add in the outline width, which overflows our border area + const nsStyleOutline* outline; + ::GetStyleData(mStyleContext, &outline); + + nscoord width; + outline->GetOutlineWidth(width); + r.Inflate(width, width); +#endif + + // overflow:hidden doesn't need to take account of the child area + const nsStyleDisplay* display; + ::GetStyleData(mStyleContext, &display); + if (NS_STYLE_OVERFLOW_HIDDEN == display->mOverflow + && (display->IsBlockLevel() || display->IsFloating())) { + aOverflowArea = r; + } + } + + // Set state bit to indicate whether there is any overflow + if (aOverflowArea.x < 0 + || aOverflowArea.y < 0 + || aOverflowArea.XMost() > mRect.width + || aOverflowArea.YMost() > mRect.height) { + mState |= NS_FRAME_OUTSIDE_CHILDREN; + } else { + mState &= ~NS_FRAME_OUTSIDE_CHILDREN; + } +} + void nsFrame::SetOverflowClipRect(nsIRenderingContext& aRenderingContext) { diff --git a/mozilla/layout/generic/nsFrame.h b/mozilla/layout/generic/nsFrame.h index 2a35962f237..0dc8a2cc154 100644 --- a/mozilla/layout/generic/nsFrame.h +++ b/mozilla/layout/generic/nsFrame.h @@ -348,6 +348,11 @@ public: const nsRect& aDamageRect, PRBool aImmediate = PR_FALSE) const; + // Helper function to compute the overflow area for a frame, + // taking into account overflow:hidden and any outline present. + // This sets the frame state bit FRAME_OUTSIDE_CHILDREN if necessary. + void ComputeOverflowArea(nsRect& aOverflowArea, const nsRect& aCombinedChildren); + // Helper function to return the index in parent of the frame's content // object. Returns -1 on error or if the frame doesn't have a content object static PRInt32 ContentIndexInContainer(const nsIFrame* aFrame); diff --git a/mozilla/layout/generic/nsIFrame.h b/mozilla/layout/generic/nsIFrame.h index b9de9beb248..8ad5fb74517 100644 --- a/mozilla/layout/generic/nsIFrame.h +++ b/mozilla/layout/generic/nsIFrame.h @@ -794,6 +794,13 @@ public: PRInt32* outFrameContentOffset, nsIFrame* *outChildFrame) = 0; + /** + * Returns true iff the frame has a view (i.e., GetView() returns non-null) + */ + PRBool HasView() { + return (mState & NS_FRAME_HAS_VIEW) != 0; + } + /** * Get the current frame-state value for this frame. aResult is * filled in with the state bits. diff --git a/mozilla/layout/generic/nsInlineFrame.cpp b/mozilla/layout/generic/nsInlineFrame.cpp index bcea211fd32..fa7d6283afd 100644 --- a/mozilla/layout/generic/nsInlineFrame.cpp +++ b/mozilla/layout/generic/nsInlineFrame.cpp @@ -1311,16 +1311,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds); - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aDesiredSize.mOverflowArea.x < 0) || - (aDesiredSize.mOverflowArea.y < 0) || - (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) || - (aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } #endif + // Don't update the overflow area state here. It's done by line layout. return rv; } } @@ -1356,16 +1348,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, // Factor the absolutely positioned child bounds into the overflow area aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds); - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aDesiredSize.mOverflowArea.x < 0) || - (aDesiredSize.mOverflowArea.y < 0) || - (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) || - (aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } #endif + // Don't update the overflow area state here. It's done by line layout. } return rv; diff --git a/mozilla/layout/generic/nsLineLayout.cpp b/mozilla/layout/generic/nsLineLayout.cpp index 34c57d07a65..f5ae74be1a6 100644 --- a/mozilla/layout/generic/nsLineLayout.cpp +++ b/mozilla/layout/generic/nsLineLayout.cpp @@ -1258,16 +1258,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, nsIView* view; aFrame->GetView(mPresContext, &view); if (view) { - nsIViewManager *vm; - view->GetViewManager(vm); + nsCOMPtr vm; + view->GetViewManager(*getter_AddRefs(vm)); -#if 0 // XXX This is the correct code. We'll turn it on later to mitigate risk. vm->ResizeView(view, pfd->mCombinedArea); -#else // imitate the old, wrong code - nsRect r(0, 0, metrics.width, metrics.height); - vm->ResizeView(view, r); -#endif - NS_RELEASE(vm); + nsContainerFrame::SyncFrameViewAfterSizeChange(mPresContext, pfd->mFrame, nsnull, view); } // Tell the frame that we're done reflowing it @@ -3323,20 +3318,26 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea) } // If we just computed a spans combined area, we need to update its - // NS_FRAME_OUTSIDE_CHILDREN bit.. + // NS_FRAME_OUTSIDE_CHILDREN bit. We also may need to take into account + // an outline. if (nsnull != psd->mFrame) { pfd = psd->mFrame; nsIFrame* frame = pfd->mFrame; - nsFrameState oldState; - frame->GetFrameState(&oldState); - nsFrameState newState = oldState & ~NS_FRAME_OUTSIDE_CHILDREN; - if ((minX < 0) || (minY < 0) || - (maxX > pfd->mBounds.width) || (maxY > pfd->mBounds.height)) { - newState |= NS_FRAME_OUTSIDE_CHILDREN; - } - if (newState != oldState) { - frame->SetFrameState(newState); - } + + // We're conservative here; the combined area for this span/frame + // is the union of the area that the frame computed during reflow + // and the area that we computed for it here in RelativePositionFrames. + // We do this because relatively positioned frames that are also spans + // have two contributors to the overflow area: overflowing inline children + // and overflowing absolute children. + // This could be larger than necessary if inline alignment caused an inline child + // to overflow less, because its old overflow would still be counted in + // pfd->mCombinedArea. + // But in practice it's OK to have an overflow area that's larger than necessary. + // (Although if it happens too often it could become a paint performance issue). + nsRect children; + children.UnionRect(pfd->mCombinedArea, aCombinedArea); + NS_STATIC_CAST(nsFrame*, frame)->ComputeOverflowArea(aCombinedArea, children); } } diff --git a/mozilla/layout/html/base/src/nsBlockFrame.cpp b/mozilla/layout/html/base/src/nsBlockFrame.cpp index 63f0c66833d..15c59f28a1f 100644 --- a/mozilla/layout/html/base/src/nsBlockFrame.cpp +++ b/mozilla/layout/html/base/src/nsBlockFrame.cpp @@ -771,21 +771,16 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Whether or not we're complete hasn't changed aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; - // Factor the absolutely positioned child bounds into the overflow area ComputeCombinedArea(aReflowState, aMetrics); + + // Factor the absolutely positioned child bounds into the overflow area nsRect childBounds; mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } + // Finish computing the overflow area, taking account of outline and + // overflow:hidden etc + ComputeOverflowArea(aMetrics.mOverflowArea, aMetrics.mOverflowArea); return NS_OK; } @@ -1095,18 +1090,13 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, // Factor the absolutely positioned child bounds into the overflow area aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); - - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } } + // Area of child content has been computed into mOverflowArea + // Finish computing the overflow area, taking account of outline and + // overflow:hidden etc + ComputeOverflowArea(aMetrics.mOverflowArea, aMetrics.mOverflowArea); + // Clear the space manager pointer in the block reflow state so we // don't waste time translating the coordinate system back on a dead // space manager. @@ -1169,10 +1159,6 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext, } #endif -#ifdef DEBUG_roc - printf("*** Metrics width/height on the way out=%d,%d\n", aMetrics.width, aMetrics.height); -#endif - NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics); return rv; } @@ -1546,18 +1532,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState, } ComputeCombinedArea(aReflowState, aMetrics); - - // If the combined area of our children exceeds our bounding box - // then set the NS_FRAME_OUTSIDE_CHILDREN flag, otherwise clear it. - if ((aMetrics.mOverflowArea.x < 0) || - (aMetrics.mOverflowArea.y < 0) || - (aMetrics.mOverflowArea.XMost() > aMetrics.width) || - (aMetrics.mOverflowArea.YMost() > aMetrics.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } - else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } } void diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index 0aa50ae6c53..4338f6d4739 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -754,6 +754,55 @@ nsFrame::DisplaySelection(nsIPresContext* aPresContext, PRBool isOkToTurnOn) return selType; } +void +nsFrame::ComputeOverflowArea(nsRect& aOverflowArea, + const nsRect& aCombinedChildren) +{ + // the frame's rect in its own coordinate system + nsRect r(0, 0, mRect.width, mRect.height); + // Make the default combined area: frame U children + aOverflowArea.UnionRect(aCombinedChildren, r); + // WARNING: aCombinedChildren might be the same rect as aOverflowArea. + // It may have been destroyed now. Don't use it below. + + // Don't do the following mildly expensive stuff unless we have a view; + // any block frame with overflow:hidden will have a view + // (see nsContainerFrame::FrameNeedsView). + // HasView() is very cheap; it just checks a bit on mState. + if (HasView()) { + // The following code is temporarily disabled. We'll turn it on + // when proper support for 'outline' lands. Note that it assumes + // any frame with 'outline' has a view. --- roc +#if 0 + // Add in the outline width, which overflows our border area + const nsStyleOutline* outline; + ::GetStyleData(mStyleContext, &outline); + + nscoord width; + outline->GetOutlineWidth(width); + r.Inflate(width, width); +#endif + + // overflow:hidden doesn't need to take account of the child area + const nsStyleDisplay* display; + ::GetStyleData(mStyleContext, &display); + if (NS_STYLE_OVERFLOW_HIDDEN == display->mOverflow + && (display->IsBlockLevel() || display->IsFloating())) { + aOverflowArea = r; + } + } + + // Set state bit to indicate whether there is any overflow + if (aOverflowArea.x < 0 + || aOverflowArea.y < 0 + || aOverflowArea.XMost() > mRect.width + || aOverflowArea.YMost() > mRect.height) { + mState |= NS_FRAME_OUTSIDE_CHILDREN; + } else { + mState &= ~NS_FRAME_OUTSIDE_CHILDREN; + } +} + void nsFrame::SetOverflowClipRect(nsIRenderingContext& aRenderingContext) { diff --git a/mozilla/layout/html/base/src/nsFrame.h b/mozilla/layout/html/base/src/nsFrame.h index 2a35962f237..0dc8a2cc154 100644 --- a/mozilla/layout/html/base/src/nsFrame.h +++ b/mozilla/layout/html/base/src/nsFrame.h @@ -348,6 +348,11 @@ public: const nsRect& aDamageRect, PRBool aImmediate = PR_FALSE) const; + // Helper function to compute the overflow area for a frame, + // taking into account overflow:hidden and any outline present. + // This sets the frame state bit FRAME_OUTSIDE_CHILDREN if necessary. + void ComputeOverflowArea(nsRect& aOverflowArea, const nsRect& aCombinedChildren); + // Helper function to return the index in parent of the frame's content // object. Returns -1 on error or if the frame doesn't have a content object static PRInt32 ContentIndexInContainer(const nsIFrame* aFrame); diff --git a/mozilla/layout/html/base/src/nsInlineFrame.cpp b/mozilla/layout/html/base/src/nsInlineFrame.cpp index bcea211fd32..fa7d6283afd 100644 --- a/mozilla/layout/html/base/src/nsInlineFrame.cpp +++ b/mozilla/layout/html/base/src/nsInlineFrame.cpp @@ -1311,16 +1311,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds); - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aDesiredSize.mOverflowArea.x < 0) || - (aDesiredSize.mOverflowArea.y < 0) || - (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) || - (aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } #endif + // Don't update the overflow area state here. It's done by line layout. return rv; } } @@ -1356,16 +1348,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext, // Factor the absolutely positioned child bounds into the overflow area aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, childBounds); - // Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly - if ((aDesiredSize.mOverflowArea.x < 0) || - (aDesiredSize.mOverflowArea.y < 0) || - (aDesiredSize.mOverflowArea.XMost() > aDesiredSize.width) || - (aDesiredSize.mOverflowArea.YMost() > aDesiredSize.height)) { - mState |= NS_FRAME_OUTSIDE_CHILDREN; - } else { - mState &= ~NS_FRAME_OUTSIDE_CHILDREN; - } #endif + // Don't update the overflow area state here. It's done by line layout. } return rv; diff --git a/mozilla/layout/html/base/src/nsLineLayout.cpp b/mozilla/layout/html/base/src/nsLineLayout.cpp index 34c57d07a65..f5ae74be1a6 100644 --- a/mozilla/layout/html/base/src/nsLineLayout.cpp +++ b/mozilla/layout/html/base/src/nsLineLayout.cpp @@ -1258,16 +1258,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame, nsIView* view; aFrame->GetView(mPresContext, &view); if (view) { - nsIViewManager *vm; - view->GetViewManager(vm); + nsCOMPtr vm; + view->GetViewManager(*getter_AddRefs(vm)); -#if 0 // XXX This is the correct code. We'll turn it on later to mitigate risk. vm->ResizeView(view, pfd->mCombinedArea); -#else // imitate the old, wrong code - nsRect r(0, 0, metrics.width, metrics.height); - vm->ResizeView(view, r); -#endif - NS_RELEASE(vm); + nsContainerFrame::SyncFrameViewAfterSizeChange(mPresContext, pfd->mFrame, nsnull, view); } // Tell the frame that we're done reflowing it @@ -3323,20 +3318,26 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsRect& aCombinedArea) } // If we just computed a spans combined area, we need to update its - // NS_FRAME_OUTSIDE_CHILDREN bit.. + // NS_FRAME_OUTSIDE_CHILDREN bit. We also may need to take into account + // an outline. if (nsnull != psd->mFrame) { pfd = psd->mFrame; nsIFrame* frame = pfd->mFrame; - nsFrameState oldState; - frame->GetFrameState(&oldState); - nsFrameState newState = oldState & ~NS_FRAME_OUTSIDE_CHILDREN; - if ((minX < 0) || (minY < 0) || - (maxX > pfd->mBounds.width) || (maxY > pfd->mBounds.height)) { - newState |= NS_FRAME_OUTSIDE_CHILDREN; - } - if (newState != oldState) { - frame->SetFrameState(newState); - } + + // We're conservative here; the combined area for this span/frame + // is the union of the area that the frame computed during reflow + // and the area that we computed for it here in RelativePositionFrames. + // We do this because relatively positioned frames that are also spans + // have two contributors to the overflow area: overflowing inline children + // and overflowing absolute children. + // This could be larger than necessary if inline alignment caused an inline child + // to overflow less, because its old overflow would still be counted in + // pfd->mCombinedArea. + // But in practice it's OK to have an overflow area that's larger than necessary. + // (Although if it happens too often it could become a paint performance issue). + nsRect children; + children.UnionRect(pfd->mCombinedArea, aCombinedArea); + NS_STATIC_CAST(nsFrame*, frame)->ComputeOverflowArea(aCombinedArea, children); } } diff --git a/mozilla/view/public/nsIViewManager.h b/mozilla/view/public/nsIViewManager.h index 619c250094f..dc4bda1efa4 100644 --- a/mozilla/view/public/nsIViewManager.h +++ b/mozilla/view/public/nsIViewManager.h @@ -547,6 +547,9 @@ public: }; +//update view as if a child view was being invalidated, +//so the view should apply its 'child clip' +#define NS_VMREFRESH_FORCHILD 0x0001 //update view now? #define NS_VMREFRESH_IMMEDIATE 0x0002 //prevent "sync painting" diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index b5ee33a9b0c..f2adb356801 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -1629,12 +1629,18 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRU } view->ConvertFromParentCoords(&clippedRect.x, &clippedRect.y); + if ((aUpdateFlags & NS_VMREFRESH_FORCHILD) != 0 && view->GetClipChildren()) { + nsRect childClipRect; + view->GetChildClip(childClipRect); + if (!clippedRect.IntersectRect(clippedRect, childClipRect)) { + return NS_OK; + } + } + nsRect damagedRect; - damagedRect.x = aRect.x; - damagedRect.y = aRect.y; - damagedRect.width = aRect.width; - damagedRect.height = aRect.height; - damagedRect.IntersectRect(aRect, clippedRect); + if (!damagedRect.IntersectRect(aRect, clippedRect)) { + return NS_OK; + } // If the rectangle is not visible then abort // without invalidating. This is a performance @@ -2500,10 +2506,10 @@ NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY) view->GetVisibility(visibility); if (visibility != nsViewVisibility_kHide) { nsView* parentView = view->GetParent(); - UpdateView(parentView, oldArea, NS_VMREFRESH_NO_SYNC); + UpdateView(parentView, oldArea, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD); nsRect newArea; view->GetBounds(newArea); - UpdateView(parentView, newArea, NS_VMREFRESH_NO_SYNC); + UpdateView(parentView, newArea, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD); } } return NS_OK; @@ -2564,7 +2570,7 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRB UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC); view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y); - UpdateView(parentView, oldDimensions, NS_VMREFRESH_NO_SYNC); + UpdateView(parentView, oldDimensions, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD); } else { view->SetDimensions(aRect, PR_FALSE); @@ -2572,7 +2578,7 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRB nsRect r = aRect; view->ConvertToParentCoords(&r.x, &r.y); view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y); - InvalidateRectDifference(parentView, oldDimensions, r, NS_VMREFRESH_NO_SYNC); + InvalidateRectDifference(parentView, oldDimensions, r, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD); } } @@ -2650,7 +2656,8 @@ NS_IMETHODIMP nsViewManager::SetViewChildClipRegion(nsIView *aView, const nsRegi if (parent != nsnull) { view->ConvertToParentCoords(&oldClipRect.x, &oldClipRect.y); view->ConvertToParentCoords(&newClipRect.x, &newClipRect.y); - InvalidateRectDifference(parent, oldClipRect, newClipRect, NS_VMREFRESH_NO_SYNC); + InvalidateRectDifference(parent, oldClipRect, newClipRect, + NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD); } } @@ -2887,7 +2894,7 @@ NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility if (parentView) { nsRect bounds; view->GetBounds(bounds); - UpdateView(parentView, bounds, NS_VMREFRESH_NO_SYNC); + UpdateView(parentView, bounds, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD); } } else {