Bug 342874 - Use covered region to minimize svg painting. r+sr=roc

git-svn-id: svn://10.0.0.236/trunk@201370 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
tor%cs.brown.edu
2006-06-30 19:19:42 +00:00
parent 05b62880d1
commit 86c25b94a6
19 changed files with 60 additions and 40 deletions

View File

@@ -50,14 +50,16 @@ class nsIDOMSVGMatrix;
struct nsRect;
#define NS_ISVGCHILDFRAME_IID \
{ 0xa28b3f99, 0xdf64, 0x42eb, { 0x9e, 0x90, 0x63, 0x54, 0xd7, 0x46, 0x5b, 0x31 } }
{ 0xa365580d, 0x9d14, 0x4e33, { 0x99, 0xfa, 0x81, 0x07, 0x0d, 0xa0, 0xfe, 0xa6 } }
class nsISVGChildFrame : public nsISupports {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISVGCHILDFRAME_IID)
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas)=0;
// Paint this frame - aDirtyRect is the area being redrawn, in frame
// offset pixel coordinates
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect)=0;
// Check if this frame or children contain the given point,
// specified in device pixels relative to the origin of the outer
@@ -91,6 +93,9 @@ public:
// Are we a container frame?
NS_IMETHOD_(PRBool) IsDisplayContainer()=0;
// Does this frame have an current covered region in mRect (aka GetRect())?
NS_IMETHOD_(PRBool) HasValidCoveredRect()=0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGChildFrame, NS_ISVGCHILDFRAME_IID)

View File

@@ -207,11 +207,11 @@ nsSVGClipPathFrame::ClipPaint(nsISVGRendererCanvas* canvas,
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsISVGChildFrame* SVGFrame=nsnull;
kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
nsISVGChildFrame* SVGFrame = nsnull;
CallQueryInterface(kid, &SVGFrame);
if (SVGFrame) {
SVGFrame->NotifyCanvasTMChanged(PR_TRUE);
SVGFrame->PaintSVG(canvas);
SVGFrame->PaintSVG(canvas, nsnull);
}
}

View File

@@ -181,7 +181,8 @@ nsSVGDisplayContainerFrame::RemoveFrame(nsIAtom* aListName,
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGDisplayContainerFrame::PaintSVG(nsISVGRendererCanvas* canvas)
nsSVGDisplayContainerFrame::PaintSVG(nsISVGRendererCanvas* canvas,
nsRect *aDirtyRect)
{
const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
if (display->mOpacity == 0.0)
@@ -189,7 +190,7 @@ nsSVGDisplayContainerFrame::PaintSVG(nsISVGRendererCanvas* canvas)
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsSVGUtils::PaintChildWithEffects(canvas, kid);
nsSVGUtils::PaintChildWithEffects(canvas, aDirtyRect, kid);
}
return NS_OK;

View File

@@ -104,7 +104,7 @@ public:
nsIFrame* aOldFrame);
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas);
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect);
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
@@ -116,6 +116,7 @@ public:
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM) { return NS_ERROR_FAILURE; }
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_TRUE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_FALSE; }
};
#endif

View File

@@ -243,7 +243,7 @@ nsSVGFilterFrame::FilterFailCleanup(nsISVGRendererCanvas *aCanvas,
aTarget->SetOverrideCTM(nsnull);
aTarget->SetMatrixPropagation(PR_TRUE);
aTarget->NotifyCanvasTMChanged(PR_TRUE);
aTarget->PaintSVG(aCanvas);
aTarget->PaintSVG(aCanvas, nsnull);
}
NS_IMETHODIMP
@@ -281,7 +281,7 @@ nsSVGFilterFrame::FilterPaint(nsISVGRendererCanvas *aCanvas,
if (unimplementedFilter)
fprintf(stderr, "FilterFrame: unimplemented filter element\n");
#endif
aTarget->PaintSVG(aCanvas);
aTarget->PaintSVG(aCanvas, nsnull);
return NS_OK;
}
@@ -371,7 +371,7 @@ nsSVGFilterFrame::FilterPaint(nsISVGRendererCanvas *aCanvas,
}
aCanvas->PushSurface(surface, PR_FALSE);
aTarget->PaintSVG(aCanvas);
aTarget->PaintSVG(aCanvas, nsnull);
aCanvas->PopSurface();
mPrimitiveUnits->GetAnimVal(&type);

View File

