From cbc768243c0572c364fd16ba7e8f0e75ba24fdc4 Mon Sep 17 00:00:00 2001 From: "tor%cs.brown.edu" Date: Mon, 30 Jan 2006 17:53:26 +0000 Subject: [PATCH] Bug 324183 - masking and other surface operations inside a filter incorrect. r=scooter git-svn-id: svn://10.0.0.236/trunk@188470 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/layout/svg/base/src/nsSVGGFrame.cpp | 12 ++++--- .../layout/svg/base/src/nsSVGImageFrame.cpp | 12 ++++--- .../svg/base/src/nsSVGInnerSVGFrame.cpp | 12 ++++--- .../svg/base/src/nsSVGPathGeometryFrame.cpp | 12 ++++--- .../layout/svg/base/src/nsSVGTextFrame.cpp | 12 ++++--- mozilla/layout/svg/base/src/nsSVGUtils.cpp | 17 +++------- mozilla/layout/svg/base/src/nsSVGUtils.h | 4 ++- .../renderer/public/nsISVGRendererCanvas.idl | 7 +++- .../renderer/src/cairo/nsSVGCairoCanvas.cpp | 34 ++++++++++++++++--- .../src/gdiplus/nsSVGGDIPlusCanvas.cpp | 7 ++++ .../renderer/src/libart/nsSVGLibartCanvas.cpp | 7 ++++ 11 files changed, 97 insertions(+), 39 deletions(-) diff --git a/mozilla/layout/svg/base/src/nsSVGGFrame.cpp b/mozilla/layout/svg/base/src/nsSVGGFrame.cpp index 375fcbcf7cf..db88df708c3 100644 --- a/mozilla/layout/svg/base/src/nsSVGGFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGGFrame.cpp @@ -133,7 +133,8 @@ nsSVGGFrame::PaintSVG(nsISVGRendererCanvas* canvas, if (trivialClip) { canvas->PushClip(); } else { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipMaskSurface)); if (!clipMaskSurface) clip = nsnull; } @@ -155,7 +156,8 @@ nsSVGGFrame::PaintSVG(nsISVGRendererCanvas* canvas, NS_GetSVGMaskFrame(&mask, aURI, mContent); if (mask) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskSurface)); if (maskSurface) { nsCOMPtr matrix = GetCanvasTM(); @@ -167,7 +169,8 @@ nsSVGGFrame::PaintSVG(nsISVGRendererCanvas* canvas, } if (maskSurface || clipMaskSurface || display->mOpacity != 1.0) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskedSurface)); if (maskedSurface) { canvas->PushSurface(maskedSurface); } else @@ -190,7 +193,8 @@ nsSVGGFrame::PaintSVG(nsISVGRendererCanvas* canvas, maskSurface = clipMaskSurface; } else { nsCOMPtr clipped; - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipped)); canvas->PushSurface(clipped); canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface); diff --git a/mozilla/layout/svg/base/src/nsSVGImageFrame.cpp b/mozilla/layout/svg/base/src/nsSVGImageFrame.cpp index 27ff7ddde14..db2d587226d 100644 --- a/mozilla/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGImageFrame.cpp @@ -374,7 +374,8 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, if (trivialClip) { canvas->PushClip(); } else { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipMaskSurface)); if (!clipMaskSurface) clip = nsnull; } @@ -397,7 +398,8 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, NS_GetSVGMaskFrame(&mask, aURI, mContent); if (mask) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskSurface)); if (maskSurface) { nsCOMPtr matrix; @@ -409,7 +411,8 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, } if (maskSurface || clipMaskSurface) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskedSurface)); if (maskedSurface) { canvas->PushSurface(maskedSurface); } else @@ -522,7 +525,8 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, maskSurface = clipMaskSurface; } else { nsCOMPtr clipped; - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipped)); canvas->PushSurface(clipped); canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface); diff --git a/mozilla/layout/svg/base/src/nsSVGInnerSVGFrame.cpp b/mozilla/layout/svg/base/src/nsSVGInnerSVGFrame.cpp index b868cf65901..70cf9303632 100644 --- a/mozilla/layout/svg/base/src/nsSVGInnerSVGFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGInnerSVGFrame.cpp @@ -439,7 +439,8 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, clip->IsTrivial(&trivialClip); if (!trivialClip) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipMaskSurface)); if (!clipMaskSurface) clip = nsnull; } @@ -461,7 +462,8 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, NS_GetSVGMaskFrame(&mask, aURI, mContent); if (mask) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskSurface)); if (maskSurface) { nsCOMPtr matrix = GetCanvasTM(); @@ -473,7 +475,8 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, } if (maskSurface || clipMaskSurface || display->mOpacity != 1.0) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskedSurface)); if (maskedSurface) { canvas->PushSurface(maskedSurface); } else @@ -496,7 +499,8 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, maskSurface = clipMaskSurface; } else { nsCOMPtr clipped; - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipped)); canvas->PushSurface(clipped); canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface); diff --git a/mozilla/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/mozilla/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index 47625f53286..496c6e26971 100644 --- a/mozilla/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -284,7 +284,8 @@ nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas, if (trivialClip) { canvas->PushClip(); } else { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipMaskSurface)); if (!clipMaskSurface) clip = nsnull; } @@ -307,7 +308,8 @@ nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas, NS_GetSVGMaskFrame(&mask, aURI, mContent); if (mask) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskSurface)); if (maskSurface) { nsCOMPtr matrix; @@ -319,7 +321,8 @@ nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas, } if (maskSurface || clipMaskSurface) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskedSurface)); if (maskedSurface) { canvas->PushSurface(maskedSurface); } else @@ -369,7 +372,8 @@ nsSVGPathGeometryFrame::PaintSVG(nsISVGRendererCanvas* canvas, maskSurface = clipMaskSurface; } else { nsCOMPtr clipped; - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipped)); canvas->PushSurface(clipped); canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface); diff --git a/mozilla/layout/svg/base/src/nsSVGTextFrame.cpp b/mozilla/layout/svg/base/src/nsSVGTextFrame.cpp index 2142caa16ee..bc28dbbeb92 100644 --- a/mozilla/layout/svg/base/src/nsSVGTextFrame.cpp +++ b/mozilla/layout/svg/base/src/nsSVGTextFrame.cpp @@ -594,7 +594,8 @@ nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas, if (trivialClip) { canvas->PushClip(); } else { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipMaskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipMaskSurface)); if (!clipMaskSurface) clip = nsnull; } @@ -616,7 +617,8 @@ nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas, NS_GetSVGMaskFrame(&mask, aURI, mContent); if (mask) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskSurface)); if (maskSurface) { nsCOMPtr matrix = GetCanvasTM(); @@ -628,7 +630,8 @@ nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas, } if (maskSurface || clipMaskSurface || display->mOpacity != 1.0) { - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(maskedSurface)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(maskedSurface)); if (maskedSurface) { canvas->PushSurface(maskedSurface); } else @@ -652,7 +655,8 @@ nsSVGTextFrame::PaintSVG(nsISVGRendererCanvas* canvas, maskSurface = clipMaskSurface; } else { nsCOMPtr clipped; - nsSVGUtils::GetSurface(outerSVGFrame, getter_AddRefs(clipped)); + nsSVGUtils::GetSurface(outerSVGFrame, canvas, + getter_AddRefs(clipped)); canvas->PushSurface(clipped); canvas->CompositeSurfaceWithMask(maskedSurface, 0, 0, clipMaskSurface); diff --git a/mozilla/layout/svg/base/src/nsSVGUtils.cpp b/mozilla/layout/svg/base/src/nsSVGUtils.cpp index 235ffded6d1..0d2de533d14 100644 --- a/mozilla/layout/svg/base/src/nsSVGUtils.cpp +++ b/mozilla/layout/svg/base/src/nsSVGUtils.cpp @@ -66,6 +66,7 @@ #include "nsSVGPoint.h" #include "nsDOMError.h" #include "nsISVGOuterSVGFrame.h" +#include "nsISVGRendererCanvas.h" #if defined(MOZ_SVG_RENDERER_GDIPLUS) #include @@ -397,21 +398,11 @@ nsSVGUtils::TransformPoint(nsIDOMSVGMatrix *matrix, nsresult nsSVGUtils::GetSurface(nsISVGOuterSVGFrame *aOuterSVGFrame, + nsISVGRendererCanvas *aCanvas, nsISVGRendererSurface **aSurface) { - if (!aOuterSVGFrame) - return NS_ERROR_FAILURE; - - nsIFrame *frame = nsnull; - CallQueryInterface(aOuterSVGFrame, &frame); - - if (!frame) - return NS_ERROR_FAILURE; - - nsSize size = frame->GetSize(); - float p2t = frame->GetPresContext()->ScaledPixelsToTwips(); - PRUint32 width = (PRUint32)ceil(size.width/p2t); - PRUint32 height = (PRUint32)ceil(size.height/p2t); + PRUint32 width, height; + aCanvas->GetSurfaceSize(&width, &height); nsCOMPtr renderer; aOuterSVGFrame->GetRenderer(getter_AddRefs(renderer)); diff --git a/mozilla/layout/svg/base/src/nsSVGUtils.h b/mozilla/layout/svg/base/src/nsSVGUtils.h index b389ea496ec..8760ba74532 100644 --- a/mozilla/layout/svg/base/src/nsSVGUtils.h +++ b/mozilla/layout/svg/base/src/nsSVGUtils.h @@ -59,6 +59,7 @@ class nsIURI; class nsISVGOuterSVGFrame; class nsISVGRendererSurface; class nsIPresShell; +class nsISVGRendererCanvas; #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -142,8 +143,9 @@ public: static float AngleBisect(float a1, float a2); - /* Generate a new rendering surface the size of the outer svg frame */ + /* Generate a new rendering surface the size of the current surface */ static nsresult GetSurface(nsISVGOuterSVGFrame *aOuterSVGFrame, + nsISVGRendererCanvas *aCanvas, nsISVGRendererSurface **aSurface); private: diff --git a/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl b/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl index 2e92dd7aa91..3fb1d63da10 100644 --- a/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl +++ b/mozilla/layout/svg/renderer/public/nsISVGRendererCanvas.idl @@ -69,7 +69,7 @@ interface nsISVGRendererSurface; * Mozilla-native rendering object with a call to * nsISVGRenderer::createCanvas(). */ -[scriptable, uuid(9cdf3f86-a511-4948-83f8-e25460f03b83)] +[scriptable, uuid(a1ea0d56-765f-43be-88dc-e54576e5735b)] interface nsISVGRendererCanvas : nsISupports { /** @@ -133,6 +133,11 @@ interface nsISVGRendererCanvas : nsISupports void pushSurface(in nsISVGRendererSurface surface); void popSurface(); + /** + * Get the current drawing surface dimensions. + */ + void getSurfaceSize(out unsigned long width, out unsigned long height); + /** * Surface composition. */ diff --git a/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp b/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp index f882bbe8616..ae2a0f1a0f4 100644 --- a/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp +++ b/mozilla/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp @@ -701,6 +701,12 @@ nsSVGCairoCanvas::SetClipRect(nsIDOMSVGMatrix *aCTM, float aX, float aY, return NS_OK; } +struct ctxEntry { + cairo_t *mCR; + PRUint32 mWidth; + PRUint32 mHeight; +}; + /** Implements pushSurface(in nsISVGRendererSurface surface); */ NS_IMETHODIMP nsSVGCairoCanvas::PushSurface(nsISVGRendererSurface *aSurface) @@ -709,11 +715,19 @@ nsSVGCairoCanvas::PushSurface(nsISVGRendererSurface *aSurface) if (!cairoSurface) return NS_ERROR_FAILURE; - cairo_t* oldCR = mCR; - mContextStack.AppendElement(NS_STATIC_CAST(void*, oldCR)); + ctxEntry *ctx = new ctxEntry; + if (!ctx) + return NS_ERROR_OUT_OF_MEMORY; + + ctx->mCR = mCR; + ctx->mWidth = mWidth; + ctx->mHeight = mHeight; + + mContextStack.AppendElement(NS_STATIC_CAST(void*, ctx)); mCR = cairo_create(cairoSurface->GetSurface()); - // XXX Copy state over from oldCR? + aSurface->GetWidth(&mWidth); + aSurface->GetHeight(&mHeight); return NS_OK; } @@ -725,13 +739,25 @@ nsSVGCairoCanvas::PopSurface() PRUint32 count = mContextStack.Count(); if (count != 0) { cairo_destroy(mCR); - mCR = NS_STATIC_CAST(cairo_t*, mContextStack[count - 1]); + ctxEntry *ctx = NS_STATIC_CAST(ctxEntry*, mContextStack[count - 1]); + mCR = ctx->mCR; + mWidth = ctx->mWidth; + mHeight = ctx->mHeight; + delete ctx; mContextStack.RemoveElementAt(count - 1); } return NS_OK; } +NS_IMETHODIMP +nsSVGCairoCanvas::GetSurfaceSize(PRUint32 *aWidth, PRUint32 *aHeight) +{ + *aWidth = mWidth; + *aHeight = mHeight; + return NS_OK; +} + /** Implements void compositeSurface(in nsISVGRendererSurface surface, in unsigned long x, in unsigned long y, in float opacity); */ diff --git a/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp b/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp index 246bea4a7d9..43172b921d4 100644 --- a/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp +++ b/mozilla/layout/svg/renderer/src/gdiplus/nsSVGGDIPlusCanvas.cpp @@ -455,6 +455,13 @@ nsSVGGDIPlusCanvas::PopSurface() return NS_OK; } +NS_IMETHODIMP +nsSVGGDIPlusCanvas::GetSurfaceSize(PRUint32 *aWidth, PRUint32 *aHeight) +{ + // XXX + return NS_ERROR_NOT_IMPLEMENTED; +} + /** Implements void compositeSurface(in nsISVGRendererSurface surface, in unsigned long x, in unsigned long y, in float opacity); */ diff --git a/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp b/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp index 56b334695c6..b43ebd5b266 100644 --- a/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp +++ b/mozilla/layout/svg/renderer/src/libart/nsSVGLibartCanvas.cpp @@ -410,6 +410,13 @@ nsSVGLibartCanvas::PopSurface() return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +nsSVGLibartCanvas::GetSurfaceSize(PRUint32 *aWidth, PRUint32 *aHeight) +{ + // XXX + return NS_ERROR_NOT_IMPLEMENTED; +} + /** Implements void compositeSurface(in nsISVGRendererSurface surface, in unsigned long x, in unsigned long y, in float opacity); */