Loading content/canvas/src/CustomQS_Canvas2D.h +2 −75 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; Loading @@ -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 Loading content/canvas/src/nsCanvasRenderingContext2D.cpp +104 −30 Original line number Diff line number Diff line Loading @@ -85,7 +85,6 @@ #include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeNode.h" #include "nsIXPConnect.h" #include "jsapi.h" #include "nsDisplayList.h" #include "nsTArray.h" Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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; Loading @@ -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; } if (!NS_finite(aSx) || !NS_finite(aSy) || !NS_finite(aSw) || !NS_finite(aSh)) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } 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); CheckedInt32 rightMost = CheckedInt32(x) + w; CheckedInt32 bottomMost = CheckedInt32(y) + h; // 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; } if (!rightMost.valid() || !bottomMost.valid()) 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()) Loading @@ -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. Loading @@ -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(); } } Loading @@ -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++; Loading @@ -3927,6 +4000,7 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 } } *aRetval = darray; return NS_OK; } Loading content/canvas/src/nsCanvasRenderingContext2DAzure.cpp +102 −32 Original line number Diff line number Diff line /* -*- 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 * Loading Loading @@ -82,7 +82,6 @@ #include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeNode.h" #include "nsIXPConnect.h" #include "jsapi.h" #include "nsDisplayList.h" #include "nsTArray.h" Loading @@ -106,15 +105,21 @@ #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/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 Loading Loading @@ -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); /** Loading Loading @@ -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; Loading @@ -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; } 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; } CheckedInt32 rightMost = CheckedInt32(x) + w; CheckedInt32 bottomMost = CheckedInt32(y) + h; if (w == 0) { w = 1; } if (h == 0) { h = 1; } if (!rightMost.valid() || !bottomMost.valid()) 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()) { Loading @@ -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++; Loading @@ -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; } Loading content/canvas/test/test_canvas.html +1 −1 Original line number Diff line number Diff line Loading @@ -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"); Loading dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl +8 −8 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading Loading
content/canvas/src/CustomQS_Canvas2D.h +2 −75 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading Loading @@ -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; Loading @@ -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 Loading
content/canvas/src/nsCanvasRenderingContext2D.cpp +104 −30 Original line number Diff line number Diff line Loading @@ -85,7 +85,6 @@ #include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeNode.h" #include "nsIXPConnect.h" #include "jsapi.h" #include "nsDisplayList.h" #include "nsTArray.h" Loading @@ -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 Loading Loading @@ -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. Loading Loading @@ -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; Loading @@ -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; } if (!NS_finite(aSx) || !NS_finite(aSy) || !NS_finite(aSw) || !NS_finite(aSh)) { return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } 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); CheckedInt32 rightMost = CheckedInt32(x) + w; CheckedInt32 bottomMost = CheckedInt32(y) + h; // 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; } if (!rightMost.valid() || !bottomMost.valid()) 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()) Loading @@ -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. Loading @@ -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(); } } Loading @@ -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++; Loading @@ -3927,6 +4000,7 @@ nsCanvasRenderingContext2D::GetImageData_explicit(PRInt32 x, PRInt32 y, PRUint32 } } *aRetval = darray; return NS_OK; } Loading
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp +102 −32 Original line number Diff line number Diff line /* -*- 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 * Loading Loading @@ -82,7 +82,6 @@ #include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeNode.h" #include "nsIXPConnect.h" #include "jsapi.h" #include "nsDisplayList.h" #include "nsTArray.h" Loading @@ -106,15 +105,21 @@ #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/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 Loading Loading @@ -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); /** Loading Loading @@ -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; Loading @@ -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; } 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; } CheckedInt32 rightMost = CheckedInt32(x) + w; CheckedInt32 bottomMost = CheckedInt32(y) + h; if (w == 0) { w = 1; } if (h == 0) { h = 1; } if (!rightMost.valid() || !bottomMost.valid()) 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()) { Loading @@ -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++; Loading @@ -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; } Loading
content/canvas/test/test_canvas.html +1 −1 Original line number Diff line number Diff line Loading @@ -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"); Loading
dom/interfaces/canvas/nsIDOMCanvasRenderingContext2D.idl +8 −8 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading