Bug 377015 - Simplify nsSVGClipPathFrame API and make clip reference loop detection more robust. r=jwatt,sr=tor

This commit is contained in:
longsonr@gmail.com 2007-04-17 02:01:52 -07:00
parent adf8e096fb
commit 09edc1c88b
4 changed files with 48 additions and 52 deletions

View File

@ -101,10 +101,10 @@ nsSVGClipPathFrame::InitSVG()
return NS_OK;
}
NS_IMETHODIMP
nsresult
nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix)
nsIDOMSVGMatrix *aMatrix)
{
// If the flag is set when we get here, it means this clipPath frame
// has already been used painting the current clip, and the document
@ -113,13 +113,12 @@ nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
NS_WARNING("Clip loop detected!");
return NS_OK;
}
mInUse = PR_TRUE;
AutoClipPathReferencer clipRef(this);
mClipParent = aParent,
mClipParentMatrix = aMatrix;
PRBool isTrivial;
IsTrivial(&isTrivial);
PRBool isTrivial = IsTrivial();
nsAutoSVGRenderMode mode(aContext,
isTrivial ? nsSVGRenderState::CLIP
@ -140,26 +139,22 @@ nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
aContext->GetGfxContext()->NewPath();
}
mInUse = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
PRBool
nsSVGClipPathFrame::ClipHitTest(nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix,
float aX, float aY, PRBool *aHit)
nsIDOMSVGMatrix *aMatrix,
float aX, float aY)
{
*aHit = PR_FALSE;
// If the flag is set when we get here, it means this clipPath frame
// has already been used in hit testing against the current clip,
// and the document has a clip reference loop.
if (mInUse) {
NS_WARNING("Clip loop detected!");
return NS_OK;
return PR_FALSE;
}
mInUse = PR_TRUE;
AutoClipPathReferencer clipRef(this);
nsRect dirty;
mClipParent = aParent,
@ -177,23 +172,16 @@ nsSVGClipPathFrame::ClipHitTest(nsISVGChildFrame* aParent,
nsIFrame *temp = nsnull;
nsresult rv = SVGFrame->GetFrameForPointSVG(aX, aY, &temp);
if (NS_SUCCEEDED(rv) && temp) {
*aHit = PR_TRUE;
mInUse = PR_FALSE;
return NS_OK;
}
if (NS_SUCCEEDED(rv) && temp)
return PR_TRUE;
}
}
mInUse = PR_FALSE;
return NS_OK;
return PR_FALSE;
}
NS_IMETHODIMP
nsSVGClipPathFrame::IsTrivial(PRBool *aTrivial)
PRBool
nsSVGClipPathFrame::IsTrivial()
{
*aTrivial = PR_TRUE;
PRBool foundChild = PR_FALSE;
for (nsIFrame* kid = mFrames.FirstChild(); kid;
@ -204,15 +192,12 @@ nsSVGClipPathFrame::IsTrivial(PRBool *aTrivial)
if (svgChild) {
// We consider a non-trivial clipPath to be one containing
// either more than one svg child and/or a svg container
if (foundChild || svgChild->IsDisplayContainer()) {
*aTrivial = PR_FALSE;
return NS_OK;
}
if (foundChild || svgChild->IsDisplayContainer())
return PR_FALSE;
foundChild = PR_TRUE;
}
}
return NS_OK;
return PR_TRUE;
}
nsIAtom *

View File

@ -48,22 +48,22 @@ class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
NS_IMETHOD InitSVG();
public:
nsSVGClipPathFrame(nsStyleContext* aContext) : nsSVGClipPathFrameBase(aContext) {}
public:
// nsSVGClipPathFrame methods:
NS_IMETHOD ClipPaint(nsSVGRenderState* aContext,
nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix);
nsresult ClipPaint(nsSVGRenderState* aContext,
nsISVGChildFrame* aParent,
nsIDOMSVGMatrix *aMatrix);
NS_IMETHOD ClipHitTest(nsISVGChildFrame* aParent,
nsCOMPtr<nsIDOMSVGMatrix> aMatrix,
float aX, float aY, PRBool *aHit);
PRBool ClipHitTest(nsISVGChildFrame* aParent,
nsIDOMSVGMatrix *aMatrix,
float aX, float aY);
// Check if this clipPath is made up of more than one geometry object.
// If so, the clipping API in cairo isn't enough and we need to use
// mask based clipping.
NS_IMETHOD IsTrivial(PRBool *aTrivial);
PRBool IsTrivial();
/**
* Get the "type" of the frame
@ -80,6 +80,24 @@ class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
#endif
private:
// A helper class to allow us to paint clip paths safely. The helper
// automatically sets and clears the mInUse flag on the clip path frame
// (to prevent nasty reference loops). It's easy to mess this up
// and break things, so this helper makes the code far more robust.
class AutoClipPathReferencer
{
public:
AutoClipPathReferencer(nsSVGClipPathFrame *aFrame) {
NS_ASSERTION(mFrame->mInUse == PR_FALSE, "reference loop!");
mFrame->mInUse = PR_TRUE;
}
~AutoClipPathReferencer() {
mFrame->mInUse = PR_FALSE;
}
private:
nsSVGClipPathFrame *mFrame;
};
nsISVGChildFrame *mClipParent;
nsCOMPtr<nsIDOMSVGMatrix> mClipParentMatrix;

View File

@ -40,7 +40,6 @@
#include "nsSVGGFrame.h"
#include "nsIFrame.h"
#include "nsSVGMatrix.h"
#include "nsSVGClipPathFrame.h"
#include "nsGkAtoms.h"
#include "nsSVGUtils.h"
#include "nsISVGValueUtils.h"

View File

@ -811,13 +811,9 @@ AddEffectProperties(nsIFrame *aFrame)
aFrame->GetContent());
if (clip) {
aFrame->SetProperty(nsGkAtoms::clipPath, clip);
PRBool trivialClip;
clip->IsTrivial(&trivialClip);
if (trivialClip)
aFrame->AddStateBits(NS_STATE_SVG_CLIPPED_TRIVIAL);
else
aFrame->AddStateBits(NS_STATE_SVG_CLIPPED_COMPLEX);
aFrame->AddStateBits(clip->IsTrivial() ?
NS_STATE_SVG_CLIPPED_TRIVIAL :
NS_STATE_SVG_CLIPPED_COMPLEX);
}
}
@ -1038,8 +1034,6 @@ nsSVGUtils::StyleEffects(nsIFrame *aFrame)
PRBool
nsSVGUtils::HitTestClip(nsIFrame *aFrame, float x, float y)
{
PRBool clipHit = PR_TRUE;
nsISVGChildFrame* SVGFrame;
CallQueryInterface(aFrame, &SVGFrame);
@ -1048,10 +1042,10 @@ nsSVGUtils::HitTestClip(nsIFrame *aFrame, float x, float y)
clip = NS_STATIC_CAST(nsSVGClipPathFrame *,
aFrame->GetProperty(nsGkAtoms::clipPath));
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM(aFrame);
clip->ClipHitTest(SVGFrame, matrix, x, y, &clipHit);
return clip->ClipHitTest(SVGFrame, matrix, x, y);
}
return clipHit;
return PR_TRUE;
}
void