diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 8993b8d2a7bd..db605f8f5b33 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -1991,7 +1991,8 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer, ThebesDisplayItemLayerUserData* data = static_cast(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) { @@ -2000,7 +2001,8 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer, ThebesDisplayItemLayerUserData* data = static_cast(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData)); InvalidatePostTransformRegion(newThebesLayer, - geometry->ComputeInvalidationRegion().ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), + geometry->ComputeInvalidationRegion(). + ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), GetTranslationForThebesLayer(newThebesLayer)); } } @@ -2028,27 +2030,27 @@ ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer, #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()) { + // 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 - // repainted. - ThebesDisplayItemLayerUserData* data = - static_cast(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData)); nsIntPoint paintOffset = GetTranslationForThebesLayer(newThebesLayer); nsPoint offset((paintOffset.x + data->mActiveScrolledRootPosition.x) * mAppUnitsPerDevPixel / data->mXScale, (paintOffset.y + data->mActiveScrolledRootPosition.y) * mAppUnitsPerDevPixel / data->mYScale); nsPoint prevOffset((oldGeometry->mPaintOffset.x + oldGeometry->mActiveScrolledRootPosition.x) * oldGeometry->mAppUnitsPerDevPixel / data->mXScale, (oldGeometry->mPaintOffset.y + oldGeometry->mActiveScrolledRootPosition.y) * oldGeometry->mAppUnitsPerDevPixel / data->mYScale); nsPoint shift = offset - prevOffset; + // Let the display item check for geometry changes and decide what needs to be + // repainted. 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); @@ -3158,6 +3160,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 (PRUint32 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(nsTArray aRects, PRInt32 A2D) { diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index 72d3ed2409de..e39a1bf06547 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -398,6 +398,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; @@ -460,6 +465,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)) && diff --git a/layout/base/nsDisplayListInvalidation.h b/layout/base/nsDisplayListInvalidation.h index 8600522f0d76..53b957649067 100644 --- a/layout/base/nsDisplayListInvalidation.h +++ b/layout/base/nsDisplayListInvalidation.h @@ -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.