зеркало из https://github.com/mozilla/gecko-dev.git
b=534467; implement Uint8ClampedArray for CanvasPixelArray; part 3, DOM-side implementation; r=bz
This commit is contained in:
Родитель
85abed396c
Коммит
90b432f3ea
|
@ -1,5 +1,6 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
/* -*- Mode: C++; tab-width: 40; 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
|
||||
|
@ -12,10 +13,10 @@
|
|||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
* The Original Code is Gecko code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
|
@ -23,8 +24,8 @@
|
|||
* Vladimir Vukicevic <vladimir@pobox.com> (original author)
|
||||
*
|
||||
* 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"),
|
||||
* either of 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
|
||||
|
@ -36,6 +37,7 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsDOMError.h"
|
||||
#include "nsIDOMCanvasRenderingContext2D.h"
|
||||
|
||||
typedef nsresult (NS_STDCALL nsIDOMCanvasRenderingContext2D::*CanvasStyleSetterType)(const nsAString &, nsISupports *);
|
||||
|
@ -142,3 +144,216 @@ nsIDOMCanvasRenderingContext2D_GetFillStyle(JSContext *cx, JSObject *obj, jsval
|
|||
{
|
||||
return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetFillStyle_multi);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
XPC_QS_ASSERT_CONTEXT_OK(cx);
|
||||
|
||||
/* Note: this doesn't need JS_THIS_OBJECT */
|
||||
|
||||
if (argc < 2)
|
||||
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
|
||||
int32 wi, hi;
|
||||
if (!JS_ValueToECMAInt32(cx, argv[0], &wi) ||
|
||||
!JS_ValueToECMAInt32(cx, argv[1], &hi))
|
||||
return JS_FALSE;
|
||||
|
||||
if (wi <= 0 || hi <= 0)
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
|
||||
uint32 w = (uint32) wi;
|
||||
uint32 h = (uint32) hi;
|
||||
|
||||
/* Sanity check w * h here */
|
||||
uint32 len0 = w * h;
|
||||
if (len0 / w != (uint32) h)
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
|
||||
uint32 len = len0 * 4;
|
||||
if (len / 4 != len0)
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
|
||||
// create the fast typed array; it's initialized to 0 by default
|
||||
JSObject *darray = js_CreateTypedArray(cx, js::TypedArray::TYPE_UINT8_CLAMPED, len);
|
||||
JSAutoTempValueRooter rd(cx, darray);
|
||||
if (!darray)
|
||||
return JS_FALSE;
|
||||
|
||||
// Do JS_NewObject after CreateTypedArray, so that gc will get
|
||||
// triggered here if necessary
|
||||
JSObject *result = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
JSAutoTempValueRooter rr(cx, result);
|
||||
if (!result)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_DefineProperty(cx, result, "width", INT_TO_JSVAL(w), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) ||
|
||||
!JS_DefineProperty(cx, result, "height", INT_TO_JSVAL(h), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) ||
|
||||
!JS_DefineProperty(cx, result, "data", OBJECT_TO_JSVAL(darray), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
|
||||
return JS_FALSE;
|
||||
|
||||
*vp = OBJECT_TO_JSVAL(result);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
XPC_QS_ASSERT_CONTEXT_OK(cx);
|
||||
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsIDOMCanvasRenderingContext2D *self;
|
||||
xpc_qsSelfRef selfref;
|
||||
JSAutoTempValueRooter tvr(cx);
|
||||
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
|
||||
return JS_FALSE;
|
||||
|
||||
if (argc < 4)
|
||||
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
|
||||
int32 x, y;
|
||||
int32 wi, hi;
|
||||
if (!JS_ValueToECMAInt32(cx, argv[0], &x) ||
|
||||
!JS_ValueToECMAInt32(cx, argv[1], &y) ||
|
||||
!JS_ValueToECMAInt32(cx, argv[2], &wi) ||
|
||||
!JS_ValueToECMAInt32(cx, argv[3], &hi))
|
||||
return JS_FALSE;
|
||||
|
||||
if (wi <= 0 || hi <= 0)
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
|
||||
uint32 w = (uint32) wi;
|
||||
uint32 h = (uint32) hi;
|
||||
|
||||
// Sanity check w * h here
|
||||
uint32 len0 = w * h;
|
||||
if (len0 / w != (uint32) h)
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
|
||||
uint32 len = len0 * 4;
|
||||
if (len / 4 != len0)
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
|
||||
// create the fast typed array
|
||||
JSObject *darray = js_CreateTypedArray(cx, js::TypedArray::TYPE_UINT8_CLAMPED, len);
|
||||
JSAutoTempValueRooter rd(cx, darray);
|
||||
if (!darray)
|
||||
return JS_FALSE;
|
||||
|
||||
js::TypedArray *tdest = js::TypedArray::fromJSObject(darray);
|
||||
|
||||
// make the call
|
||||
rv = self->GetImageData_explicit(x, y, w, h, (PRUint8*) tdest->data, tdest->byteLength);
|
||||
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);
|
||||
JSAutoTempValueRooter rr(cx, result);
|
||||
if (!result)
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_DefineProperty(cx, result, "width", INT_TO_JSVAL(w), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) ||
|
||||
!JS_DefineProperty(cx, result, "height", INT_TO_JSVAL(h), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT) ||
|
||||
!JS_DefineProperty(cx, result, "data", OBJECT_TO_JSVAL(darray), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT))
|
||||
return JS_FALSE;
|
||||
|
||||
*vp = OBJECT_TO_JSVAL(result);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, uintN argc, jsval *vp)
|
||||
{
|
||||
XPC_QS_ASSERT_CONTEXT_OK(cx);
|
||||
|
||||
JSObject *obj = JS_THIS_OBJECT(cx, vp);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsIDOMCanvasRenderingContext2D *self;
|
||||
xpc_qsSelfRef selfref;
|
||||
JSAutoTempValueRooter tvr(cx);
|
||||
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
|
||||
return JS_FALSE;
|
||||
|
||||
if (argc < 3)
|
||||
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
|
||||
|
||||
jsval *argv = JS_ARGV(cx, vp);
|
||||
|
||||
if (JSVAL_IS_PRIMITIVE(argv[0]))
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
|
||||
|
||||
JSObject *dataObject = JSVAL_TO_OBJECT(argv[0]);
|
||||
int32 x, y;
|
||||
if (!JS_ValueToECMAInt32(cx, argv[1], &x) ||
|
||||
!JS_ValueToECMAInt32(cx, argv[2], &y))
|
||||
return JS_FALSE;
|
||||
|
||||
int32 wi, hi;
|
||||
JSObject *darray;
|
||||
|
||||
// grab width, height, and the dense array from the dataObject
|
||||
JSAutoTempValueRooter tv(cx);
|
||||
|
||||
if (!JS_GetProperty(cx, dataObject, "width", tv.addr()) ||
|
||||
!JS_ValueToECMAInt32(cx, tv.value(), &wi))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_GetProperty(cx, dataObject, "height", tv.addr()) ||
|
||||
!JS_ValueToECMAInt32(cx, tv.value(), &hi))
|
||||
return JS_FALSE;
|
||||
|
||||
if (wi <= 0 || hi <= 0)
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
|
||||
uint32 w = (uint32) wi;
|
||||
uint32 h = (uint32) hi;
|
||||
|
||||
if (!JS_GetProperty(cx, dataObject, "data", tv.addr()) ||
|
||||
JSVAL_IS_PRIMITIVE(tv.value()))
|
||||
return JS_FALSE;
|
||||
darray = JSVAL_TO_OBJECT(tv.value());
|
||||
|
||||
JSAutoTempValueRooter tsrc_tvr(cx);
|
||||
|
||||
js::TypedArray *tsrc = NULL;
|
||||
if (darray->getClass() == &js::TypedArray::fastClasses[js::TypedArray::TYPE_UINT8] ||
|
||||
darray->getClass() == &js::TypedArray::fastClasses[js::TypedArray::TYPE_UINT8_CLAMPED])
|
||||
{
|
||||
tsrc = js::TypedArray::fromJSObject(darray);
|
||||
} else if (JS_IsArrayObject(cx, darray) || js_IsTypedArray(darray)) {
|
||||
// ugh, this isn't a uint8 typed array, someone made their own object; convert it to a typed array
|
||||
JSObject *nobj = js_CreateTypedArrayWithArray(cx, js::TypedArray::TYPE_UINT8, darray);
|
||||
if (!nobj)
|
||||
return JS_FALSE;
|
||||
|
||||
*tsrc_tvr.addr() = OBJECT_TO_JSVAL(nobj);
|
||||
tsrc = js::TypedArray::fromJSObject(nobj);
|
||||
} else {
|
||||
// yeah, no.
|
||||
return xpc_qsThrow(cx, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
|
||||
}
|
||||
|
||||
// make the call
|
||||
rv = self->PutImageData_explicit(x, y, w, h, (PRUint8*) tsrc->data, tsrc->byteLength);
|
||||
if (NS_FAILED(rv))
|
||||
return xpc_qsThrowMethodFailed(cx, rv, vp);
|
||||
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
|
|
@ -3426,9 +3426,16 @@ nsCanvasRenderingContext2D::EnsureUnpremultiplyTable() {
|
|||
}
|
||||
|
||||
|
||||
// ImageData getImageData (in float x, in float y, in float width, in float height);
|
||||
NS_IMETHODIMP
|
||||
nsCanvasRenderingContext2D::GetImageData()
|
||||
{
|
||||
/* 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 (!mValid)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -3438,42 +3445,15 @@ nsCanvasRenderingContext2D::GetImageData()
|
|||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsAXPCNativeCallContext *ncc = nsnull;
|
||||
nsresult rv = nsContentUtils::XPConnect()->
|
||||
GetCurrentNativeCallContext(&ncc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!ncc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSContext *ctx = nsnull;
|
||||
|
||||
rv = ncc->GetJSContext(&ctx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 argc;
|
||||
jsval *argv = nsnull;
|
||||
|
||||
ncc->GetArgc(&argc);
|
||||
ncc->GetArgvPtr(&argv);
|
||||
|
||||
JSAutoRequest ar(ctx);
|
||||
|
||||
int32 x, y, w, h;
|
||||
if (!JS_ConvertArguments (ctx, argc, argv, "jjjj", &x, &y, &w, &h))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
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]);
|
||||
int surfaceDataStride = w*4;
|
||||
int surfaceDataOffset = 0;
|
||||
PRUint32 len = w * h * 4;
|
||||
if (aDataLen != len)
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (!surfaceData)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsRefPtr<gfxImageSurface> tmpsurf = new gfxImageSurface(surfaceData,
|
||||
/* Copy the surface contents to the buffer */
|
||||
nsRefPtr<gfxImageSurface> tmpsurf = new gfxImageSurface(aData,
|
||||
gfxIntSize(w, h),
|
||||
w * 4,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
|
@ -3489,99 +3469,39 @@ nsCanvasRenderingContext2D::GetImageData()
|
|||
tmpctx->SetSource(mSurface, gfxPoint(-(int)x, -(int)y));
|
||||
tmpctx->Paint();
|
||||
|
||||
tmpctx = nsnull;
|
||||
tmpsurf = nsnull;
|
||||
|
||||
PRUint32 len = w * h * 4;
|
||||
if (len > (((PRUint32)0xfff00000)/sizeof(jsval)))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
jsval *dest;
|
||||
JSObject *dataArray = js_NewArrayObjectWithCapacity(ctx, len, &dest);
|
||||
if (!dataArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// make sure sUnpremultiplyTable has been created
|
||||
EnsureUnpremultiplyTable();
|
||||
|
||||
PRUint8 *row;
|
||||
// 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;
|
||||
|
||||
for (int j = 0; j < h; j++) {
|
||||
row = surfaceData + surfaceDataOffset + (surfaceDataStride * j);
|
||||
for (int i = 0; i < w; i++) {
|
||||
// XXX Is there some useful swizzle MMX we can use here?
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
PRUint8 b = *row++;
|
||||
PRUint8 g = *row++;
|
||||
PRUint8 r = *row++;
|
||||
PRUint8 a = *row++;
|
||||
PRUint8 b = *src++;
|
||||
PRUint8 g = *src++;
|
||||
PRUint8 r = *src++;
|
||||
PRUint8 a = *src++;
|
||||
#else
|
||||
PRUint8 a = *row++;
|
||||
PRUint8 r = *row++;
|
||||
PRUint8 g = *row++;
|
||||
PRUint8 b = *row++;
|
||||
PRUint8 a = *src++;
|
||||
PRUint8 r = *src++;
|
||||
PRUint8 g = *src++;
|
||||
PRUint8 b = *src++;
|
||||
#endif
|
||||
// Convert to non-premultiplied color
|
||||
|
||||
*dest++ = INT_TO_JSVAL(sUnpremultiplyTable[a][r]);
|
||||
*dest++ = INT_TO_JSVAL(sUnpremultiplyTable[a][g]);
|
||||
*dest++ = INT_TO_JSVAL(sUnpremultiplyTable[a][b]);
|
||||
*dest++ = INT_TO_JSVAL(a);
|
||||
*dst++ = sUnpremultiplyTable[a][r];
|
||||
*dst++ = sUnpremultiplyTable[a][g];
|
||||
*dst++ = sUnpremultiplyTable[a][b];
|
||||
*dst++ = a;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate result object after array, so if we have to trigger gc
|
||||
// we do it now.
|
||||
JSObject *result = JS_NewObject(ctx, NULL, NULL, NULL);
|
||||
if (!result)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsAutoGCRoot resultGCRoot(&result, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!JS_DefineProperty(ctx, result, "width", INT_TO_JSVAL(w), NULL, NULL, 0) ||
|
||||
!JS_DefineProperty(ctx, result, "height", INT_TO_JSVAL(h), NULL, NULL, 0) ||
|
||||
!JS_DefineProperty(ctx, result, "data", OBJECT_TO_JSVAL(dataArray), NULL, NULL, 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
jsval *retvalPtr;
|
||||
ncc->GetRetValPtr(&retvalPtr);
|
||||
*retvalPtr = OBJECT_TO_JSVAL(result);
|
||||
ncc->SetReturnValueWasSet(PR_TRUE);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static inline PRUint8 ToUint8(jsint aInput)
|
||||
{
|
||||
if (PRUint32(aInput) > 255)
|
||||
return (aInput < 0) ? 0 : 255;
|
||||
return PRUint8(aInput);
|
||||
}
|
||||
|
||||
static inline PRUint8 ToUint8(double aInput)
|
||||
{
|
||||
if (!(aInput >= 0)) /* Not < so that NaN coerces to 0 */
|
||||
return 0;
|
||||
if (aInput > 255)
|
||||
return 255;
|
||||
double toTruncate = aInput + 0.5;
|
||||
PRUint8 retval = PRUint8(toTruncate);
|
||||
|
||||
// now retval is rounded to nearest, ties rounded up. We want
|
||||
// rounded to nearest ties to even, so check whether we had a tie.
|
||||
if (retval == toTruncate) {
|
||||
// It was a tie (since adding 0.5 gave us the exact integer we want).
|
||||
// Since we rounded up, we either already have an even number or we
|
||||
// have an odd number but the number we want is one less. So just
|
||||
// unconditionally masking out the ones bit should do the trick to get
|
||||
// us the value we want.
|
||||
return (retval & ~1);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void
|
||||
nsCanvasRenderingContext2D::EnsurePremultiplyTable() {
|
||||
if (sPremultiplyTable)
|
||||
|
@ -3604,163 +3524,60 @@ nsCanvasRenderingContext2D::EnsurePremultiplyTable() {
|
|||
// void putImageData (in ImageData d, in float x, in float y);
|
||||
NS_IMETHODIMP
|
||||
nsCanvasRenderingContext2D::PutImageData()
|
||||
{
|
||||
/* Should never be called -- PutImageData_explicit is the QS entry point */
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 w, PRUint32 h,
|
||||
unsigned char *aData, PRUint32 aDataLen)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mValid)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAXPCNativeCallContext *ncc = nsnull;
|
||||
rv = nsContentUtils::XPConnect()->
|
||||
GetCurrentNativeCallContext(&ncc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!ncc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSContext *ctx = nsnull;
|
||||
|
||||
rv = ncc->GetJSContext(&ctx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 argc;
|
||||
jsval *argv = nsnull;
|
||||
|
||||
ncc->GetArgc(&argc);
|
||||
ncc->GetArgvPtr(&argv);
|
||||
|
||||
JSAutoRequest ar(ctx);
|
||||
|
||||
JSObject *dataObject;
|
||||
int32 x, y;
|
||||
|
||||
if (!JS_ConvertArguments (ctx, argc, argv, "ojj", &dataObject, &x, &y))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (!dataObject)
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
int32 w, h;
|
||||
JSObject *dataArray;
|
||||
jsval v;
|
||||
|
||||
if (!JS_GetProperty(ctx, dataObject, "width", &v) ||
|
||||
!JS_ValueToInt32(ctx, v, &w))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (!JS_GetProperty(ctx, dataObject, "height", &v) ||
|
||||
!JS_ValueToInt32(ctx, v, &h))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (!JS_GetProperty(ctx, dataObject, "data", &v) ||
|
||||
!JSVAL_IS_OBJECT(v))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
dataArray = JSVAL_TO_OBJECT(v);
|
||||
|
||||
if (!CanvasUtils::CheckSaneSubrectSize (x, y, w, h, mWidth, mHeight))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
jsuint arrayLen;
|
||||
if (!JS_IsArrayObject(ctx, dataArray) ||
|
||||
!JS_GetArrayLength(ctx, dataArray, &arrayLen) ||
|
||||
arrayLen < (jsuint)(w * h * 4))
|
||||
PRUint32 len = w * h * 4;
|
||||
if (aDataLen != len)
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
nsAutoArrayPtr<PRUint8> imageBuffer(new (std::nothrow) PRUint8[w * h * 4]);
|
||||
if (!imageBuffer)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PRUint8 *imgPtr = imageBuffer.get();
|
||||
|
||||
EnsurePremultiplyTable();
|
||||
|
||||
JSBool canFastPath =
|
||||
js_CoerceArrayToCanvasImageData(dataArray, 0, w*h*4, imageBuffer);
|
||||
|
||||
// no fast path? go slow. We sadly need this for now, instead of just
|
||||
// throwing, because dataArray might not be dense in case someone stuck
|
||||
// their own array on the imageData.
|
||||
// FIXME: it'd be awfully nice if we could prevent such modification of
|
||||
// imageData objects, since it's likely the spec won't allow it anyway.
|
||||
// Bug 497110 covers this.
|
||||
if (!canFastPath) {
|
||||
jsval vr, vg, vb, va;
|
||||
PRUint8 ir, ig, ib, ia;
|
||||
for (int32 j = 0; j < h; j++) {
|
||||
int32 lineOffset = (j*w*4);
|
||||
for (int32 i = 0; i < w; i++) {
|
||||
int32 pixelOffset = lineOffset + i*4;
|
||||
if (!JS_GetElement(ctx, dataArray, pixelOffset + 0, &vr) ||
|
||||
!JS_GetElement(ctx, dataArray, pixelOffset + 1, &vg) ||
|
||||
!JS_GetElement(ctx, dataArray, pixelOffset + 2, &vb) ||
|
||||
!JS_GetElement(ctx, dataArray, pixelOffset + 3, &va))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (JSVAL_IS_INT(vr)) ir = ToUint8(JSVAL_TO_INT(vr));
|
||||
else if (JSVAL_IS_DOUBLE(vr)) ir = ToUint8(*JSVAL_TO_DOUBLE(vr));
|
||||
else return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (JSVAL_IS_INT(vg)) ig = ToUint8(JSVAL_TO_INT(vg));
|
||||
else if (JSVAL_IS_DOUBLE(vg)) ig = ToUint8(*JSVAL_TO_DOUBLE(vg));
|
||||
else return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (JSVAL_IS_INT(vb)) ib = ToUint8(JSVAL_TO_INT(vb));
|
||||
else if (JSVAL_IS_DOUBLE(vb)) ib = ToUint8(*JSVAL_TO_DOUBLE(vb));
|
||||
else return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (JSVAL_IS_INT(va)) ia = ToUint8(JSVAL_TO_INT(va));
|
||||
else if (JSVAL_IS_DOUBLE(va)) ia = ToUint8(*JSVAL_TO_DOUBLE(va));
|
||||
else return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
// Convert to premultiplied color (losslessly if the input came from getImageData)
|
||||
ir = sPremultiplyTable[ia][ir];
|
||||
ig = sPremultiplyTable[ia][ig];
|
||||
ib = sPremultiplyTable[ia][ib];
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
*imgPtr++ = ib;
|
||||
*imgPtr++ = ig;
|
||||
*imgPtr++ = ir;
|
||||
*imgPtr++ = ia;
|
||||
#else
|
||||
*imgPtr++ = ia;
|
||||
*imgPtr++ = ir;
|
||||
*imgPtr++ = ig;
|
||||
*imgPtr++ = ib;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Walk through and premultiply and swap rgba */
|
||||
PRUint8 ir, ig, ib, ia;
|
||||
PRUint8 *ptr = imgPtr;
|
||||
for (int32 i = 0; i < w*h; i++) {
|
||||
ir = ptr[0];
|
||||
ig = ptr[1];
|
||||
ib = ptr[2];
|
||||
ia = ptr[3];
|
||||
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
ptr[0] = sPremultiplyTable[ia][ib];
|
||||
ptr[1] = sPremultiplyTable[ia][ig];
|
||||
ptr[2] = sPremultiplyTable[ia][ir];
|
||||
#else
|
||||
ptr[0] = ia;
|
||||
ptr[1] = sPremultiplyTable[ia][ir];
|
||||
ptr[2] = sPremultiplyTable[ia][ig];
|
||||
ptr[3] = sPremultiplyTable[ia][ib];
|
||||
#endif
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(imageBuffer.get(),
|
||||
gfxIntSize(w, h),
|
||||
w * 4,
|
||||
nsRefPtr<gfxImageSurface> imgsurf = new gfxImageSurface(gfxIntSize(w, h),
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (!imgsurf || imgsurf->CairoStatus())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// ensure premultiply table has been created
|
||||
EnsurePremultiplyTable();
|
||||
|
||||
PRUint8 *src = aData;
|
||||
PRUint8 *dst = imgsurf->Data();
|
||||
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
PRUint8 r = *src++;
|
||||
PRUint8 g = *src++;
|
||||
PRUint8 b = *src++;
|
||||
PRUint8 a = *src++;
|
||||
|
||||
// Convert to premultiplied color (losslessly if the input came from getImageData)
|
||||
#ifdef IS_LITTLE_ENDIAN
|
||||
*dst++ = sPremultiplyTable[a][b];
|
||||
*dst++ = sPremultiplyTable[a][g];
|
||||
*dst++ = sPremultiplyTable[a][r];
|
||||
*dst++ = a;
|
||||
#else
|
||||
*dst++ = a;
|
||||
*dst++ = sPremultiplyTable[a][r];
|
||||
*dst++ = sPremultiplyTable[a][g];
|
||||
*dst++ = sPremultiplyTable[a][b];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
gfxContextPathAutoSaveRestore pathSR(mThebes);
|
||||
gfxContextAutoSaveRestore autoSR(mThebes);
|
||||
|
||||
|
@ -3775,7 +3592,7 @@ nsCanvasRenderingContext2D::PutImageData()
|
|||
mThebes->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
mThebes->Fill();
|
||||
|
||||
return Redraw();
|
||||
return Redraw(gfxRect(x, y, w, h));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -3795,79 +3612,8 @@ nsCanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
|
|||
NS_IMETHODIMP
|
||||
nsCanvasRenderingContext2D::CreateImageData()
|
||||
{
|
||||
if (!mValid)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAXPCNativeCallContext *ncc = nsnull;
|
||||
nsresult rv = nsContentUtils::XPConnect()->
|
||||
GetCurrentNativeCallContext(&ncc);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!ncc)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JSContext *ctx = nsnull;
|
||||
|
||||
rv = ncc->GetJSContext(&ctx);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 argc;
|
||||
jsval *argv = nsnull;
|
||||
|
||||
ncc->GetArgc(&argc);
|
||||
ncc->GetArgvPtr(&argv);
|
||||
|
||||
JSAutoRequest ar(ctx);
|
||||
|
||||
int32 width, height;
|
||||
if (!JS_ConvertArguments (ctx, argc, argv, "jj", &width, &height))
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
|
||||
PRUint32 w = (PRUint32) width;
|
||||
PRUint32 h = (PRUint32) height;
|
||||
|
||||
// check for overflow when calculating len
|
||||
PRUint32 len0 = w * h;
|
||||
if (len0 / w != (PRUint32) h)
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
PRUint32 len = len0 * 4;
|
||||
if (len / 4 != len0)
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
|
||||
jsval *dest;
|
||||
JSObject *dataArray = js_NewArrayObjectWithCapacity(ctx, len, &dest);
|
||||
if (!dataArray)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsAutoGCRoot arrayGCRoot(&dataArray, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (PRUint32 i = 0; i < len; i++)
|
||||
*dest++ = JSVAL_ZERO;
|
||||
|
||||
// Allocate result object after array, so if we have to trigger gc
|
||||
// we do it now.
|
||||
JSObject *result = JS_NewObject(ctx, NULL, NULL, NULL);
|
||||
if (!result)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsAutoGCRoot resultGCRoot(&result, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!JS_DefineProperty(ctx, result, "width", INT_TO_JSVAL(w), NULL, NULL, 0) ||
|
||||
!JS_DefineProperty(ctx, result, "height", INT_TO_JSVAL(h), NULL, NULL, 0) ||
|
||||
!JS_DefineProperty(ctx, result, "data", OBJECT_TO_JSVAL(dataArray), NULL, NULL, 0))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
jsval *retvalPtr;
|
||||
ncc->GetRetValPtr(&retvalPtr);
|
||||
*retvalPtr = OBJECT_TO_JSVAL(result);
|
||||
ncc->SetReturnValueWasSet(PR_TRUE);
|
||||
|
||||
return NS_OK;
|
||||
/* Should never be called; handled entirely in the quickstub */
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -182,10 +182,22 @@ 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();
|
||||
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);
|
||||
[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);
|
||||
|
||||
// ImageData createImageData(in float w, in float h);
|
||||
// Note: this is basically script-only (and really, quickstub-only). Native callers
|
||||
// should just use the noscript 'explicit' get/put methods above, instead of using
|
||||
// a separate ImageData object.
|
||||
void createImageData();
|
||||
|
||||
// image smoothing mode -- if disabled, images won't be smoothed
|
||||
|
|
|
@ -12089,6 +12089,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
|||
case js::TypedArray::TYPE_UINT8_CLAMPED:
|
||||
addr_ins = lir->ins2(LIR_piadd, data_ins, pidx_ins);
|
||||
lir->insStore(LIR_stb, lir->insCall(&js_TypedArray_uint8_clamp_double_ci, &v_ins), addr_ins, 0);
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("Unknown typed array type in tracer");
|
||||
}
|
||||
|
|
|
@ -520,9 +520,18 @@ class TypedArrayTemplate
|
|||
jsuint index;
|
||||
// We can't just chain to js_SetProperty, because we're not a normal object.
|
||||
if (!tarray->isArrayIndex(cx, id, &index)) {
|
||||
#if 0
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
||||
JSMSG_TYPED_ARRAY_BAD_INDEX);
|
||||
return false;
|
||||
#endif
|
||||
// Silent ignore is better than an exception here, because
|
||||
// at some point we may want to support other properties on
|
||||
// these objects. This is especially true when these arrays
|
||||
// are used to implement HTML Canvas 2D's PixelArray objects,
|
||||
// which used to be plain old arrays.
|
||||
*vp = JSVAL_VOID;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (JSVAL_IS_INT(*vp)) {
|
||||
|
|
|
@ -92,11 +92,6 @@ members = [
|
|||
'nsIDOMTextMetrics.*',
|
||||
'nsIDOMCanvasGradient.*',
|
||||
'nsIDOMCanvasPattern.*',
|
||||
# NOTE: createImageDate(), getImageData(), and putImageData() use
|
||||
# GetCurrentNativeCallContext
|
||||
'-nsIDOMCanvasRenderingContext2D.createImageData',
|
||||
'-nsIDOMCanvasRenderingContext2D.getImageData',
|
||||
'-nsIDOMCanvasRenderingContext2D.putImageData',
|
||||
|
||||
# dom/interfaces/core
|
||||
'nsIDOMCharacterData.data',
|
||||
|
@ -625,6 +620,10 @@ customMethodCalls = {
|
|||
'nsICanvasRenderingContextWebGL_VertexAttrib1fv': CUSTOM_QS,
|
||||
'nsICanvasRenderingContextWebGL_VertexAttrib2fv': CUSTOM_QS,
|
||||
'nsICanvasRenderingContextWebGL_VertexAttrib3fv': CUSTOM_QS,
|
||||
'nsICanvasRenderingContextWebGL_VertexAttrib4fv': CUSTOM_QS
|
||||
'nsICanvasRenderingContextWebGL_VertexAttrib4fv': CUSTOM_QS,
|
||||
# Canvas 2D
|
||||
'nsIDOMCanvasRenderingContext2D_CreateImageData': CUSTOM_QS,
|
||||
'nsIDOMCanvasRenderingContext2D_GetImageData': CUSTOM_QS,
|
||||
'nsIDOMCanvasRenderingContext2D_PutImageData': CUSTOM_QS,
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче