diff --git a/layout/svg/base/src/nsSVGFilterFrame.cpp b/layout/svg/base/src/nsSVGFilterFrame.cpp index 1743f2ad2d41..c9f319212d42 100644 --- a/layout/svg/base/src/nsSVGFilterFrame.cpp +++ b/layout/svg/base/src/nsSVGFilterFrame.cpp @@ -433,13 +433,13 @@ nsSVGFilterFrame::FilterPaint(nsISVGRendererCanvas *aCanvas, ctm->Multiply(scale, getter_AddRefs(fini)); - aCanvas->CompositeSurfaceMatrix(filterResult, fini, 1.0); + nsresult rv = aCanvas->CompositeSurfaceMatrix(filterResult, fini, 1.0); aTarget->SetOverrideCTM(nsnull); aTarget->SetMatrixPropagation(PR_TRUE); aTarget->NotifyCanvasTMChanged(PR_TRUE); - return NS_OK; + return rv; } NS_IMETHODIMP_(nsRect) diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 751c690c2e05..526e5456006e 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -1466,8 +1466,7 @@ nsSVGGlyphFrame::GetGlobalTransform(cairo_t *ctx, aCanvas->AdjustMatrixForInitialTransform(&matrix); } - cairo_matrix_t inverse = matrix; - if (cairo_matrix_invert(&inverse)) { + if (nsSVGUtils::IsSingular(&matrix)) { cairo_identity_matrix(ctx); return NS_ERROR_FAILURE; } diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index 7d0a41f6d671..378c93b188e7 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -254,6 +254,8 @@ nsSVGImageFrame::GetImageTransform() NS_IMETHODIMP nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect) { + nsresult rv = NS_OK; + if (!GetStyleVisibility()->IsVisible()) return NS_OK; @@ -292,17 +294,19 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect) if (GetStyleDisplay()->IsScrollableOverflow()) { canvas->PushClip(); - canvas->SetClipRect(ctm, x, y, width, height); + rv = canvas->SetClipRect(ctm, x, y, width, height); } - canvas->CompositeSurfaceMatrix(mSurface, fini, - mStyleContext->GetStyleDisplay()->mOpacity); + if (NS_SUCCEEDED(rv)) { + rv = canvas->CompositeSurfaceMatrix(mSurface, fini, + mStyleContext->GetStyleDisplay()->mOpacity); + } if (GetStyleDisplay()->IsScrollableOverflow()) canvas->PopClip(); } - return NS_OK; + return rv; } NS_IMETHODIMP diff --git a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp index b6af68b3a821..3b2a2bf96c6e 100644 --- a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp @@ -173,9 +173,7 @@ nsSVGInnerSVGFrame::GetType() const NS_IMETHODIMP nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect) { -#ifdef DEBUG -// printf("nsSVGInnerSVG(%p)::Paint\n", this); -#endif + nsresult rv = NS_OK; canvas->PushClip(); @@ -194,15 +192,18 @@ nsSVGInnerSVGFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect) clipTransform = parent->GetCanvasTM(); } - if (clipTransform) - canvas->SetClipRect(clipTransform, x, y, width, height); + if (clipTransform) { + rv = canvas->SetClipRect(clipTransform, x, y, width, height); + } } - nsSVGInnerSVGFrameBase::PaintSVG(canvas, aDirtyRect); + if (NS_SUCCEEDED(rv)) { + rv = nsSVGInnerSVGFrameBase::PaintSVG(canvas, aDirtyRect); + } canvas->PopClip(); - return NS_OK; + return rv; } NS_IMETHODIMP diff --git a/layout/svg/base/src/nsSVGMaskFrame.cpp b/layout/svg/base/src/nsSVGMaskFrame.cpp index 0299fab41d1f..384a77761f49 100644 --- a/layout/svg/base/src/nsSVGMaskFrame.cpp +++ b/layout/svg/base/src/nsSVGMaskFrame.cpp @@ -143,6 +143,7 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsISVGRendererCanvas* aCanvas, { nsCOMPtr cairoCanvas = do_QueryInterface(aCanvas); cairo_t *ctx = cairoCanvas->GetContext(); + cairo_pattern_t *pattern = nsnull; cairo_push_group(ctx); @@ -202,7 +203,12 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsISVGRendererCanvas* aCanvas, fprintf(stderr, "mask clip: %f,%f %fx%f\n", x, y, width, height); #endif - aCanvas->SetClipRect(aMatrix, x, y, width, height); + if (NS_FAILED(aCanvas->SetClipRect(aMatrix, x, y, width, height))) { + pattern = cairo_pop_group(ctx); + if (pattern) + cairo_pattern_destroy(pattern); + return nsnull; + } } mMaskParent = aParent, @@ -213,7 +219,7 @@ nsSVGMaskFrame::ComputeMaskAlpha(nsISVGRendererCanvas* aCanvas, nsSVGUtils::PaintChildWithEffects(aCanvas, nsnull, kid); } - cairo_pattern_t *pattern = cairo_pop_group(ctx); + pattern = cairo_pop_group(ctx); if (!pattern) return nsnull; diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index 69ed35f47031..7a5fe189e6b2 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -647,8 +647,7 @@ nsSVGPathGeometryFrame::GeneratePath(cairo_t *ctx, nsISVGCairoCanvas* aCanvas) aCanvas->AdjustMatrixForInitialTransform(&matrix); } - cairo_matrix_t inverse = matrix; - if (cairo_matrix_invert(&inverse)) { + if (nsSVGUtils::IsSingular(&matrix)) { cairo_identity_matrix(ctx); cairo_new_path(ctx); return; diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 06c4ba749491..5cab946433d7 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -918,6 +918,18 @@ nsSVGUtils::GetCairoComputationalSurface() return mCairoComputationalSurface; } +PRBool +nsSVGUtils::IsSingular(const cairo_matrix_t *aMatrix) +{ + double a, b, c, d; + + a = aMatrix->xx; b = aMatrix->yx; + c = aMatrix->xy; d = aMatrix->yy; + + // if the determinant (ad - bc) is zero it's singular + return a * d == b * c; +} + cairo_matrix_t nsSVGUtils::ConvertSVGMatrixToCairo(nsIDOMSVGMatrix *aMatrix) { diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index 87483cef3fdb..2da90ec1e728 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -248,6 +248,12 @@ public: static cairo_surface_t * GetCairoComputationalSurface(); + /* + * A singular matrix is a non invertible square matrix. + */ + static PRBool + IsSingular(const cairo_matrix_t *aMatrix); + /* * Convert a nsIDOMSVGMatrix to a cairo_matrix_t. */ diff --git a/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp b/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp index ecd405f38d28..984df34ad779 100644 --- a/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp +++ b/layout/svg/renderer/src/cairo/nsSVGCairoCanvas.cpp @@ -133,7 +133,7 @@ public: NS_IMETHOD AdjustMatrixForInitialTransform(cairo_matrix_t* aMatrix); protected: - void SetupCairoMatrix(nsIDOMSVGMatrix *aCTM); + nsresult SetupCairoMatrix(nsIDOMSVGMatrix *aCTM); private: nsCOMPtr mMozContext; @@ -451,11 +451,17 @@ NS_INTERFACE_MAP_END //---------------------------------------------------------------------- // nsISVGRendererCanvas methods: -void nsSVGCairoCanvas::SetupCairoMatrix(nsIDOMSVGMatrix *aCTM) +nsresult +nsSVGCairoCanvas::SetupCairoMatrix(nsIDOMSVGMatrix *aCTM) { cairo_matrix_t matrix = nsSVGUtils::ConvertSVGMatrixToCairo(aCTM); AdjustMatrixForInitialTransform(&matrix); + + if (nsSVGUtils::IsSingular(&matrix)) { + return NS_ERROR_FAILURE; + } cairo_set_matrix(mCR, &matrix); + return NS_OK; } /** Implements [noscript] nsIRenderingContext lockRenderingContext(const in nsRectRef rect); */ @@ -463,7 +469,11 @@ NS_IMETHODIMP nsSVGCairoCanvas::LockRenderingContext(nsIDOMSVGMatrix* aCTM, nsIRenderingContext **_retval) { - SetupCairoMatrix(aCTM); + nsresult rv = SetupCairoMatrix(aCTM); + if (NS_FAILED(rv)) { + *_retval = nsnull; + return rv; + } *_retval = mMozContext; NS_ADDREF(*_retval); return NS_OK; @@ -701,7 +711,10 @@ nsSVGCairoCanvas::SetClipRect(nsIDOMSVGMatrix *aCTM, float aX, float aY, cairo_matrix_t oldMatrix; cairo_get_matrix(mCR, &oldMatrix); - SetupCairoMatrix(aCTM); + nsresult rv = SetupCairoMatrix(aCTM); + if (NS_FAILED(rv)) { + return rv; + } cairo_new_path(mCR); cairo_rectangle(mCR, aX, aY, aWidth, aHeight); @@ -775,7 +788,11 @@ nsSVGCairoCanvas::CompositeSurfaceMatrix(cairo_surface_t *aSurface, { cairo_save(mCR); - SetupCairoMatrix(aCTM); + nsresult rv = SetupCairoMatrix(aCTM); + if (NS_FAILED(rv)) { + cairo_restore(mCR); + return rv; + } cairo_set_source_surface(mCR, aSurface, 0.0, 0.0); cairo_paint_with_alpha(mCR, aOpacity);