From ea3f06c6f035fec29cc9359f721985e4168462a7 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Wed, 29 Aug 2012 17:39:33 +1200 Subject: [PATCH] Bug 539356 - Part 9d - Make SVG support the new invalidation model. r=jwatt --- layout/svg/nsSVGForeignObjectFrame.cpp | 15 ++++++++++ layout/svg/nsSVGForeignObjectFrame.h | 2 ++ layout/svg/nsSVGIntegrationUtils.cpp | 14 +++++---- layout/svg/nsSVGIntegrationUtils.h | 4 +-- layout/svg/nsSVGOuterSVGFrame.cpp | 39 ++++++++++++++++++++++++++ layout/svg/nsSVGOuterSVGFrame.h | 23 ++++++++++++++- layout/svg/nsSVGUtils.cpp | 11 ++++++-- 7 files changed, 98 insertions(+), 10 deletions(-) diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp index 3952833c028..3b1bfe0afe8 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 da11611163c..d9cd2903f88 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 d69f7517f1b..9cad61533d5 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 4e883a60555..16d157e5cb1 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 9280cb5807b..a6821f3dfe6 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 82d19194361..49a2d0e0b4c 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 b6b3af90a9f..6af829de6b2 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