diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp index 3952833c0286..3b1bfe0afe85 100644 --- a/layout/svg/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/nsSVGForeignObjectFrame.cpp @@ -613,3 +613,18 @@ nsSVGForeignObjectFrame::DoReflow() mInReflow = false; } +nsRect +nsSVGForeignObjectFrame::GetInvalidRegion() +{ + nsIFrame* kid = GetFirstPrincipalChild(); + if (kid->HasInvalidFrameInSubtree()) { + gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height); + r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel()); + nsRect rect = ToCanvasBounds(r, GetCanvasTM(FOR_PAINTING), PresContext()); + rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect); + return rect; + } + return nsRect(); +} + + diff --git a/layout/svg/nsSVGForeignObjectFrame.h b/layout/svg/nsSVGForeignObjectFrame.h index da11611163c8..d9cd2903f88a 100644 --- a/layout/svg/nsSVGForeignObjectFrame.h +++ b/layout/svg/nsSVGForeignObjectFrame.h @@ -90,6 +90,8 @@ public: gfxMatrix GetCanvasTM(uint32_t aFor); + nsRect GetInvalidRegion(); + protected: // implementation helpers: void DoReflow(); diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index d69f7517f1b7..9cad61533d5f 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -280,9 +280,9 @@ nsRect return overflowRect - (aFrame->GetOffsetTo(firstFrame) + firstFrameToUserSpace); } -nsRect +nsIntRect nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, - const nsRect& aInvalidRect) + const nsIntRect& aInvalidRect) { // Don't bother calling GetEffectProperties; the filter property should // already have been set up during reflow/ComputeFrameEffectsRect @@ -298,22 +298,26 @@ nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, return aInvalidRect; } + int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); + nsSVGFilterFrame* filterFrame = prop->GetFilterFrame(); if (!filterFrame) { // The frame is either not there or not currently available, // perhaps because we're in the middle of tearing stuff down. // Be conservative. - return aFrame->GetVisualOverflowRect(); + nsRect overflow = aFrame->GetVisualOverflowRect(); + return overflow.ToOutsidePixels(appUnitsPerDevPixel); } // Convert aInvalidRect into "user space" in app units: nsPoint toUserSpace = aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame); - nsRect preEffectsRect = aInvalidRect + toUserSpace; + nsRect preEffectsRect = aInvalidRect.ToAppUnits(appUnitsPerDevPixel) + toUserSpace; // Return ther result, relative to aFrame, not in user space: - return filterFrame->GetPostFilterDirtyArea(firstFrame, preEffectsRect) - + nsRect result = filterFrame->GetPostFilterDirtyArea(firstFrame, preEffectsRect) - toUserSpace; + return result.ToOutsidePixels(appUnitsPerDevPixel); } nsRect diff --git a/layout/svg/nsSVGIntegrationUtils.h b/layout/svg/nsSVGIntegrationUtils.h index 4e883a605559..16d157e5cb19 100644 --- a/layout/svg/nsSVGIntegrationUtils.h +++ b/layout/svg/nsSVGIntegrationUtils.h @@ -116,8 +116,8 @@ public: * Used to adjust the area of a frame that needs to be invalidated to take * account of SVG effects. */ - static nsRect - AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, const nsRect& aInvalidRect); + static nsIntRect + AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, const nsIntRect& aInvalidRect); /** * Figure out which area of the source is needed given an area to diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp index 9280cb5807ba..a6821f3dfe62 100644 --- a/layout/svg/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/nsSVGOuterSVGFrame.cpp @@ -22,6 +22,7 @@ #include "nsSVGSVGElement.h" #include "nsSVGTextFrame.h" #include "nsSVGViewElement.h" +#include "nsSubDocumentFrame.h" namespace dom = mozilla::dom; @@ -505,6 +506,11 @@ public: HitTestState* aState, nsTArray *aOutFrames); virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx); + + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion); + NS_DISPLAY_DECL_NAME("SVGOuterSVG", TYPE_SVG_OUTER_SVG) }; @@ -570,6 +576,39 @@ nsDisplayOuterSVG::Paint(nsDisplayListBuilder* aBuilder, #endif } +static PLDHashOperator CheckForeignObjectInvalidatedArea(nsPtrHashKey* aEntry, void* aData) +{ + nsRegion* region = static_cast(aData); + region->Or(*region, aEntry->GetKey()->GetInvalidRegion()); + return PL_DHASH_NEXT; +} + +nsRegion +nsSVGOuterSVGFrame::FindInvalidatedForeignObjectFrameChildren(nsIFrame* aFrame) +{ + nsRegion result; + if (mForeignObjectHash.Count()) { + mForeignObjectHash.EnumerateEntries(CheckForeignObjectInvalidatedArea, &result); + } + return result; +} + +void +nsDisplayOuterSVG::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, + const nsDisplayItemGeometry* aGeometry, + nsRegion* aInvalidRegion) +{ + nsSVGOuterSVGFrame *frame = static_cast(mFrame); + frame->InvalidateSVG(frame->FindInvalidatedForeignObjectFrameChildren(frame)); + + nsRegion result = frame->GetInvalidRegion(); + result.MoveBy(ToReferenceFrame()); + frame->ClearInvalidRegion(); + + nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); + aInvalidRegion->Or(*aInvalidRegion, result); +} + // helper static inline bool DependsOnIntrinsicSize(const nsIFrame* aEmbeddingFrame) diff --git a/layout/svg/nsSVGOuterSVGFrame.h b/layout/svg/nsSVGOuterSVGFrame.h index 82d19194361b..49a2d0e0b4c8 100644 --- a/layout/svg/nsSVGOuterSVGFrame.h +++ b/layout/svg/nsSVGOuterSVGFrame.h @@ -144,6 +144,25 @@ public: return mCallingReflowSVG; } + void InvalidateSVG(const nsRegion& aRegion) + { + if (!aRegion.IsEmpty()) { + mInvalidRegion.Or(mInvalidRegion, aRegion); + InvalidateFrame(); + } + } + + void ClearInvalidRegion() { mInvalidRegion.SetEmpty(); } + + const nsRegion& GetInvalidRegion() { + if (!IsInvalid()) { + mInvalidRegion.SetEmpty(); + } + return mInvalidRegion; + } + + nsRegion FindInvalidatedForeignObjectFrameChildren(nsIFrame* aFrame); + protected: bool mCallingReflowSVG; @@ -164,10 +183,12 @@ protected: // A hash-set containing our nsSVGForeignObjectFrame descendants. Note we use // a hash-set to avoid the O(N^2) behavior we'd get tearing down an SVG frame // subtree if we were to use a list (see bug 381285 comment 20). - nsTHashtable mForeignObjectHash; + nsTHashtable > mForeignObjectHash; nsAutoPtr mCanvasTM; + nsRegion mInvalidRegion; + float mFullZoom; bool mViewportInitialized; diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index b6b3af90a9fb..6af829de6b27 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -415,6 +415,14 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate, return; } + aFrame->InvalidateFrameSubtree(); + + if ((aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame || + aFrame->GetType() == nsGkAtoms::svgGlyphFrame) && + NS_SVGDisplayListPaintingEnabled()) { + return; + } + // Okay, so now we pass the area that needs to be invalidated up our parent // chain, accounting for filter effects and transforms as we go, until we // reach our nsSVGOuterSVGFrame where we can invalidate: @@ -479,8 +487,7 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate, NS_ASSERTION(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG, "SVG frames must always have an nsSVGOuterSVGFrame ancestor!"); - static_cast(aFrame)->InvalidateWithFlags(invalidArea, - aFlags); + static_cast(aFrame)->InvalidateSVG(invalidArea); } void