Bug 550309 - Part e: Remove custom quickstub for getImageData and return an actual ImageData; r=bz

This commit is contained in:
Ms2ger 2012-03-16 10:48:55 +01:00
Родитель 056121c36c
Коммит 2322c5ae81
6 изменённых файлов: 218 добавлений и 148 удалений

Просмотреть файл

@ -161,9 +161,6 @@ static bool
CreateImageData(JSContext* cx,
uint32_t w,
uint32_t h,
nsIDOMCanvasRenderingContext2D* self,
int32_t x,
int32_t y,
jsval* vp)
{
using mozilla::CheckedInt;
@ -186,19 +183,6 @@ CreateImageData(JSContext* cx,
return false;
}
if (self) {
JSObject *tdest = js::TypedArray::getTypedArray(darray);
// make the call
nsresult rv =
self->GetImageData_explicit(x, y, w, h,
static_cast<PRUint8*>(JS_GetTypedArrayData(tdest)),
JS_GetTypedArrayByteLength(tdest));
if (NS_FAILED(rv)) {
return xpc_qsThrowMethodFailed(cx, rv, vp);
}
}
// Do JS_NewObject after CreateTypedArray, so that gc will get
// triggered here if necessary
JSObject* result = JS_NewObject(cx, NULL, NULL, NULL);
@ -239,7 +223,7 @@ nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, unsigned argc, jsv
return false;
}
return CreateImageData(cx, data_width, data_height, NULL, 0, 0, vp);
return CreateImageData(cx, data_width, data_height, vp);
}
double width, height;
@ -258,64 +242,7 @@ nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, unsigned argc, jsv
uint32_t w = NS_ABS(wi);
uint32_t h = NS_ABS(hi);
return CreateImageData(cx, w, h, NULL, 0, 0, vp);
}
static JSBool
nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, unsigned argc, jsval *vp)
{
XPC_QS_ASSERT_CONTEXT_OK(cx);
JSObject *obj = JS_THIS_OBJECT(cx, vp);
if (!obj)
return JS_FALSE;
nsIDOMCanvasRenderingContext2D *self;
xpc_qsSelfRef selfref;
JS::AutoValueRooter tvr(cx);
if (!xpc_qsUnwrapThis(cx, obj, &self, &selfref.ptr, tvr.jsval_addr(), nsnull))
return JS_FALSE;
if (argc < 4)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
double xd, yd, width, height;
if (!JS_ValueToNumber(cx, argv[0], &xd) ||
!JS_ValueToNumber(cx, argv[1], &yd) ||
!JS_ValueToNumber(cx, argv[2], &width) ||
!JS_ValueToNumber(cx, argv[3], &height))
return false;
if (!NS_finite(xd) || !NS_finite(yd) ||
!NS_finite(width) || !NS_finite(height))
return xpc_qsThrow(cx, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
if (!width || !height)
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
int32_t x = JS_DoubleToInt32(xd);
int32_t y = JS_DoubleToInt32(yd);
int32_t wi = JS_DoubleToInt32(width);
int32_t hi = JS_DoubleToInt32(height);
// Handle negative width and height by flipping the rectangle over in the
// relevant direction.
uint32_t w, h;
if (width < 0) {
w = -wi;
x -= w;
} else {
w = wi;
}
if (height < 0) {
h = -hi;
y -= h;
} else {
h = hi;
}
return CreateImageData(cx, w, h, self, x, y, vp);
return CreateImageData(cx, w, h, vp);
}
static JSBool

Просмотреть файл

@ -85,7 +85,6 @@
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeNode.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
#include "nsDisplayList.h"
#include "nsTArray.h"
@ -109,12 +108,19 @@
#include "nsIMemoryReporter.h"
#include "nsStyleUtil.h"
#include "CanvasImageCache.h"
#include "CheckedInt.h"
#include <algorithm>
#include "jsapi.h"
#include "jstypedarray.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/ipc/PDocumentRendererParent.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/ipc/PDocumentRendererParent.h"
// windows.h (included by chromium code) defines this, in its infinite wisdom
#undef DrawText
@ -405,6 +411,10 @@ public:
friend class PathAutoSaveRestore;
protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
uint32_t aWidth, uint32_t aHeight,
JSObject** aRetval);
/**
* The number of living nsCanvasRenderingContexts. When this goes down to
* 0, we free the premultiply and unpremultiply tables, if they exist.
@ -3821,19 +3831,11 @@ nsCanvasRenderingContext2D::EnsureUnpremultiplyTable() {
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetImageData()
nsCanvasRenderingContext2D::GetImageData(double aSx, double aSy,
double aSw, double aSh,
JSContext* aCx,
nsIDOMImageData** aRetval)
{
/* Should never be called -- GetImageData_explicit is the QS entry point */
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
PRUint8 *aData, PRUint32 aDataLen)
{
if (!EnsureSurface())
return NS_ERROR_FAILURE;
if (!mCanvasElement && !mDocShell) {
NS_ERROR("No canvas element and no docshell in GetImageData!!!");
return NS_ERROR_DOM_SECURITY_ERR;
@ -3843,26 +3845,97 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
// then it's special internal use.
if (mCanvasElement &&
HTMLCanvasElement()->IsWriteOnly() &&
!nsContentUtils::IsCallerTrustedForRead())
{
!nsContentUtils::IsCallerTrustedForRead()) {
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
return NS_ERROR_DOM_SECURITY_ERR;
}
if (w == 0 || h == 0 || aDataLen != w * h * 4)
return NS_ERROR_DOM_SYNTAX_ERR;
if (!EnsureSurface()) {
return NS_ERROR_FAILURE;
}
CheckedInt32 rightMost = CheckedInt32(x) + w;
CheckedInt32 bottomMost = CheckedInt32(y) + h;
if (!NS_finite(aSx) || !NS_finite(aSy) ||
!NS_finite(aSw) || !NS_finite(aSh)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
if (!rightMost.valid() || !bottomMost.valid())
if (!aSw || !aSh) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
int32_t x = JS_DoubleToInt32(aSx);
int32_t y = JS_DoubleToInt32(aSy);
int32_t wi = JS_DoubleToInt32(aSw);
int32_t hi = JS_DoubleToInt32(aSh);
// Handle negative width and height by flipping the rectangle over in the
// relevant direction.
uint32_t w, h;
if (aSw < 0) {
w = -wi;
x -= w;
} else {
w = wi;
}
if (aSh < 0) {
h = -hi;
y -= h;
} else {
h = hi;
}
if (w == 0) {
w = 1;
}
if (h == 0) {
h = 1;
}
JSObject* array;
nsresult rv = GetImageDataArray(aCx, x, y, w, h, &array);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(array);
nsRefPtr<ImageData> imageData = new ImageData(w, h, *array);
imageData.forget(aRetval);
return NS_OK;
}
nsresult
nsCanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
int32_t aX,
int32_t aY,
uint32_t aWidth,
uint32_t aHeight,
JSObject** aRetval)
{
MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
if (!len.valid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth;
CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight;
if (!rightMost.valid() || !bottomMost.valid()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
JSObject* darray =
js_CreateTypedArray(aCx, js::TypedArray::TYPE_UINT8_CLAMPED, len.value());
if (!darray) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint8_t* data = static_cast<uint8_t*>(JS_GetTypedArrayData(darray));
/* Copy the surface contents to the buffer */
nsRefPtr<gfxImageSurface> tmpsurf =
new gfxImageSurface(aData,
gfxIntSize(w, h),
w * 4,
new gfxImageSurface(data,
gfxIntSize(aWidth, aHeight),
aWidth * 4,
gfxASurface::ImageFormatARGB32);
if (tmpsurf->CairoStatus())
@ -3875,7 +3948,7 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
if (!mZero) {
gfxRect srcRect(0, 0, mWidth, mHeight);
gfxRect destRect(x, y, w, h);
gfxRect destRect(aX, aY, aWidth, aHeight);
bool finishedPainting = false;
// In the common case, we want to avoid the Rectangle call.
@ -3892,7 +3965,7 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
if (!finishedPainting) {
tmpctx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpctx->SetSource(mSurface, gfxPoint(-x, -y));
tmpctx->SetSource(mSurface, gfxPoint(-aX, -aY));
tmpctx->Paint();
}
}
@ -3902,11 +3975,11 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
// NOTE! dst is the same as src, and this relies on reading
// from src and advancing that ptr before writing to dst.
PRUint8 *src = aData;
PRUint8 *dst = aData;
uint8_t *src = data;
uint8_t *dst = data;
for (PRUint32 j = 0; j < h; j++) {
for (PRUint32 i = 0; i < w; i++) {
for (uint32_t j = 0; j < aHeight; ++j) {
for (uint32_t i = 0; i < aWidth; ++i) {
// XXX Is there some useful swizzle MMX we can use here?
#ifdef IS_LITTLE_ENDIAN
PRUint8 b = *src++;
@ -3927,6 +4000,7 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
}
}
*aRetval = darray;
return NS_OK;
}

Просмотреть файл

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
@ -82,7 +82,6 @@
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeNode.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
#include "nsDisplayList.h"
#include "nsTArray.h"
@ -106,15 +105,21 @@
#include "nsIMemoryReporter.h"
#include "nsStyleUtil.h"
#include "CanvasImageCache.h"
#include "CheckedInt.h"
#include <algorithm>
#include "mozilla/dom/ContentParent.h"
#include "mozilla/ipc/PDocumentRendererParent.h"
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "jsapi.h"
#include "jstypedarray.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/PBrowserParent.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/ipc/DocumentRendererParent.h"
#include "mozilla/ipc/PDocumentRendererParent.h"
#include "mozilla/Preferences.h"
#ifdef XP_WIN
@ -443,6 +448,10 @@ public:
nsresult BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3);
protected:
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
uint32_t aWidth, uint32_t aHeight,
JSObject** aRetval);
nsresult InitializeWithTarget(DrawTarget *surface, PRInt32 width, PRInt32 height);
/**
@ -3992,15 +4001,10 @@ nsCanvasRenderingContext2DAzure::EnsureUnpremultiplyTable() {
NS_IMETHODIMP
nsCanvasRenderingContext2DAzure::GetImageData()
{
/* Should never be called -- GetImageData_explicit is the QS entry point */
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
PRUint8 *aData, PRUint32 aDataLen)
nsCanvasRenderingContext2DAzure::GetImageData(double aSx, double aSy,
double aSw, double aSh,
JSContext* aCx,
nsIDOMImageData** aRetval)
{
if (!mValid)
return NS_ERROR_FAILURE;
@ -4020,33 +4024,97 @@ nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRU
return NS_ERROR_DOM_SECURITY_ERR;
}
if (w == 0 || h == 0 || aDataLen != w * h * 4)
return NS_ERROR_DOM_SYNTAX_ERR;
if (!NS_finite(aSx) || !NS_finite(aSy) ||
!NS_finite(aSw) || !NS_finite(aSh)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
CheckedInt32 rightMost = CheckedInt32(x) + w;
CheckedInt32 bottomMost = CheckedInt32(y) + h;
if (!aSw || !aSh) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
if (!rightMost.valid() || !bottomMost.valid())
int32_t x = JS_DoubleToInt32(aSx);
int32_t y = JS_DoubleToInt32(aSy);
int32_t wi = JS_DoubleToInt32(aSw);
int32_t hi = JS_DoubleToInt32(aSh);
// Handle negative width and height by flipping the rectangle over in the
// relevant direction.
uint32_t w, h;
if (aSw < 0) {
w = -wi;
x -= w;
} else {
w = wi;
}
if (aSh < 0) {
h = -hi;
y -= h;
} else {
h = hi;
}
if (w == 0) {
w = 1;
}
if (h == 0) {
h = 1;
}
JSObject* array;
nsresult rv = GetImageDataArray(aCx, x, y, w, h, &array);
NS_ENSURE_SUCCESS(rv, rv);
MOZ_ASSERT(array);
nsRefPtr<ImageData> imageData = new ImageData(w, h, *array);
imageData.forget(aRetval);
return NS_OK;
}
nsresult
nsCanvasRenderingContext2DAzure::GetImageDataArray(JSContext* aCx,
int32_t aX,
int32_t aY,
uint32_t aWidth,
uint32_t aHeight,
JSObject** aRetval)
{
MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
if (!len.valid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth;
CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight;
if (!rightMost.valid() || !bottomMost.valid()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
JSObject* darray =
js_CreateTypedArray(aCx, js::TypedArray::TYPE_UINT8_CLAMPED, len.value());
if (!darray) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (mZero) {
*aRetval = darray;
return NS_OK;
}
IntRect srcRect(0, 0, mWidth, mHeight);
IntRect destRect(x, y, w, h);
uint8_t* data = static_cast<uint8_t*>(JS_GetTypedArrayData(darray));
if (!srcRect.Contains(destRect)) {
// Some data is outside the canvas surface, clear the destination.
memset(aData, 0, aDataLen);
}
IntRect srcRect(0, 0, mWidth, mHeight);
IntRect destRect(aX, aY, aWidth, aHeight);
IntRect srcReadRect = srcRect.Intersect(destRect);
IntRect dstWriteRect = srcReadRect;
dstWriteRect.MoveBy(-x, -y);
dstWriteRect.MoveBy(-aX, -aY);
PRUint8 *src = aData;
PRUint32 srcStride = w * 4;
uint8_t* src = data;
uint32_t srcStride = aWidth * 4;
RefPtr<DataSourceSurface> readback;
if (!srcReadRect.IsEmpty()) {
@ -4063,10 +4131,10 @@ nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRU
// NOTE! dst is the same as src, and this relies on reading
// from src and advancing that ptr before writing to dst.
PRUint8 *dst = aData + dstWriteRect.y * (w * 4) + dstWriteRect.x * 4;
uint8_t* dst = data + dstWriteRect.y * (aWidth * 4) + dstWriteRect.x * 4;
for (int j = 0; j < dstWriteRect.height; j++) {
for (int i = 0; i < dstWriteRect.width; i++) {
for (int32_t j = 0; j < dstWriteRect.height; ++j) {
for (int32_t i = 0; i < dstWriteRect.width; ++i) {
// XXX Is there some useful swizzle MMX we can use here?
#ifdef IS_LITTLE_ENDIAN
PRUint8 b = *src++;
@ -4086,8 +4154,10 @@ nsCanvasRenderingContext2DAzure::GetImageData_explicit(PRInt32 x, PRInt32 y, PRU
*dst++ = a;
}
src += srcStride - (dstWriteRect.width * 4);
dst += (w * 4) - (dstWriteRect.width * 4);
dst += (aWidth * 4) - (dstWriteRect.width * 4);
}
*aRetval = darray;
return NS_OK;
}

Просмотреть файл

@ -8219,7 +8219,7 @@ ok(window.Uint8ClampedArray !== undefined, "window.Uint8ClampedArray !== undefin
window.ImageData.prototype.thisImplementsImageData = true;
window.Uint8ClampedArray.prototype.thisImplementsUint8ClampedArray = true;
var imgdata = ctx.getImageData(0, 0, 1, 1);
todo(imgdata.thisImplementsImageData, "imgdata.thisImplementsImageData");
ok(imgdata.thisImplementsImageData, "imgdata.thisImplementsImageData");
ok(imgdata.data.thisImplementsUint8ClampedArray, "imgdata.data.thisImplementsUint8ClampedArray");

Просмотреть файл

@ -70,7 +70,7 @@ interface nsIDOMImageData : nsISupports
readonly attribute jsval data;
};
[scriptable, uuid(274213a8-df51-4b52-bfad-d306a1d5f642)]
[scriptable, uuid(c835c768-2dcc-461c-82f5-3653710d2942)]
interface nsIDOMCanvasRenderingContext2D : nsISupports
{
// back-reference to the canvas element for which
@ -198,15 +198,15 @@ enum CanvasMultiGetterType {
// void putImageData (in ImageData d, in float x, in float y);
// ImageData = { width: #, height: #, data: [r, g, b, a, ...] }
// These are just dummy functions; for JS, they are implemented as quickstubs
// that call the _explicit methods below. Native callers should use the _explit
// methods directly.
void getImageData();
[implicit_jscontext]
nsIDOMImageData getImageData(in double sx, in double sy, in double sw, in double sh);
// This is just a dummy function; for JS, it is implemented as a quickstub
// that call the _explicit methods below. Native callers should use the
// _explicit method directly.
void putImageData();
// dataLen must be == width*height*4 in both of these calls
[noscript] void getImageData_explicit(in long x, in long y, in unsigned long width, in unsigned long height,
[array, size_is(dataLen)] in octet dataPtr, in unsigned long dataLen);
// dataLen must be == width*height*4 in this call
[noscript] void putImageData_explicit(in long x, in long y, in unsigned long width, in unsigned long height,
[array, size_is(dataLen)] in octet dataPtr, in unsigned long dataLen, in boolean hasDirtyRect,
in long dirtyX, in long dirtyY, in long dirtyWidth, in long dirtyHeight);

Просмотреть файл

@ -1002,7 +1002,6 @@ customMethodCalls = {
'nsIDOMWebGLRenderingContext_VertexAttrib4fv': CUSTOM_QS,
# Canvas 2D
'nsIDOMCanvasRenderingContext2D_CreateImageData': CUSTOM_QS,
'nsIDOMCanvasRenderingContext2D_GetImageData': CUSTOM_QS,
'nsIDOMCanvasRenderingContext2D_PutImageData': CUSTOM_QS,
# Nasty hack to make the ordering of |arc| and |arcTo| correct.
# |arc| is not traceable because it has an optional argument.