diff --git a/content/canvas/src/CanvasUtils.cpp b/content/canvas/src/CanvasUtils.cpp new file mode 100644 index 000000000000..6718bf05ffbb --- /dev/null +++ b/content/canvas/src/CanvasUtils.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Vladimir Vukicevic + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "prmem.h" + +#include "nsIServiceManager.h" + +#include "nsIDOMDocument.h" +#include "nsIDocument.h" +#include "nsIDOMCanvasRenderingContext2D.h" +#include "nsICanvasRenderingContextInternal.h" +#include "nsICanvasElement.h" +#include "nsIPrincipal.h" +#include "nsINode.h" + +#include "nsGfxCIID.h" + +#include "nsTArray.h" + +#include "CanvasUtils.h" + +using namespace mozilla; + +void +CanvasUtils::DoDrawImageSecurityCheck(nsICanvasElement *aCanvasElement, + nsIPrincipal *aPrincipal, + PRBool forceWriteOnly) +{ + // Callers should ensure that mCanvasElement is non-null before calling this + if (!aCanvasElement) { + NS_WARNING("DoDrawImageSecurityCheck called without canvas element!"); + return; + } + + if (aCanvasElement->IsWriteOnly()) + return; + + // If we explicitly set WriteOnly just do it and get out + if (forceWriteOnly) { + aCanvasElement->SetWriteOnly(); + return; + } + + if (aPrincipal == nsnull) + return; + + nsCOMPtr elem = do_QueryInterface(aCanvasElement); + if (elem) { // XXXbz How could this actually be null? + PRBool subsumes; + nsresult rv = + elem->NodePrincipal()->Subsumes(aPrincipal, &subsumes); + + if (NS_SUCCEEDED(rv) && subsumes) { + // This canvas has access to that image anyway + return; + } + } + + aCanvasElement->SetWriteOnly(); +} diff --git a/content/canvas/src/CanvasUtils.h b/content/canvas/src/CanvasUtils.h new file mode 100644 index 000000000000..86794193fbe1 --- /dev/null +++ b/content/canvas/src/CanvasUtils.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Vladimir Vukicevic + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef _CANVASUTILS_H_ +#define _CANVASUTILS_H_ + +#include "prtypes.h" +#include "nsContentUtils.h" +#include "nsICanvasElement.h" +#include "nsIPrincipal.h" +#include "nsIDOMElement.h" +#include "nsRect.h" + +#include "gfxASurface.h" + +namespace mozilla { + +class CanvasUtils { +public: + // Check that the rectangle [x,y,w,h] is a subrectangle of [0,0,realWidth,realHeight] + + static PRBool CheckSaneSubrectSize(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h, + PRInt32 realWidth, PRInt32 realHeight) + { + return nsIntRect(0, 0, realWidth, realHeight).Contains(nsIntRect(x, y, w, h)); + } + + // Flag aCanvasElement as write-only if drawing an image with aPrincipal + // onto it would make it such. + + static void DoDrawImageSecurityCheck(nsICanvasElement *aCanvasElement, + nsIPrincipal *aPrincipal, + PRBool forceWriteOnly); + +private: + // this can't be instantiated + CanvasUtils() { } +}; + +} + +#endif /* _CANVASUTILS_H_ */ diff --git a/content/canvas/src/Makefile.in b/content/canvas/src/Makefile.in index b2581da1df9f..06e2474dd12d 100644 --- a/content/canvas/src/Makefile.in +++ b/content/canvas/src/Makefile.in @@ -68,17 +68,11 @@ REQUIRES = \ qcms \ $(NULL) -# XXX some platforms can't handle building -# an empty .a/lib. Remove this dummy.cpp -# whenever w have a rendering context -# that doesn't depend on any non-default -# libraries. -CPPSRCS = dummy.cpp \ - $(NULL) -ifdef MOZ_ENABLE_CANVAS -CPPSRCS += nsCanvasRenderingContext2D.cpp -endif +CPPSRCS = \ + CanvasUtils.cpp \ + nsCanvasRenderingContext2D.cpp \ + $(NULL) # we don't want the shared lib, but we want to force the creation of a static lib. FORCE_STATIC_LIB = 1 diff --git a/content/canvas/src/dummy.cpp b/content/canvas/src/dummy.cpp deleted file mode 100644 index ca2d4037b956..000000000000 --- a/content/canvas/src/dummy.cpp +++ /dev/null @@ -1,9 +0,0 @@ -/* - * This file only exists because some platforms can't handle building an empty .a - * file, or .lib, or whatever (e.g. OS X, possibly Win32). - * - * Need at least one external symbol for some linkers to create a proper - * archive file: https://bugzilla.mozilla.org/show_bug.cgi?id=311143 - */ -void concvsdummy(void) {} - diff --git a/content/canvas/src/nsCanvasRenderingContext2D.cpp b/content/canvas/src/nsCanvasRenderingContext2D.cpp index 12f1f7ea3a7f..4dcf620df6e1 100644 --- a/content/canvas/src/nsCanvasRenderingContext2D.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2D.cpp @@ -55,15 +55,9 @@ #include "nsIPresShell.h" #include "nsIVariant.h" -#include "imgIRequest.h" -#include "imgIContainer.h" -#include "gfxIImageFrame.h" #include "nsIDOMHTMLCanvasElement.h" #include "nsICanvasElement.h" -#include "nsIDOMHTMLImageElement.h" -#include "nsIImageLoadingContent.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIImage.h" #include "nsIFrame.h" #include "nsDOMError.h" #include "nsIScriptError.h" @@ -110,17 +104,15 @@ #include "nsBidiPresUtils.h" -#ifdef MOZ_MEDIA -#include "nsHTMLVideoElement.h" -#endif +#include "CanvasUtils.h" + +using namespace mozilla; #ifndef M_PI #define M_PI 3.14159265358979323846 #define M_PI_2 1.57079632679489661923 #endif -static PRBool CheckSaneSubrectSize (PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h, PRInt32 realWidth, PRInt32 realHeight); - /* Float validation stuff */ #define VALIDATE(_f) if (!JSDOUBLE_IS_FINITE(_f)) return PR_FALSE @@ -360,14 +352,6 @@ protected: */ void ApplyStyle(Style aWhichStyle, PRBool aUseGlobalAlpha = PR_TRUE); - // If aPrincipal is not subsumed by this canvas element, then - // we make the canvas write-only so bad guys can't extract the pixel - // data. If forceWriteOnly is set, we force write only to be set - // and ignore aPrincipal. (This is used for when the original data came - // from a that had write-only set.) - void DoDrawImageSecurityCheck(nsIPrincipal* aPrincipal, - PRBool forceWriteOnly); - // Member vars PRInt32 mWidth, mHeight; PRPackedBool mValid; @@ -614,14 +598,6 @@ protected: static PRBool ConvertJSValToDouble(double* aProp, JSContext* aContext, jsval aValue); - // thebes helpers - nsresult ThebesSurfaceFromElement(nsIDOMElement *imgElt, - PRBool forceCopy, - gfxASurface **aSurface, - PRInt32 *widthOut, PRInt32 *heightOut, - nsIPrincipal **prinOut, - PRBool *forceWriteOnlyOut); - // other helpers void GetAppUnitsValues(PRUint32 *perDevPixel, PRUint32 *perCSSPixel) { // If we don't have a canvas element, we just return something generic. @@ -791,43 +767,6 @@ nsCanvasRenderingContext2D::DirtyAllStyles() } } -void -nsCanvasRenderingContext2D::DoDrawImageSecurityCheck(nsIPrincipal* aPrincipal, - PRBool forceWriteOnly) -{ - // Callers should ensure that mCanvasElement is non-null before calling this - if (!mCanvasElement) { - NS_WARNING("DoDrawImageSecurityCheck called without canvas element!"); - return; - } - - if (mCanvasElement->IsWriteOnly()) - return; - - // If we explicitly set WriteOnly just do it and get out - if (forceWriteOnly) { - mCanvasElement->SetWriteOnly(); - return; - } - - if (aPrincipal == nsnull) - return; - - nsCOMPtr elem = do_QueryInterface(mCanvasElement); - if (elem) { // XXXbz How could this actually be null? - PRBool subsumes; - nsresult rv = - elem->NodePrincipal()->Subsumes(aPrincipal, &subsumes); - - if (NS_SUCCEEDED(rv) && subsumes) { - // This canvas has access to that image anyway - return; - } - } - - mCanvasElement->SetWriteOnly(); -} - void nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle, PRBool aUseGlobalAlpha) @@ -850,8 +789,9 @@ nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle, if (!mCanvasElement) return; - DoDrawImageSecurityCheck(pattern->Principal(), - pattern->GetForceWriteOnly()); + CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, + pattern->Principal(), + pattern->GetForceWriteOnly()); gfxPattern* gpat = pattern->GetPattern(); @@ -1333,7 +1273,6 @@ nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image, const nsAString& repeat, nsIDOMCanvasPattern **_retval) { - nsresult rv; gfxPattern::GraphicsExtend extend; if (repeat.IsEmpty() || repeat.EqualsLiteral("repeat")) { @@ -1351,22 +1290,17 @@ nsCanvasRenderingContext2D::CreatePattern(nsIDOMHTMLElement *image, return NS_ERROR_DOM_SYNTAX_ERR; } - PRInt32 imgWidth, imgHeight; - nsCOMPtr principal; - PRBool forceWriteOnly = PR_FALSE; - nsRefPtr imgsurf; - rv = ThebesSurfaceFromElement(image, PR_TRUE, - getter_AddRefs(imgsurf), &imgWidth, &imgHeight, - getter_AddRefs(principal), &forceWriteOnly); - if (NS_FAILED(rv)) - return rv; + nsLayoutUtils::SurfaceFromElementResult res = + nsLayoutUtils::SurfaceFromElement(image, nsLayoutUtils::SFE_WANT_NEW_SURFACE); + if (!res.mSurface) + return NS_ERROR_NOT_AVAILABLE; - nsRefPtr thebespat = new gfxPattern(imgsurf); + nsRefPtr thebespat = new gfxPattern(res.mSurface); thebespat->SetExtend(extend); - nsRefPtr pat = new nsCanvasPattern(thebespat, principal, - forceWriteOnly); + nsRefPtr pat = new nsCanvasPattern(thebespat, res.mPrincipal, + res.mIsWriteOnly); if (!pat) return NS_ERROR_OUT_OF_MEMORY; @@ -2959,22 +2893,33 @@ nsCanvasRenderingContext2D::DrawImage() ctx, argv[0])) return NS_ERROR_DOM_TYPE_MISMATCH_ERR; - PRInt32 imgWidth, imgHeight; - nsCOMPtr principal; - PRBool forceWriteOnly = PR_FALSE; gfxMatrix matrix; nsRefPtr pattern; nsRefPtr path; - nsRefPtr imgsurf; #ifdef WINCE nsRefPtr currentSurface; #endif - rv = ThebesSurfaceFromElement(imgElt, PR_FALSE, - getter_AddRefs(imgsurf), &imgWidth, &imgHeight, - getter_AddRefs(principal), &forceWriteOnly); - if (NS_FAILED(rv)) - return rv; - DoDrawImageSecurityCheck(principal, forceWriteOnly); + nsLayoutUtils::SurfaceFromElementResult res = + nsLayoutUtils::SurfaceFromElement(imgElt); + if (!res.mSurface) + return NS_ERROR_NOT_AVAILABLE; + +#ifndef WINCE + // On non-CE, force a copy if we're using drawImage with our destination + // as a source to work around some Cairo self-copy semantics issues. + if (res.mSurface == mSurface) { + res = nsLayoutUtils::SurfaceFromElement(imgElt, nsLayoutUtils::SFE_WANT_NEW_SURFACE); + if (!res.mSurface) + return NS_ERROR_NOT_AVAILABLE; + } +#endif + + nsRefPtr imgsurf = res.mSurface; + nsCOMPtr principal = res.mPrincipal; + gfxIntSize imgSize = res.mSize; + PRBool forceWriteOnly = res.mIsWriteOnly; + + CanvasUtils::DoDrawImageSecurityCheck(mCanvasElement, principal, forceWriteOnly); gfxContextPathAutoSaveRestore pathSR(mThebes, PR_FALSE); @@ -2987,16 +2932,16 @@ nsCanvasRenderingContext2D::DrawImage() GET_ARG(&dx, argv[1]); GET_ARG(&dy, argv[2]); sx = sy = 0.0; - dw = sw = (double) imgWidth; - dh = sh = (double) imgHeight; + dw = sw = (double) imgSize.width; + dh = sh = (double) imgSize.height; } else if (argc == 5) { GET_ARG(&dx, argv[1]); GET_ARG(&dy, argv[2]); GET_ARG(&dw, argv[3]); GET_ARG(&dh, argv[4]); sx = sy = 0.0; - sw = (double) imgWidth; - sh = (double) imgHeight; + sw = (double) imgSize.width; + sh = (double) imgSize.height; } else if (argc == 9) { GET_ARG(&sx, argv[1]); GET_ARG(&sy, argv[2]); @@ -3027,8 +2972,8 @@ nsCanvasRenderingContext2D::DrawImage() // check args if (sx < 0.0 || sy < 0.0 || - sw < 0.0 || sw > (double) imgWidth || - sh < 0.0 || sh > (double) imgHeight || + sw < 0.0 || sw > (double) imgSize.width || + sh < 0.0 || sh > (double) imgSize.height || dw < 0.0 || dh < 0.0) { // XXX ERRMSG we need to report an error to developers here! (bug 329026) @@ -3258,192 +3203,6 @@ nsCanvasRenderingContext2D::ConvertJSValToXPCObject(nsISupports** aSupports, REF return JS_FALSE; } -/* thebes ARGB32 surfaces are ARGB stored as a packed 32-bit integer; on little-endian - * platforms, they appear as BGRA bytes in the surface data. The color values are also - * stored with premultiplied alpha. - * - * If forceCopy is FALSE, a surface may be returned that's only valid during the current - * operation. If it's TRUE, a copy will always be made that can safely be retained. - */ - -nsresult -nsCanvasRenderingContext2D::ThebesSurfaceFromElement(nsIDOMElement *imgElt, - PRBool forceCopy, - gfxASurface **aSurface, - PRInt32 *widthOut, - PRInt32 *heightOut, - nsIPrincipal **prinOut, - PRBool *forceWriteOnlyOut) -{ - nsresult rv; - - nsCOMPtr node = do_QueryInterface(imgElt); - - /* If it's a Canvas, grab its internal surface as necessary */ - nsCOMPtr canvas = do_QueryInterface(imgElt); - if (node && canvas) { - PRUint32 w, h; - rv = canvas->GetSize(&w, &h); - NS_ENSURE_SUCCESS(rv, rv); - - nsRefPtr sourceSurface; - - if (!forceCopy && canvas->CountContexts() == 1) { - nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0); - rv = srcCanvas->GetThebesSurface(getter_AddRefs(sourceSurface)); -#ifndef WINCE - // force a copy if we couldn't get the surface, or if it's - // the same as what we have - if (sourceSurface == mSurface || NS_FAILED(rv)) -#else - // force a copy if we couldn't get the surface - if (NS_FAILED(rv)) -#endif - sourceSurface = nsnull; - } - - if (sourceSurface == nsnull) { - nsRefPtr surf = - gfxPlatform::GetPlatform()->CreateOffscreenSurface - (gfxIntSize(w, h), gfxASurface::ImageFormatARGB32); - nsRefPtr ctx = new gfxContext(surf); - rv = canvas->RenderContexts(ctx, gfxPattern::FILTER_NEAREST); - if (NS_FAILED(rv)) - return rv; - sourceSurface = surf; - } - - *aSurface = sourceSurface.forget().get(); - *widthOut = w; - *heightOut = h; - - NS_ADDREF(*prinOut = node->NodePrincipal()); - *forceWriteOnlyOut = canvas->IsWriteOnly(); - - return NS_OK; - } - -#ifdef MOZ_MEDIA - /* Maybe it's