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:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user