Bug 539356 - Part 9d - Make SVG support the new invalidation model. r=jwatt

This commit is contained in:
Matt Woodrow 2012-08-29 17:39:33 +12:00
parent cee1aa3599
commit da86ec189f
7 changed files with 98 additions and 10 deletions

View File

@ -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();
}

View File

@ -90,6 +90,8 @@ public:
gfxMatrix GetCanvasTM(uint32_t aFor);
nsRect GetInvalidRegion();
protected:
// implementation helpers:
void DoReflow();

View File

@ -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

View File

@ -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

View File

@ -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<nsIFrame*> *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<nsSVGForeignObjectFrame>* aEntry, void* aData)
{
nsRegion* region = static_cast<nsRegion*>(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<nsSVGOuterSVGFrame*>(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)

View File

@ -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<nsVoidPtrHashKey> mForeignObjectHash;
nsTHashtable<nsPtrHashKey<nsSVGForeignObjectFrame> > mForeignObjectHash;
nsAutoPtr<gfxMatrix> mCanvasTM;
nsRegion mInvalidRegion;
float mFullZoom;
bool mViewportInitialized;

View File

@ -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<nsSVGOuterSVGFrame*>(aFrame)->InvalidateWithFlags(invalidArea,
aFlags);
static_cast<nsSVGOuterSVGFrame*>(aFrame)->InvalidateSVG(invalidArea);
}
void