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

This commit is contained in:
roc+%cs.cmu.edu 2002-12-21 23:25:38 +00:00
Родитель 89d4967bdf
Коммит a5a3f217d1
14 изменённых файлов: 207 добавлений и 157 удалений

Просмотреть файл

@ -794,6 +794,13 @@ public:
PRInt32* outFrameContentOffset, PRInt32* outFrameContentOffset,
nsIFrame* *outChildFrame) = 0; 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 * Get the current frame-state value for this frame. aResult is
* filled in with the state bits. * filled in with the state bits.

Просмотреть файл

@ -771,21 +771,16 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
// Whether or not we're complete hasn't changed // Whether or not we're complete hasn't changed
aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE;
// Factor the absolutely positioned child bounds into the overflow area
ComputeCombinedArea(aReflowState, aMetrics); ComputeCombinedArea(aReflowState, aMetrics);
// Factor the absolutely positioned child bounds into the overflow area
nsRect childBounds; nsRect childBounds;
mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds);
// Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly // Finish computing the overflow area, taking account of outline and
if ((aMetrics.mOverflowArea.x < 0) || // overflow:hidden etc
(aMetrics.mOverflowArea.y < 0) || ComputeOverflowArea(aMetrics.mOverflowArea, aMetrics.mOverflowArea);
(aMetrics.mOverflowArea.XMost() > aMetrics.width) ||
(aMetrics.mOverflowArea.YMost() > aMetrics.height)) {
mState |= NS_FRAME_OUTSIDE_CHILDREN;
} else {
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
}
return NS_OK; return NS_OK;
} }
@ -1095,18 +1090,13 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
// Factor the absolutely positioned child bounds into the overflow area // Factor the absolutely positioned child bounds into the overflow area
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, 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;
}
} }
// 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 // Clear the space manager pointer in the block reflow state so we
// don't waste time translating the coordinate system back on a dead // don't waste time translating the coordinate system back on a dead
// space manager. // space manager.
@ -1169,10 +1159,6 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
} }
#endif #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); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
return rv; return rv;
} }
@ -1546,18 +1532,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
} }
ComputeCombinedArea(aReflowState, aMetrics); 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 void

Просмотреть файл

@ -754,6 +754,55 @@ nsFrame::DisplaySelection(nsIPresContext* aPresContext, PRBool isOkToTurnOn)
return selType; 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 void
nsFrame::SetOverflowClipRect(nsIRenderingContext& aRenderingContext) nsFrame::SetOverflowClipRect(nsIRenderingContext& aRenderingContext)
{ {

Просмотреть файл

@ -348,6 +348,11 @@ public:
const nsRect& aDamageRect, const nsRect& aDamageRect,
PRBool aImmediate = PR_FALSE) const; 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 // 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 // object. Returns -1 on error or if the frame doesn't have a content object
static PRInt32 ContentIndexInContainer(const nsIFrame* aFrame); static PRInt32 ContentIndexInContainer(const nsIFrame* aFrame);

Просмотреть файл

@ -794,6 +794,13 @@ public:
PRInt32* outFrameContentOffset, PRInt32* outFrameContentOffset,
nsIFrame* *outChildFrame) = 0; 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 * Get the current frame-state value for this frame. aResult is
* filled in with the state bits. * filled in with the state bits.

Просмотреть файл

@ -1311,16 +1311,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext,
mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, 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 #endif
// Don't update the overflow area state here. It's done by line layout.
return rv; return rv;
} }
} }
@ -1356,16 +1348,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext,
// Factor the absolutely positioned child bounds into the overflow area // Factor the absolutely positioned child bounds into the overflow area
aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, 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 #endif
// Don't update the overflow area state here. It's done by line layout.
} }
return rv; return rv;

Просмотреть файл

