Bug 530686. Don't redraw box-shadows over the bounding rect of the dirty region; just redraw them over a (somewhat simplified) dirty region. r=dbaron

This commit is contained in:
Robert O'Callahan 2009-11-30 18:14:04 -05:00
parent 2775cf57b8
commit 6780628363
5 changed files with 134 additions and 6 deletions

View File

@ -815,13 +815,53 @@ nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
mFrame->GetSkipSides());
}
// Given a region, compute a conservative approximation to it as a list
// of rectangles that aren't vertically adjacent (i.e., vertically
// adjacent or overlapping rectangles are combined).
// Right now this is only approximate, some vertically overlapping rectangles
// aren't guaranteed to be combined.
static void
ComputeDisjointRectangles(const nsRegion& aRegion,
nsTArray<nsRect>* aRects) {
nscoord accumulationMargin = nsPresContext::CSSPixelsToAppUnits(25);
nsRect accumulated;
nsRegionRectIterator iter(aRegion);
while (PR_TRUE) {
const nsRect* r = iter.Next();
if (r && !accumulated.IsEmpty() &&
accumulated.YMost() >= r->y - accumulationMargin) {
accumulated.UnionRect(accumulated, *r);
continue;
}
if (!accumulated.IsEmpty()) {
aRects->AppendElement(accumulated);
accumulated.Empty();
}
if (!r)
break;
accumulated = *r;
}
}
void
nsDisplayBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx) {
nsPoint offset = aBuilder->ToReferenceFrame(mFrame);
nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
nsRect(offset, mFrame->GetSize()),
mVisibleRect);
nsRect borderRect = nsRect(offset, mFrame->GetSize());
nsPresContext* presContext = mFrame->PresContext();
nsAutoTArray<nsRect,10> rects;
ComputeDisjointRectangles(mVisibleRegion, &rects);
for (PRUint32 i = 0; i < rects.Length(); ++i) {
aCtx->PushState();
aCtx->SetClipRect(rects[i], nsClipCombine_kIntersect);
nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
borderRect, rects[i]);
aCtx->PopState();
}
}
nsRect
@ -840,6 +880,9 @@ nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
aVisibleRegionBeforeMove))
return PR_FALSE;
// Store the actual visible region
mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
nsPoint origin = aBuilder->ToReferenceFrame(mFrame);
nsRect visibleBounds = aVisibleRegion->GetBounds();
if (aVisibleRegionBeforeMove) {
@ -866,9 +909,34 @@ void
nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
nsIRenderingContext* aCtx) {
nsPoint offset = aBuilder->ToReferenceFrame(mFrame);
nsCSSRendering::PaintBoxShadowInner(mFrame->PresContext(), *aCtx, mFrame,
nsRect(offset, mFrame->GetSize()),
mVisibleRect);
nsRect borderRect = nsRect(offset, mFrame->GetSize());
nsPresContext* presContext = mFrame->PresContext();
nsAutoTArray<nsRect,10> rects;
ComputeDisjointRectangles(mVisibleRegion, &rects);
for (PRUint32 i = 0; i < rects.Length(); ++i) {
aCtx->PushState();
aCtx->SetClipRect(rects[i], nsClipCombine_kIntersect);
nsCSSRendering::PaintBoxShadowInner(presContext, *aCtx, mFrame,
borderRect, rects[i]);
aCtx->PopState();
}
}
PRBool
nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
nsRegion* aVisibleRegionBeforeMove) {
NS_ASSERTION((aVisibleRegionBeforeMove != nsnull) == aBuilder->HasMovingFrames(),
"Should have aVisibleRegionBeforeMove when there are moving frames");
if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion,
aVisibleRegionBeforeMove))
return PR_FALSE;
// Store the actual visible region
mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
return PR_TRUE;
}
nsDisplayWrapList::nsDisplayWrapList(nsIFrame* aFrame, nsDisplayList* aList)

View File

@ -1212,6 +1212,9 @@ public:
nsRegion* aVisibleRegion,
nsRegion* aVisibleRegionBeforeMove);
NS_DISPLAY_DECL_NAME("BoxShadowOuter")
private:
nsRegion mVisibleRegion;
};
/**
@ -1229,7 +1232,13 @@ public:
#endif
virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx);
virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
nsRegion* aVisibleRegion,
nsRegion* aVisibleRegionBeforeMove);
NS_DISPLAY_DECL_NAME("BoxShadowInner")
private:
nsRegion mVisibleRegion;
};
/**

View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<head>
<style type="text/css">
#rear {
width: 500px;
height: 1500px;
-moz-box-shadow: 0 0 100px #667;
display: block;
}
</style>
</head>
<body>
<div id="rear"></div>
</body>
</html>

View File

@ -0,0 +1,34 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<head>
<style type="text/css">
#rear {
width: 500px;
height: 1500px;
-moz-box-shadow: 0 0 100px #667;
display: block;
}
.cover {
position: absolute;
width: 520px;
height: 100px;
background: yellow;
}
</style>
<script>
function doTest() {
var es = document.getElementsByClassName("cover");
for (var i = 0; i < es.length; ++i) {
es[i].style.display = 'none';
}
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest, false);
</script>
</head>
<body>
<div id="rear"></div>
<div class="cover" style="top:100px"></div>
<div class="cover" style="top:300px"></div>
</body>
</html>

View File

@ -1347,3 +1347,4 @@ fails-if(MOZ_WIDGET_TOOLKIT!="cocoa") == 488692-1.html 488692-1-ref.html # needs
== 528038-1e.html 528038-1-ref.html
== 528038-1f.html 528038-1-ref.html
== 528038-2.html 528038-2-ref.html
== 530686-1.html 503686-1-ref.html