Bug 959958 - Implement ImageData constructor. r=bz
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Tue, 28 Jan 2014 22:04:40 +0900
changeset 181606 4a801fc0581969d58ccd0d6a0f5cf9528a99d9c8
parent 181605 38cb01168c322c9daf55befad2cee88ba6b166c1
child 181607 d52d1a8ea36ccc36ea64988105f151745f01c465
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs959958
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 959958 - Implement ImageData constructor. r=bz
content/canvas/src/ImageData.cpp
content/canvas/src/ImageData.h
content/canvas/test/mochitest.ini
content/canvas/test/test_ImageData_ctor.html
content/canvas/test/test_canvas.html
dom/webidl/ImageData.webidl
--- a/content/canvas/src/ImageData.cpp
+++ b/content/canvas/src/ImageData.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ImageData.h"
 
+#include "mozilla/CheckedInt.h"
 #include "mozilla/HoldDropJSObjects.h"
 #include "mozilla/dom/ImageDataBinding.h"
 
 #include "jsapi.h"
 
 namespace mozilla {
 namespace dom {
 
@@ -30,16 +31,69 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ImageData)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ImageData)
   tmp->DropData();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
+//static
+ImageData*
+ImageData::Constructor(const GlobalObject& aGlobal,
+                       const uint32_t aWidth,
+                       const uint32_t aHeight,
+                       ErrorResult& aRv)
+{
+  if (aWidth == 0 || aHeight == 0) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  CheckedInt<uint32_t> length = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
+  if (!length.isValid()) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  JS::Rooted<JSObject*> obj(aGlobal.GetContext(), aGlobal.Get());
+  JSObject* data = Uint8ClampedArray::Create(aGlobal.GetContext(), obj,
+                                             length.value());
+  if (!data) {
+    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
+    return nullptr;
+  }
+  return new ImageData(aWidth, aHeight, *data);
+}
+
+//static
+ImageData*
+ImageData::Constructor(const GlobalObject& aGlobal,
+                       const Uint8ClampedArray& aData,
+                       const uint32_t aWidth,
+                       const Optional<uint32_t>& aHeight,
+                       ErrorResult& aRv)
+{
+  uint32_t length = aData.Length();
+  if (length == 0 || length % 4) {
+    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
+    return nullptr;
+  }
+  length /= 4;
+  if (aWidth == 0) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  uint32_t height = length / aWidth;
+  if (length != aWidth * height ||
+      (aHeight.WasPassed() && aHeight.Value() != height)) {
+    aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+    return nullptr;
+  }
+  return new ImageData(aWidth, height, *aData.Obj());
+}
+
 void
 ImageData::HoldData()
 {
   mozilla::HoldJSObjects(this);
 }
 
 void
 ImageData::DropData()
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -5,16 +5,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ImageData_h
 #define mozilla_dom_ImageData_h
 
 #include "nsIDOMCanvasRenderingContext2D.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/TypedArray.h"
 #include <stdint.h>
 
 #include "nsCycleCollectionParticipant.h"
 #include "nsTraceRefcnt.h"
 #include "js/GCAPI.h"
 
 namespace mozilla {
 namespace dom {
@@ -35,16 +37,27 @@ public:
   {
     MOZ_COUNT_DTOR(ImageData);
     DropData();
   }
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageData)
 
+  static ImageData* Constructor(const GlobalObject& aGlobal,
+                                const uint32_t aWidth,
+                                const uint32_t aHeight,
+                                ErrorResult& aRv);
+
+  static ImageData* Constructor(const GlobalObject& aGlobal,
+                                const Uint8ClampedArray& aData,
+                                const uint32_t aWidth,
+                                const Optional<uint32_t>& aHeight,
+                                ErrorResult& aRv);
+
   uint32_t Width() const
   {
     return mWidth;
   }
   uint32_t Height() const
   {
     return mHeight;
   }
--- a/content/canvas/test/mochitest.ini
+++ b/content/canvas/test/mochitest.ini
@@ -92,16 +92,17 @@ support-files =
 [test_bug902651.html]
 [test_canvas.html]
 [test_canvas_focusring.html]
 [test_canvas_font_setter.html]
 [test_canvas_strokeStyle_getter.html]
 [test_drawImageIncomplete.html]
 [test_drawImage_document_domain.html]
 [test_drawImage_edge_cases.html]
+[test_ImageData_ctor.html]
 [test_isPointInStroke.html]
 [test_mozDashOffset.html]
 [test_mozGetAsFile.html]
 [test_strokeText_throw.html]
 [test_toBlob.html]
 [test_toDataURL_alpha.html]
 [test_toDataURL_lowercase_ascii.html]
 [test_toDataURL_parameters.html]
new file mode 100644
--- /dev/null
+++ b/content/canvas/test/test_ImageData_ctor.html
@@ -0,0 +1,80 @@
+<!DOCTYPE HTML><meta charset=utf-8>
+<title>Canvas test: ImageData</title>
+<script type="text/javascript" src="/resources/testharness.js"></script>
+<script type="text/javascript" src="/resources/testharnessreport.js"></script>
+<body>
+<div id="log"></div>
+<script>
+
+test(function() {
+  assert_throws(new TypeError(), function(){ new ImageData(); });
+  assert_throws(new TypeError(), function(){ new ImageData(1); });
+  assert_throws(new TypeError(), function(){ new ImageData(new Uint8ClampedArray([1,2,3,4])); });
+  assert_throws("IndexSizeError", function(){ new ImageData(0,0); });
+  assert_throws("IndexSizeError", function(){ new ImageData(0,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(1,0); });
+  new ImageData(1,1);
+  new ImageData(1,2);
+  new ImageData(1,3);
+  assert_throws("IndexSizeError", function(){ new ImageData(2,0); });
+  new ImageData(2,1);
+  new ImageData(2,2);
+  assert_throws("IndexSizeError", function(){ new ImageData(32768,32768); });
+  assert_throws("IndexSizeError", function(){ new ImageData(32768,32769); });
+  assert_throws("IndexSizeError", function(){ new ImageData(32769,32768); });
+  assert_throws("IndexSizeError", function(){ new ImageData(2,536870912); });
+  assert_throws("IndexSizeError", function(){ new ImageData(2,536870913); });
+  assert_throws("IndexSizeError", function(){ new ImageData(536870912,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(536870913,2); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),0); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),0,0); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3]),1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5]),1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4]),1);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1);
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),3); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3]),1,1); });
+  assert_throws("InvalidStateError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5]),1,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0,0); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),0,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),1,0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4]),1,1);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),1,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2,0); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2,1); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4]),2,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1,1); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1,2);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),1,3); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,0); });
+  new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,1);
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,536870912); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),2,536870913); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),536870912,2); });
+  assert_throws("IndexSizeError", function(){ new ImageData(new Uint8ClampedArray([1,2,3,4,5,6,7,8]),536870913,2); });
+}, "Test constructor arguments");
+
+test(function() {
+  var data = new Uint8ClampedArray([1,2,3,4,5,6,7,8]);
+  var imgData = new ImageData(data,1);
+  assert_equals(imgData.width, 1);
+  assert_equals(imgData.height, 2);
+  assert_array_equals(imgData.data, [1,2,3,4,5,6,7,8]);
+  data.set([8,7,6,5,4,3,2,1]);
+  assert_array_equals(imgData.data, [8,7,6,5,4,3,2,1]);
+}, "The data argument is not copied");
+
+</script>
+
--- a/content/canvas/test/test_canvas.html
+++ b/content/canvas/test/test_canvas.html
@@ -8358,19 +8358,26 @@ ok(imgdata.data[0] === 255, "imgdata.dat
 <script>
 
 function test_2d_imageData_object_ctor() {
 
 var canvas = document.getElementById('c280');
 var ctx = canvas.getContext('2d');
 
 ok(window.ImageData !== undefined, "window.ImageData !== undefined");
-try { var _thrown = false;
-  new window.ImageData(1,1);
-} catch (e) { _thrown = true; } finally { ok(_thrown, "should throw exception"); }
+
+var _thrown_outer = false;
+try {
+
+new window.ImageData(1,1);
+
+} catch (e) {
+    _thrown_outer = true;
+}
+ok(!_thrown_outer, ctx.canvas.id + ' should not throw exception');
 
 
 }
 </script>
 
 <!-- [[[ test_2d.imageData.object.nan.html ]]] -->
 
 <p>Canvas test: 2d.imageData.object.nan</p>
--- a/dom/webidl/ImageData.webidl
+++ b/dom/webidl/ImageData.webidl
@@ -5,16 +5,18 @@
  *
  * The origin of this IDL file is
  * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata
  *
  * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and Opera Software ASA.
  * You are granted a license to use, reproduce and create derivative works of this document.
  */
 
+[Constructor(unsigned long sw, unsigned long sh),
+ Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh)]
 interface ImageData {
  [Constant]
  readonly attribute unsigned long width;
  [Constant]
  readonly attribute unsigned long height;
  [Constant, StoreInSlot]
  readonly attribute Uint8ClampedArray data;
 };