@ -1258,16 +1258,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
nsIView* view; nsIView* view;
aFrame->GetView(mPresContext, &view); aFrame->GetView(mPresContext, &view);
if (view) { if (view) {
nsIViewManager *vm; nsCOMPtr<nsIViewManager> vm;
view->GetViewManager(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); vm->ResizeView(view, pfd->mCombinedArea);
#else // imitate the old, wrong code nsContainerFrame::SyncFrameViewAfterSizeChange(mPresContext, pfd->mFrame, nsnull, view);
nsRect r(0, 0, metrics.width, metrics.height);
vm->ResizeView(view, r);
#endif
NS_RELEASE(vm);
} }
// Tell the frame that we're done reflowing it // 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 // 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) { if (nsnull != psd->mFrame) {
pfd = psd->mFrame; pfd = psd->mFrame;
nsIFrame* frame = pfd->mFrame; nsIFrame* frame = pfd->mFrame;
nsFrameState oldState;
frame->GetFrameState(&oldState); // We're conservative here; the combined area for this span/frame
nsFrameState newState = oldState & ~NS_FRAME_OUTSIDE_CHILDREN; // is the union of the area that the frame computed during reflow
if ((minX < 0) || (minY < 0) || // and the area that we computed for it here in RelativePositionFrames.
(maxX > pfd->mBounds.width) || (maxY > pfd->mBounds.height)) { // We do this because relatively positioned frames that are also spans
newState |= NS_FRAME_OUTSIDE_CHILDREN; // have two contributors to the overflow area: overflowing inline children
} // and overflowing absolute children.
if (newState != oldState) { // This could be larger than necessary if inline alignment caused an inline child
frame->SetFrameState(newState); // 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);
} }
} }

Просмотреть файл

@ -771,21 +771,16 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
// Whether or not we're complete hasn't changed // Whether or not we're complete hasn't changed
aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE; aStatus = (nsnull != mNextInFlow) ? NS_FRAME_NOT_COMPLETE : NS_FRAME_COMPLETE;
// Factor the absolutely positioned child bounds into the overflow area
ComputeCombinedArea(aReflowState, aMetrics); ComputeCombinedArea(aReflowState, aMetrics);
// Factor the absolutely positioned child bounds into the overflow area
nsRect childBounds; nsRect childBounds;
mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds); aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, childBounds);
// Make sure the NS_FRAME_OUTSIDE_CHILDREN flag is set correctly // Finish computing the overflow area, taking account of outline and
if ((aMetrics.mOverflowArea.x < 0) || // overflow:hidden etc
(aMetrics.mOverflowArea.y < 0) || ComputeOverflowArea(aMetrics.mOverflowArea, aMetrics.mOverflowArea);
(aMetrics.mOverflowArea.XMost() > aMetrics.width) ||
(aMetrics.mOverflowArea.YMost() > aMetrics.height)) {
mState |= NS_FRAME_OUTSIDE_CHILDREN;
} else {
mState &= ~NS_FRAME_OUTSIDE_CHILDREN;
}
return NS_OK; return NS_OK;
} }
@ -1095,18 +1090,13 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
// Factor the absolutely positioned child bounds into the overflow area // Factor the absolutely positioned child bounds into the overflow area
aMetrics.mOverflowArea.UnionRect(aMetrics.mOverflowArea, 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;
}
} }
// 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 // Clear the space manager pointer in the block reflow state so we
// don't waste time translating the coordinate system back on a dead // don't waste time translating the coordinate system back on a dead
// space manager. // space manager.
@ -1169,10 +1159,6 @@ nsBlockFrame::Reflow(nsIPresContext* aPresContext,
} }
#endif #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); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aMetrics);
return rv; return rv;
} }
@ -1546,18 +1532,6 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
} }
ComputeCombinedArea(aReflowState, aMetrics); 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 void

Просмотреть файл

@ -754,6 +754,55 @@ nsFrame::DisplaySelection(nsIPresContext* aPresContext, PRBool isOkToTurnOn)
return selType; 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 void
nsFrame::SetOverflowClipRect(nsIRenderingContext& aRenderingContext) nsFrame::SetOverflowClipRect(nsIRenderingContext& aRenderingContext)
{ {

Просмотреть файл

@ -348,6 +348,11 @@ public:
const nsRect& aDamageRect, const nsRect& aDamageRect,
PRBool aImmediate = PR_FALSE) const; 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 // 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 // object. Returns -1 on error or if the frame doesn't have a content object
static PRInt32 ContentIndexInContainer(const nsIFrame* aFrame); static PRInt32 ContentIndexInContainer(const nsIFrame* aFrame);

Просмотреть файл

@ -1311,16 +1311,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext,
mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds); mAbsoluteContainer.CalculateChildBounds(aPresContext, childBounds);
aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, 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 #endif
// Don't update the overflow area state here. It's done by line layout.
return rv; return rv;
} }
} }
@ -1356,16 +1348,8 @@ nsPositionedInlineFrame::Reflow(nsIPresContext* aPresContext,
// Factor the absolutely positioned child bounds into the overflow area // Factor the absolutely positioned child bounds into the overflow area
aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, 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 #endif
// Don't update the overflow area state here. It's done by line layout.
} }
return rv; return rv;

Просмотреть файл

