b=492724; pull out canvas utility functions into CanvasUtils/LayoutUtils; r+sr=roc

This commit is contained in:
Vladimir Vukicevic 2009-06-25 13:30:56 -07:00
parent 3398165d33
commit 670216332d
8 changed files with 449 additions and 303 deletions

View File

@ -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 <vladimir@pobox.com>
* 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<nsINode> 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();
}

View File

@ -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 <vladimir@pobox.com>
* 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_ */

View File

@ -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

View File

@ -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) {}

View File

@ -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 <canvas> 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<nsINode> 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,7 +789,8 @@ nsCanvasRenderingContext2D::ApplyStyle(Style aWhichStyle,
if (!mCanvasElement)
return;
DoDrawImageSecurityCheck(pattern->Principal(),
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<nsIPrincipal> principal;
PRBool forceWriteOnly = PR_FALSE;
nsRefPtr<gfxASurface> 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<gfxPattern> thebespat = new gfxPattern(imgsurf);
nsRefPtr<gfxPattern> thebespat = new gfxPattern(res.mSurface);
thebespat->SetExtend(extend);
nsRefPtr<nsCanvasPattern> pat = new nsCanvasPattern(thebespat, principal,
forceWriteOnly);
nsRefPtr<nsCanvasPattern> 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<nsIPrincipal> principal;
PRBool forceWriteOnly = PR_FALSE;
gfxMatrix matrix;
nsRefPtr<gfxPattern> pattern;
nsRefPtr<gfxPath> path;
nsRefPtr<gfxASurface> imgsurf;
#ifdef WINCE
nsRefPtr<gfxASurface> 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<gfxASurface> imgsurf = res.mSurface;
nsCOMPtr<nsIPrincipal> 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<nsINode> node = do_QueryInterface(imgElt);
/* If it's a Canvas, grab its internal surface as necessary */
nsCOMPtr<nsICanvasElement> canvas = do_QueryInterface(imgElt);
if (node && canvas) {
PRUint32 w, h;
rv = canvas->GetSize(&w, &h);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<gfxASurface> 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<gfxASurface> surf =
gfxPlatform::GetPlatform()->CreateOffscreenSurface
(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> 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 <video>? */
nsCOMPtr<nsIDOMHTMLVideoElement> ve = do_QueryInterface(imgElt);
if (node && ve) {
nsHTMLVideoElement *video = static_cast<nsHTMLVideoElement*>(ve.get());
/* If it doesn't have a principal, just bail */
nsCOMPtr<nsIPrincipal> principal = video->GetCurrentPrincipal();
if (!principal)
return NS_ERROR_DOM_SECURITY_ERR;
PRUint32 videoWidth, videoHeight;
rv = video->GetVideoWidth(&videoWidth);
rv |= video->GetVideoHeight(&videoHeight);
if (NS_FAILED(rv))
return NS_ERROR_NOT_AVAILABLE;
nsRefPtr<gfxASurface> surf =
gfxPlatform::GetPlatform()->CreateOffscreenSurface
(gfxIntSize(videoWidth, videoHeight), gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
video->Paint(ctx, gfxPattern::FILTER_NEAREST, gfxRect(0, 0, videoWidth, videoHeight));
*aSurface = surf.forget().get();
*widthOut = videoWidth;
*heightOut = videoHeight;
*prinOut = principal.forget().get();
*forceWriteOnlyOut = PR_FALSE;
return NS_OK;
}
#endif
/* Finally, check if it's a normal image */
nsCOMPtr<imgIContainer> imgContainer;
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(imgElt);
if (!imageLoader)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<imgIRequest> imgRequest;
rv = imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(imgRequest));
NS_ENSURE_SUCCESS(rv, rv);
if (!imgRequest)
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_ERROR_NOT_AVAILABLE;
PRUint32 status;
imgRequest->GetImageStatus(&status);
if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0)
return NS_ERROR_NOT_AVAILABLE;
// In case of data: URIs, we want to ignore principals;
// they should have the originating content's principal,
// but that's broken at the moment in imgLib.
nsCOMPtr<nsIURI> uri;
rv = imgRequest->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR);
PRBool isDataURI = PR_FALSE;
rv = uri->SchemeIs("data", &isDataURI);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_SECURITY_ERR);
// Data URIs are always OK; set the principal
// to null to indicate that.
if (isDataURI) {
*prinOut = nsnull;
} else {
rv = imgRequest->GetImagePrincipal(prinOut);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(*prinOut, NS_ERROR_DOM_SECURITY_ERR);
}
*forceWriteOnlyOut = PR_FALSE;
rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
NS_ENSURE_SUCCESS(rv, rv);
if (!imgContainer)
return NS_ERROR_NOT_AVAILABLE;
nsCOMPtr<gfxIImageFrame> frame;
rv = imgContainer->GetCurrentFrame(getter_AddRefs(frame));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIImage> img(do_GetInterface(frame));
PRInt32 imgWidth, imgHeight;
rv = frame->GetWidth(&imgWidth);
rv |= frame->GetHeight(&imgHeight);
if (NS_FAILED(rv))
return NS_ERROR_FAILURE;
if (widthOut)
*widthOut = imgWidth;
if (heightOut)
*heightOut = imgHeight;
nsRefPtr<gfxPattern> gfxpattern;
img->GetPattern(getter_AddRefs(gfxpattern));
nsRefPtr<gfxASurface> gfxsurf = gfxpattern->GetSurface();
if (!gfxsurf) {
gfxsurf = new gfxImageSurface (gfxIntSize(imgWidth, imgHeight), gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> ctx = new gfxContext(gfxsurf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetPattern(gfxpattern);
ctx->Paint();
}
*aSurface = gfxsurf.forget().get();
return NS_OK;
}
/* Check that the rect [x,y,w,h] is a valid subrect of [0,0,realWidth,realHeight]
* without overflowing any integers and the like.
*/
@ -3614,7 +3373,7 @@ nsCanvasRenderingContext2D::GetImageData()
if (!JS_ConvertArguments (ctx, argc, argv, "jjjj", &x, &y, &w, &h))
return NS_ERROR_DOM_SYNTAX_ERR;
if (!CheckSaneSubrectSize (x, y, w, h, mWidth, mHeight))
if (!CanvasUtils::CheckSaneSubrectSize (x, y, w, h, mWidth, mHeight))
return NS_ERROR_DOM_SYNTAX_ERR;
nsAutoArrayPtr<PRUint8> surfaceData (new (std::nothrow) PRUint8[w * h * 4]);
@ -3802,7 +3561,7 @@ nsCanvasRenderingContext2D::PutImageData()
return NS_ERROR_DOM_SYNTAX_ERR;
dataArray = JSVAL_TO_OBJECT(v);
if (!CheckSaneSubrectSize (x, y, w, h, mWidth, mHeight))
if (!CanvasUtils::CheckSaneSubrectSize (x, y, w, h, mWidth, mHeight))
return NS_ERROR_DOM_SYNTAX_ERR;
jsuint arrayLen;
@ -3972,7 +3731,7 @@ nsCanvasRenderingContext2D::CreateImageData()
// check for overflow when calculating len
PRUint32 len0 = w * h;
if (len0 / w != h)
if (len0 / w != (PRUint32) h)
return NS_ERROR_DOM_INDEX_SIZE_ERR;
PRUint32 len = len0 * 4;
if (len / 4 != len0)

View File

@ -46,6 +46,8 @@ typedef struct _cairo_user_data_key cairo_user_data_key_t;
typedef void (*thebes_destroy_func_t) (void *data);
class gfxImageSurface;
/**
* A surface is something you can draw on. Instantiate a subclass of this
* abstract class, and use gfxContext to draw on this surface.

View File

@ -81,6 +81,13 @@
#include "gfxUserFontSet.h"
#include "nsTArray.h"
#include "nsTextFragment.h"
#include "nsICanvasElement.h"
#include "nsICanvasRenderingContextInternal.h"
#include "gfxPlatform.h"
#include "nsHTMLVideoElement.h"
#include "imgIRequest.h"
#include "imgIContainer.h"
#include "nsIImageLoadingContent.h"
#ifdef MOZ_SVG
#include "nsSVGUtils.h"
@ -3290,6 +3297,190 @@ nsLayoutUtils::GetTextFragmentForPrinting(const nsIFrame* aFrame)
return frag;
}
nsLayoutUtils::SurfaceFromElementResult
nsLayoutUtils::SurfaceFromElement(nsIDOMElement *aElement,
PRUint32 aSurfaceFlags)
{
SurfaceFromElementResult result;
nsresult rv;
nsCOMPtr<nsINode> node = do_QueryInterface(aElement);
PRBool forceCopy = (aSurfaceFlags & SFE_WANT_NEW_SURFACE) != 0;
PRBool wantImageSurface = (aSurfaceFlags & SFE_WANT_IMAGE_SURFACE) != 0;
// If it's a <canvas>, we may be able to just grab its internal surface
nsCOMPtr<nsICanvasElement> canvas = do_QueryInterface(aElement);
if (node && canvas) {
PRUint32 w, h;
rv = canvas->GetSize(&w, &h);
if (NS_FAILED(rv))
return result;
nsRefPtr<gfxASurface> surf;
if (!forceCopy && canvas->CountContexts() == 1) {
nsICanvasRenderingContextInternal *srcCanvas = canvas->GetContextAtIndex(0);
rv = srcCanvas->GetThebesSurface(getter_AddRefs(surf));
if (NS_FAILED(rv))
surf = nsnull;
}
if (surf && wantImageSurface && surf->GetType() != gfxASurface::SurfaceTypeImage)
surf = nsnull;
if (!surf) {
if (wantImageSurface) {
surf = new gfxImageSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
} else {
surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
}
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
rv = canvas->RenderContexts(ctx, gfxPattern::FILTER_NEAREST);
if (NS_FAILED(rv))
return result;
}
nsCOMPtr<nsIPrincipal> principal = node->NodePrincipal();
result.mSurface = surf;
result.mSize = gfxIntSize(w, h);
result.mPrincipal = node->NodePrincipal();
result.mIsWriteOnly = canvas->IsWriteOnly();
return result;
}
#ifdef MOZ_MEDIA
// Maybe it's <video>?
nsCOMPtr<nsIDOMHTMLVideoElement> ve = do_QueryInterface(aElement);
if (node && ve) {
nsHTMLVideoElement *video = static_cast<nsHTMLVideoElement*>(ve.get());
// If it doesn't have a principal, just bail
nsCOMPtr<nsIPrincipal> principal = video->GetCurrentPrincipal();
if (!principal)
return result;
PRUint32 w, h;
rv = video->GetVideoWidth(&w);
rv |= video->GetVideoHeight(&h);
if (NS_FAILED(rv))
return result;
nsRefPtr<gfxASurface> surf;
if (wantImageSurface) {
surf = new gfxImageSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
} else {
surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(w, h), gfxASurface::ImageFormatARGB32);
}
nsRefPtr<gfxContext> ctx = new gfxContext(surf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
video->Paint(ctx, gfxPattern::FILTER_NEAREST, gfxRect(0, 0, w, h));
result.mSurface = surf;
result.mSize = gfxIntSize(w, h);
result.mPrincipal = principal;
result.mIsWriteOnly = PR_FALSE;
return result;
}
#endif
// Finally, check if it's a normal image
nsCOMPtr<imgIContainer> imgContainer;
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(aElement);
if (!imageLoader)
return result;
nsCOMPtr<imgIRequest> imgRequest;
rv = imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(imgRequest));
if (NS_FAILED(rv) || !imgRequest)
return result;
PRUint32 status;
imgRequest->GetImageStatus(&status);
if ((status & imgIRequest::STATUS_LOAD_COMPLETE) == 0)
return result;
// In case of data: URIs, we want to ignore principals;
// they should have the originating content's principal,
// but that's broken at the moment in imgLib.
nsCOMPtr<nsIURI> uri;
rv = imgRequest->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv))
return result;
PRBool isDataURI = PR_FALSE;
rv = uri->SchemeIs("data", &isDataURI);
if (NS_FAILED(rv))
return result;
// Data URIs are always OK; set the principal
// to null to indicate that.
nsCOMPtr<nsIPrincipal> principal;
if (!isDataURI) {
rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
if (NS_FAILED(rv) || !principal)
return result;
}
rv = imgRequest->GetImage(getter_AddRefs(imgContainer));
if (NS_FAILED(rv) || !imgContainer)
return result;
nsCOMPtr<gfxIImageFrame> frame;
rv = imgContainer->GetCurrentFrame(getter_AddRefs(frame));
if (NS_FAILED(rv))
return result;
nsCOMPtr<nsIImage> img(do_GetInterface(frame));
if (!img)
return result;
PRInt32 imgWidth, imgHeight;
rv = frame->GetWidth(&imgWidth);
rv |= frame->GetHeight(&imgHeight);
if (NS_FAILED(rv))
return result;
nsRefPtr<gfxPattern> gfxpattern;
img->GetPattern(getter_AddRefs(gfxpattern));
nsRefPtr<gfxASurface> gfxsurf = gfxpattern->GetSurface();
if (wantImageSurface && gfxsurf->GetType() != gfxASurface::SurfaceTypeImage) {
forceCopy = PR_TRUE;
}
if (forceCopy || !gfxsurf) {
if (wantImageSurface) {
gfxsurf = new gfxImageSurface (gfxIntSize(imgWidth, imgHeight), gfxASurface::ImageFormatARGB32);
} else {
gfxsurf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(imgWidth, imgHeight),
gfxASurface::ImageFormatARGB32);
}
nsRefPtr<gfxContext> ctx = new gfxContext(gfxsurf);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->SetPattern(gfxpattern);
ctx->Paint();
}
result.mSurface = gfxsurf;
result.mSize = gfxIntSize(imgWidth, imgHeight);
result.mPrincipal = principal;
result.mIsWriteOnly = PR_FALSE;
return result;
}
nsSetAttrRunnable::nsSetAttrRunnable(nsIContent* aContent, nsIAtom* aAttrName,
const nsAString& aValue)
: mContent(aContent),

View File

@ -1033,6 +1033,45 @@ public:
!aFrame->GetFirstContinuation()->
GetProperty(nsGkAtoms::IBSplitSpecialSibling);
}
/**
* Obtain a gfxASurface from the given DOM element, if possible.
* This obtains the most natural surface from the element; that
* is, the one that can be obtained with the fewest conversions.
*
* The flags below can modify the behaviour of this function. The
* result is returned as a SurfaceFromElementResult struct, also
* defined below.
*
* Currently, this will do:
* - HTML Canvas elements: will return the underlying canvas surface
* - HTML Video elements: will return the current video frame
* - Image elements: will return the image
*
* The above results are modified by the below flags (copying,
* forcing image surface, etc.).
*/
enum {
/* Always create a new surface for the result */
SFE_WANT_NEW_SURFACE = 1 << 0,
/* When creating a new surface, create an image surface */
SFE_WANT_IMAGE_SURFACE = 1 << 1
};
struct SurfaceFromElementResult {
/* mSurface will contain the resulting surface, or will be NULL on error */
nsRefPtr<gfxASurface> mSurface;
/* The size of the surface */
gfxIntSize mSize;
/* The principal associated with the element whose surface was returned */
nsCOMPtr<nsIPrincipal> mPrincipal;
/* Whether the element was "write only", that is, the bits should not be exposed to content */
PRBool mIsWriteOnly;
};
static SurfaceFromElementResult SurfaceFromElement(nsIDOMElement *aElement,
PRUint32 aSurfaceFlags = 0);
};
class nsAutoDisableGetUsedXAssertions