nsresult nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext, nsISVGChildFrame* aParent, 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 // has a clip reference loop. if (mInUse) { NS_WARNING("Clip loop detected!"); return NS_OK; } AutoClipPathReferencer clipRef(this); mClipParent = aParent, mClipParentMatrix = aMatrix; PRBool isTrivial = IsTrivial(); nsAutoSVGRenderMode mode(aContext, isTrivial ? nsSVGRenderState::CLIP : nsSVGRenderState::CLIP_MASK); for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = nsnull; CallQueryInterface(kid, &SVGFrame); if (SVGFrame) { // The CTM of each frame referencing us can be different. SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION | nsISVGChildFrame::TRANSFORM_CHANGED); SVGFrame->PaintSVG(aContext, nsnull); } } if (isTrivial) { aContext->GetGfxContext()->Clip(); aContext->GetGfxContext()->NewPath(); } return NS_OK; }
bool nsSVGClipPathFrame::ClipHitTest(nsIFrame* aParent, const gfxMatrix &aMatrix, const nsPoint &aPoint) { // 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 false; } AutoClipPathReferencer clipRef(this); mClipParent = aParent; if (mClipParentMatrix) { *mClipParentMatrix = aMatrix; } else { mClipParentMatrix = new gfxMatrix(aMatrix); } nsSVGClipPathFrame *clipPathFrame = nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull); if (clipPathFrame && !clipPathFrame->ClipHitTest(aParent, aMatrix, aPoint)) return false; for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); if (SVGFrame) { // Notify the child frame that we may be working with a // different transform, so it can update its covered region // (used to shortcut hit testing). SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED); if (SVGFrame->GetFrameForPoint(aPoint)) return true; } } return false; }
bool nsSVGClipPathFrame::IsValid() { if (mInUse) { NS_WARNING("Clip loop detected!"); return false; } AutoClipPathReferencer clipRef(this); bool isOK = true; nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(&isOK); if (!isOK) { return false; } for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsIAtom *type = kid->GetType(); if (type == nsGkAtoms::svgUseFrame) { for (nsIFrame* grandKid = kid->GetFirstPrincipalChild(); grandKid; grandKid = grandKid->GetNextSibling()) { nsIAtom *type = grandKid->GetType(); if (type != nsGkAtoms::svgPathGeometryFrame && type != nsGkAtoms::svgTextFrame) { return false; } } continue; } if (type != nsGkAtoms::svgPathGeometryFrame && type != nsGkAtoms::svgTextFrame) { return false; } } return true; }
PRBool nsSVGClipPathFrame::ClipHitTest(nsISVGChildFrame* aParent, nsIDOMSVGMatrix *aMatrix, float aX, float aY) { // 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 PR_FALSE; } AutoClipPathReferencer clipRef(this); nsRect dirty; mClipParent = aParent, mClipParentMatrix = aMatrix; for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = nsnull; CallQueryInterface(kid, &SVGFrame); if (SVGFrame) { // Notify the child frame that we may be working with a // different transform, so it can update its covered region // (used to shortcut hit testing). SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED); nsIFrame *temp = nsnull; nsresult rv = SVGFrame->GetFrameForPointSVG(aX, aY, &temp); if (NS_SUCCEEDED(rv) && temp) return PR_TRUE; } } return PR_FALSE; }
nsresult nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext, nsIFrame* aParent, const gfxMatrix &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 // has a clip reference loop. if (mInUse) { NS_WARNING("Clip loop detected!"); return NS_OK; } AutoClipPathReferencer clipRef(this); mClipParent = aParent; if (mClipParentMatrix) { *mClipParentMatrix = aMatrix; } else { mClipParentMatrix = new gfxMatrix(aMatrix); } bool isTrivial = IsTrivial(); nsAutoSVGRenderMode mode(aContext, isTrivial ? nsSVGRenderState::CLIP : nsSVGRenderState::CLIP_MASK); gfxContext *gfx = aContext->GetGfxContext(); nsSVGClipPathFrame *clipPathFrame = nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull); bool referencedClipIsTrivial; if (clipPathFrame) { referencedClipIsTrivial = clipPathFrame->IsTrivial(); gfx->Save(); if (referencedClipIsTrivial) { clipPathFrame->ClipPaint(aContext, aParent, aMatrix); } else { gfx->PushGroup(gfxASurface::CONTENT_ALPHA); } } for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); if (SVGFrame) { // The CTM of each frame referencing us can be different. SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION | nsISVGChildFrame::TRANSFORM_CHANGED); bool isOK = true; nsSVGClipPathFrame *clipPathFrame = nsSVGEffects::GetEffectProperties(kid).GetClipPathFrame(&isOK); if (!isOK) { continue; } bool isTrivial; if (clipPathFrame) { isTrivial = clipPathFrame->IsTrivial(); gfx->Save(); if (isTrivial) { clipPathFrame->ClipPaint(aContext, aParent, aMatrix); } else { gfx->PushGroup(gfxASurface::CONTENT_ALPHA); } } SVGFrame->PaintSVG(aContext, nsnull); if (clipPathFrame) { if (!isTrivial) { gfx->PopGroupToSource(); nsRefPtr<gfxPattern> clipMaskSurface; gfx->PushGroup(gfxASurface::CONTENT_ALPHA); clipPathFrame->ClipPaint(aContext, aParent, aMatrix); clipMaskSurface = gfx->PopGroup(); if (clipMaskSurface) { gfx->Mask(clipMaskSurface); } } gfx->Restore(); } } } if (clipPathFrame) { if (!referencedClipIsTrivial) { gfx->PopGroupToSource(); nsRefPtr<gfxPattern> clipMaskSurface; gfx->PushGroup(gfxASurface::CONTENT_ALPHA); clipPathFrame->ClipPaint(aContext, aParent, aMatrix); clipMaskSurface = gfx->PopGroup(); if (clipMaskSurface) { gfx->Mask(clipMaskSurface); } } gfx->Restore(); } if (isTrivial) { gfx->Clip(); gfx->NewPath(); } return NS_OK; }
nsresult nsSVGClipPathFrame::ClipPaint(nsRenderingContext* aContext, nsIFrame* aParent, const gfxMatrix &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 // has a clip reference loop. if (mInUse) { NS_WARNING("Clip loop detected!"); return NS_OK; } AutoClipPathReferencer clipRef(this); mClipParent = aParent; if (mClipParentMatrix) { *mClipParentMatrix = aMatrix; } else { mClipParentMatrix = new gfxMatrix(aMatrix); } gfxContext *gfx = aContext->ThebesContext(); nsISVGChildFrame *singleClipPathChild = nsnull; if (IsTrivial(&singleClipPathChild)) { // Notify our child that it's painting as part of a clipPath, and that // we only require it to draw its path (it should skip filling, etc.): SVGAutoRenderState mode(aContext, SVGAutoRenderState::CLIP); if (!singleClipPathChild) { // We have no children - the spec says clip away everything: gfx->Rectangle(gfxRect()); } else { singleClipPathChild->NotifySVGChanged( nsISVGChildFrame::DO_NOT_NOTIFY_RENDERING_OBSERVERS | nsISVGChildFrame::TRANSFORM_CHANGED); singleClipPathChild->PaintSVG(aContext, nsnull); } gfx->Clip(); gfx->NewPath(); return NS_OK; } // Seems like this is a non-trivial clipPath, so we need to use a clip mask. // Notify our children that they're painting into a clip mask: SVGAutoRenderState mode(aContext, SVGAutoRenderState::CLIP_MASK); // Check if this clipPath is itself clipped by another clipPath: nsSVGClipPathFrame *clipPathFrame = nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull); bool referencedClipIsTrivial; if (clipPathFrame) { referencedClipIsTrivial = clipPathFrame->IsTrivial(); gfx->Save(); if (referencedClipIsTrivial) { clipPathFrame->ClipPaint(aContext, aParent, aMatrix); } else { gfx->PushGroup(gfxASurface::CONTENT_ALPHA); } } for (nsIFrame* kid = mFrames.FirstChild(); kid; kid = kid->GetNextSibling()) { nsISVGChildFrame* SVGFrame = do_QueryFrame(kid); if (SVGFrame) { // The CTM of each frame referencing us can be different. SVGFrame->NotifySVGChanged( nsISVGChildFrame::DO_NOT_NOTIFY_RENDERING_OBSERVERS | nsISVGChildFrame::TRANSFORM_CHANGED); bool isOK = true; nsSVGClipPathFrame *clipPathFrame = nsSVGEffects::GetEffectProperties(kid).GetClipPathFrame(&isOK); if (!isOK) { continue; } bool isTrivial; if (clipPathFrame) { isTrivial = clipPathFrame->IsTrivial(); gfx->Save(); if (isTrivial) { clipPathFrame->ClipPaint(aContext, aParent, aMatrix); } else { gfx->PushGroup(gfxASurface::CONTENT_ALPHA); } } SVGFrame->PaintSVG(aContext, nsnull); if (clipPathFrame) { if (!isTrivial) { gfx->PopGroupToSource(); nsRefPtr<gfxPattern> clipMaskSurface; gfx->PushGroup(gfxASurface::CONTENT_ALPHA); clipPathFrame->ClipPaint(aContext, aParent, aMatrix); clipMaskSurface = gfx->PopGroup(); if (clipMaskSurface) { gfx->Mask(clipMaskSurface); } } gfx->Restore(); } } } if (clipPathFrame) { if (!referencedClipIsTrivial) { gfx->PopGroupToSource(); nsRefPtr<gfxPattern> clipMaskSurface; gfx->PushGroup(gfxASurface::CONTENT_ALPHA); clipPathFrame->ClipPaint(aContext, aParent, aMatrix); clipMaskSurface = gfx->PopGroup(); if (clipMaskSurface) { gfx->Mask(clipMaskSurface); } } gfx->Restore(); } return NS_OK; }