@ -1258,16 +1258,11 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
nsIView* view; nsIView* view;
aFrame->GetView(mPresContext, &view); aFrame->GetView(mPresContext, &view);
if (view) { if (view) {
nsIViewManager *vm; nsCOMPtr<nsIViewManager> vm;
view->GetViewManager(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); vm->ResizeView(view, pfd->mCombinedArea);
#else // imitate the old, wrong code nsContainerFrame::SyncFrameViewAfterSizeChange(mPresContext, pfd->mFrame, nsnull, view);
nsRect r(0, 0, metrics.width, metrics.height);
vm->ResizeView(view, r);
#endif
NS_RELEASE(vm);
} }
// Tell the frame that we're done reflowing it // 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 // 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) { if (nsnull != psd->mFrame) {
pfd = psd->mFrame; pfd = psd->mFrame;
nsIFrame* frame = pfd->mFrame; nsIFrame* frame = pfd->mFrame;
nsFrameState oldState;
frame->GetFrameState(&oldState); // We're conservative here; the combined area for this span/frame
nsFrameState newState = oldState & ~NS_FRAME_OUTSIDE_CHILDREN; // is the union of the area that the frame computed during reflow
if ((minX < 0) || (minY < 0) || // and the area that we computed for it here in RelativePositionFrames.
(maxX > pfd->mBounds.width) || (maxY > pfd->mBounds.height)) { // We do this because relatively positioned frames that are also spans
newState |= NS_FRAME_OUTSIDE_CHILDREN; // have two contributors to the overflow area: overflowing inline children
} // and overflowing absolute children.
if (newState != oldState) { // This could be larger than necessary if inline alignment caused an inline child
frame->SetFrameState(newState); // 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);
} }
} }

Просмотреть файл

@ -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? //update view now?
#define NS_VMREFRESH_IMMEDIATE 0x0002 #define NS_VMREFRESH_IMMEDIATE 0x0002
//prevent "sync painting" //prevent "sync painting"

Просмотреть файл

@ -1629,12 +1629,18 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRU
} }
view->ConvertFromParentCoords(&clippedRect.x, &clippedRect.y); 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; nsRect damagedRect;
damagedRect.x = aRect.x; if (!damagedRect.IntersectRect(aRect, clippedRect)) {
damagedRect.y = aRect.y; return NS_OK;
damagedRect.width = aRect.width; }
damagedRect.height = aRect.height;
damagedRect.IntersectRect(aRect, clippedRect);
// If the rectangle is not visible then abort // If the rectangle is not visible then abort
// without invalidating. This is a performance // without invalidating. This is a performance
@ -2500,10 +2506,10 @@ NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY)
view->GetVisibility(visibility); view->GetVisibility(visibility);
if (visibility != nsViewVisibility_kHide) { if (visibility != nsViewVisibility_kHide) {
nsView* parentView = view->GetParent(); nsView* parentView = view->GetParent();
UpdateView(parentView, oldArea, NS_VMREFRESH_NO_SYNC); UpdateView(parentView, oldArea, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD);
nsRect newArea; nsRect newArea;
view->GetBounds(newArea); view->GetBounds(newArea);
UpdateView(parentView, newArea, NS_VMREFRESH_NO_SYNC); UpdateView(parentView, newArea, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD);
} }
} }
return NS_OK; return NS_OK;
@ -2564,7 +2570,7 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRB
UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC); UpdateView(view, aRect, NS_VMREFRESH_NO_SYNC);
view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y); view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.y);
UpdateView(parentView, oldDimensions, NS_VMREFRESH_NO_SYNC); UpdateView(parentView, oldDimensions, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD);
} else { } else {
view->SetDimensions(aRect, PR_FALSE); view->SetDimensions(aRect, PR_FALSE);
@ -2572,7 +2578,7 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, const nsRect &aRect, PRB
nsRect r = aRect; nsRect r = aRect;
view->ConvertToParentCoords(&r.x, &r.y); view->ConvertToParentCoords(&r.x, &r.y);
view->ConvertToParentCoords(&oldDimensions.x, &oldDimensions.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) { if (parent != nsnull) {
view->ConvertToParentCoords(&oldClipRect.x, &oldClipRect.y); view->ConvertToParentCoords(&oldClipRect.x, &oldClipRect.y);
view->ConvertToParentCoords(&newClipRect.x, &newClipRect.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) { if (parentView) {
nsRect bounds; nsRect bounds;
view->GetBounds(bounds); view->GetBounds(bounds);
UpdateView(parentView, bounds, NS_VMREFRESH_NO_SYNC); UpdateView(parentView, bounds, NS_VMREFRESH_NO_SYNC | NS_VMREFRESH_FORCHILD);
} }
} }
else { else {