@@ -211,7 +211,8 @@ TransformRect(float* aX, float *aY, float* aWidth, float *aHeight,
}
NS_IMETHODIMP
nsSVGForeignObjectFrame::PaintSVG(nsISVGRendererCanvas* canvas)
nsSVGForeignObjectFrame::PaintSVG(nsISVGRendererCanvas* canvas,
nsRect *aDirtyRect)
{
nsIFrame* kid = GetFirstChild(nsnull);
if (!kid)

View File

@@ -107,7 +107,7 @@ public:
// implementation inherited from nsSupportsWeakReference
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas);
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect);
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
@@ -119,6 +119,7 @@ public:
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_TRUE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_FALSE; }
// foreignobject public methods
/**

View File

@@ -233,7 +233,7 @@ nsSVGGlyphFrame::IsFrameOfType(PRUint32 aFlags) const
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGGlyphFrame::PaintSVG(nsISVGRendererCanvas* canvas)
nsSVGGlyphFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect)
{
#ifdef DEBUG
//printf("nsSVGGlyphFrame(%p)::Paint\n", this);

View File

@@ -100,7 +100,7 @@ public:
#endif
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas);
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect);
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
@@ -112,6 +112,7 @@ public:
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM) { return NS_ERROR_FAILURE; }
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_FALSE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_TRUE; }
// nsISVGGeometrySource interface:
NS_IMETHOD GetCanvasTM(nsIDOMSVGMatrix * *aCTM);

View File

@@ -88,7 +88,7 @@ public:
nsSVGImageFrame(nsStyleContext* aContext) : nsSVGPathGeometryFrame(aContext) {}
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas);
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect);
// nsSVGGeometryFrame overload:
// Lie about our fill/stroke so hit detection works
@@ -213,7 +213,7 @@ nsSVGImageFrame::AttributeChanged(PRInt32 aNameSpaceID,
//----------------------------------------------------------------------
// nsISVGChildFrame methods:
NS_IMETHODIMP
nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas)
nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect)
{
if (!GetStyleVisibility()->IsVisible())
return NS_OK;

View File

@@ -88,7 +88,7 @@ public:
#endif
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas);
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect);
NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation);
NS_IMETHOD SetMatrixPropagation(PRBool aPropagate);
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
@@ -173,7 +173,7 @@ nsSVGInnerSVGFrame::GetType() const
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas)
nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect)
{
#ifdef DEBUG
// printf("nsSVGInnerSVG(%p)::Paint\n", this);
@@ -200,7 +200,7 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas)
canvas->SetClipRect(clipTransform, x, y, width, height);
}
nsSVGInnerSVGFrameBase::PaintSVG(canvas);
nsSVGInnerSVGFrameBase::PaintSVG(canvas, aDirtyRect);
canvas->PopClip();

View File

@@ -265,7 +265,7 @@ nsSVGMarkerFrame::PaintMark(nsISVGRendererCanvas *aCanvas,
kid->QueryInterface(NS_GET_IID(nsISVGChildFrame),(void**)&SVGFrame);
if (SVGFrame) {
SVGFrame->NotifyCanvasTMChanged(PR_TRUE);
nsSVGUtils::PaintChildWithEffects(aCanvas, kid);
nsSVGUtils::PaintChildWithEffects(aCanvas, nsnull, kid);
}
}

View File

@@ -266,7 +266,7 @@ nsSVGMaskFrame::MaskPaint(nsISVGRendererCanvas* aCanvas,
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsSVGUtils::PaintChildWithEffects(aCanvas, kid);
nsSVGUtils::PaintChildWithEffects(aCanvas, nsnull, kid);
}
aCanvas->PopSurface();

View File

@@ -404,15 +404,6 @@ nsSVGOuterSVGFrame::Paint(nsIRenderingContext& aRenderingContext,
PRTime start = PR_Now();
#endif
float pxPerTwips = GetPxPerTwips();
int x0 = (int)(dirtyRect.x*pxPerTwips);
int y0 = (int)(dirtyRect.y*pxPerTwips);
int x1 = (int)ceil((dirtyRect.XMost())*pxPerTwips);
int y1 = (int)ceil((dirtyRect.YMost())*pxPerTwips);
NS_ASSERTION(x0>=0 && y0>=0, "unexpected negative coordinates");
NS_ASSERTION(x1-x0>0 && y1-y0>0, "zero sized dirtyRect");
nsRect dirtyRectPx(x0, y0, x1-x0, y1-y0);
// If we don't have a renderer due to the component failing
// to load (gdi+ or cairo not available), indicate to the user
// what's going on by drawing a red "X" at the appropriate spot.
@@ -424,16 +415,18 @@ nsSVGOuterSVGFrame::Paint(nsIRenderingContext& aRenderingContext,
return;
}
dirtyRect.ScaleRoundOut(GetPxPerTwips());
nsCOMPtr<nsISVGRendererCanvas> canvas;
mRenderer->CreateCanvas(&aRenderingContext, GetPresContext(), dirtyRectPx,
mRenderer->CreateCanvas(&aRenderingContext, GetPresContext(), dirtyRect,
getter_AddRefs(canvas));
// paint children:
for (nsIFrame* kid = mFrames.FirstChild(); kid;
kid = kid->GetNextSibling()) {
nsSVGUtils::PaintChildWithEffects(canvas, kid);
nsSVGUtils::PaintChildWithEffects(canvas, &dirtyRect, kid);
}
canvas->Flush();
canvas = nsnull;

View File

@@ -277,7 +277,8 @@ nsSVGPathGeometryFrame::UpdateMarkerProperty()
// nsISVGChildFrame methods
NS_IMETHODIMP
nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas)
nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas,
nsRect *aDirtyRect)
{
if (!GetStyleVisibility()->IsVisible())
return NS_OK;

View File

@@ -109,7 +109,7 @@ protected:
nsISVGValue::modificationType aModType);
// nsISVGChildFrame interface:
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas);
NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect);
NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit);
NS_IMETHOD_(nsRect) GetCoveredRegion();
NS_IMETHOD UpdateCoveredRegion();
@@ -121,6 +121,7 @@ protected:
NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM);
NS_IMETHOD GetBBox(nsIDOMSVGRect **_retval);
NS_IMETHOD_(PRBool) IsDisplayContainer() { return PR_FALSE; }
NS_IMETHOD_(PRBool) HasValidCoveredRect() { return PR_TRUE; }
// nsISVGGeometrySource interface:
virtual nsresult UpdateGraphic(PRBool suppressInvalidation = PR_FALSE);

View File

@@ -292,7 +292,7 @@ nsSVGPatternFrame::PaintPattern(nsISVGRendererCanvas* canvas,
nsRect dummyRect;
for (nsIFrame* kid = firstKid; kid;
kid = kid->GetNextSibling()) {
nsSVGUtils::PaintChildWithEffects(canvas, kid);
nsSVGUtils::PaintChildWithEffects(canvas, nsnull, kid);
}
mSource = nsnull;

View File

@@ -622,6 +622,7 @@ GetMaskSurface(nsISVGRendererCanvas *aCanvas, nsIFrame *aFrame, float opacity)
void
nsSVGUtils::PaintChildWithEffects(nsISVGRendererCanvas *aCanvas,
nsRect *aDirtyRect,
nsIFrame *aFrame)
{
nsISVGChildFrame *svgChildFrame;
@@ -639,6 +640,17 @@ nsSVGUtils::PaintChildWithEffects(nsISVGRendererCanvas *aCanvas,
AddEffectProperties(aFrame);
nsFrameState state = aFrame->GetStateBits();
/* Check if we need to draw anything */
if (aDirtyRect) {
if (state & NS_STATE_SVG_FILTERED) {
if (!aDirtyRect->Intersects(FindFilterInvalidation(aFrame)))
return;
} else if (svgChildFrame->HasValidCoveredRect()) {
if (!aDirtyRect->Intersects(aFrame->GetRect()))
return;
}
}
/* SVG defines the following rendering model:
*
* 1. Render geometry
@@ -688,7 +700,7 @@ nsSVGUtils::PaintChildWithEffects(nsISVGRendererCanvas *aCanvas,
aFrame->GetProperty(nsGkAtoms::filter));
property->mFilter->FilterPaint(aCanvas, svgChildFrame);
} else {
svgChildFrame->PaintSVG(aCanvas);
svgChildFrame->PaintSVG(aCanvas, aDirtyRect);
}
if (state & NS_STATE_SVG_CLIPPED_TRIVIAL) {

View File

@@ -171,9 +171,12 @@ public:
nsIDOMSVGAnimatedPreserveAspectRatio *aPreserveAspectRatio,
PRBool aIgnoreAlign = PR_FALSE);
/* Paint frame with SVG effects */
/* Paint frame with SVG effects - aDirtyRect is the area being
* redrawn, in frame offset pixel coordinates */
static void
PaintChildWithEffects(nsISVGRendererCanvas *aCanvas, nsIFrame *aFrame);
PaintChildWithEffects(nsISVGRendererCanvas *aCanvas,
nsRect *aDirtyRect,
nsIFrame *aFrame);
/* Style change for effects (filter/clip/mask/opacity) - call when
* the frame's style has changed to make sure the effects properties