Commit b9704abc authored by Ms2ger's avatar Ms2ger
Browse files

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

parent 88749694
Loading
Loading
Loading
Loading
+2 −75
Original line number Diff line number Diff line
@@ -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
+104 −30
Original line number Diff line number Diff line
@@ -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;
    }

    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())
@@ -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;
}

+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
 *
@@ -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 "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
@@ -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;
  }

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

+1 −1
Original line number Diff line number Diff line
@@ -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");
+8 −8
Original line number Diff line number Diff line
@@ -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);
Loading