b=534467; implement Uint8ClampedArray for CanvasPixelArray; part 3, DOM-side implementation; r=bz

This commit is contained in:
Vladimir Vukicevic 2010-03-03 16:40:27 -08:00
Родитель 85abed396c
Коммит 90b432f3ea
6 изменённых файлов: 322 добавлений и 340 удалений

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

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