Bug 770001. When comparing clips, adjust for any change in the ThebesLayer coordinate system. When clips are different, try to accumulate differences intelligently, taking into account that changes in clips outside the bounds of the clipped display item don't matter. r=mattwoodrow

This commit is contained in:
Robert O'Callahan 2012-08-29 17:48:44 +12:00
parent 3a8db38bc7
commit 73932e816e
3 changed files with 59 additions and 8 deletions

View File

@ -2183,7 +2183,8 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>(t->GetUserData(&gThebesDisplayItemLayerUserData));
InvalidatePostTransformRegion(t,
oldGeometry->ComputeInvalidationRegion().ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
oldGeometry->ComputeInvalidationRegion().
ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
mLayerBuilder->GetLastPaintOffset(t));
}
if (aNewLayer) {
@ -2192,7 +2193,8 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData));
InvalidatePostTransformRegion(newThebesLayer,
geometry->ComputeInvalidationRegion().ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
geometry->ComputeInvalidationRegion().
ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel),
GetTranslationForThebesLayer(newThebesLayer));
}
}
@ -2219,20 +2221,21 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem,
#ifdef DEBUG_INVALIDATIONS
printf("Display item type %s(%p) added to layer %p!\n", aItem->Name(), f, aNewLayer);
#endif
} else if (aItem->IsInvalid() || *oldClip != aClip) {
// Either layout marked item as needing repainting, or the clip on it changed, invalidate
// the entire old and new areas.
// TODO: We could be smarter about handling clip changes here instead of repainting everything.
} else if (aItem->IsInvalid()) {
// Either layout marked item as needing repainting, invalidate the entire old and new areas.
combined.Or(geometry->ComputeInvalidationRegion(), oldGeometry->ComputeInvalidationRegion());
#ifdef DEBUG_INVALIDATIONS
printf("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), f, aNewLayer);
#endif
} else {
// No obvious differences, so let the display item check for geometry changes and decide what needs to be
// Let the display item check for geometry changes and decide what needs to be
// repainted.
nsPoint shift = aTopLeft - data->mLastActiveScrolledRootOrigin;
oldGeometry->MoveBy(shift);
aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined);
oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(),
aClip, geometry->ComputeInvalidationRegion(),
&combined);
#ifdef DEBUG_INVALIDATIONS
if (!combined.IsEmpty()) {
printf("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), f, aNewLayer);
@ -3448,6 +3451,43 @@ FrameLayerBuilder::Clip::RemoveRoundedCorners()
mRoundedClipRects.Clear();
}
static void
AccumulateRectDifference(const nsRect& aR1, const nsRect& aR2, nsRegion* aOut)
{
if (aR1.IsEqualInterior(aR2))
return;
nsRegion r;
r.Xor(aR1, aR2);
aOut->Or(*aOut, r);
}
void
FrameLayerBuilder::Clip::AddOffsetAndComputeDifference(const nsPoint& aOffset,
const nsRect& aBounds,
const Clip& aOther,
const nsRect& aOtherBounds,
nsRegion* aDifference)
{
if (mHaveClipRect != aOther.mHaveClipRect ||
mRoundedClipRects.Length() != aOther.mRoundedClipRects.Length()) {
aDifference->Or(*aDifference, aBounds);
aDifference->Or(*aDifference, aOtherBounds);
return;
}
if (mHaveClipRect) {
AccumulateRectDifference((mClipRect + aOffset).Intersect(aBounds),
aOther.mClipRect.Intersect(aOtherBounds),
aDifference);
}
for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) {
if (mRoundedClipRects[i] + aOffset != aOther.mRoundedClipRects[i]) {
// The corners make it tricky so we'll just add both rects here.
aDifference->Or(*aDifference, mRoundedClipRects[i].mRect.Intersect(aBounds));
aDifference->Or(*aDifference, aOther.mRoundedClipRects[i].mRect.Intersect(aOtherBounds));
}
}
}
gfxRect
CalculateBounds(const nsTArray<FrameLayerBuilder::Clip::RoundedRect>& aRects, int32_t A2D)
{

View File

@ -413,6 +413,11 @@ public:
// Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h
nscoord mRadii[8];
RoundedRect operator+(const nsPoint& aOffset) const {
RoundedRect r = *this;
r.mRect += aOffset;
return r;
}
bool operator==(const RoundedRect& aOther) const {
if (!mRect.IsEqualInterior(aOther.mRect)) {
return false;
@ -475,6 +480,12 @@ public:
// Gets rid of any rounded corners in this clip.
void RemoveRoundedCorners();
// Adds the difference between Intersect(*this + aPoint, aBounds) and
// Intersect(aOther, aOtherBounds) to aDifference.
void AddOffsetAndComputeDifference(const nsPoint& aPoint, const nsRect& aBounds,
const Clip& aOther, const nsRect& aOtherBounds,
nsRegion* aDifference);
bool operator==(const Clip& aOther) const {
return mHaveClipRect == aOther.mHaveClipRect &&
(!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) &&

View File

@ -28,7 +28,7 @@ public:
* Compute the area required to be invalidated if this
* display item is removed.
*/
nsRegion ComputeInvalidationRegion() { return mBounds; }
const nsRect& ComputeInvalidationRegion() { return mBounds; }
/**
* Shifts all retained areas of the nsDisplayItemGeometry by the given offset.