Bug 1239300 - reject promise with null while creating imagebitmap from empty blob; r=smaug
authorKaku Kuo <tkuo@mozilla.com>
Tue, 19 Jan 2016 14:35:01 +0800
changeset 304863 060438e9046e8ffb053b431e04cfa4e06eb7aedb
parent 304862 b7d242697573582facc85968cabe4aa64f39fd29
child 304864 55bd36961865f0d768227807ee9b6c1820c26668
push id9214
push userraliiev@mozilla.com
push dateMon, 07 Mar 2016 14:25:21 +0000
treeherdermozilla-aurora@8849dd1a4a79 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1239300
milestone47.0a1
Bug 1239300 - reject promise with null while creating imagebitmap from empty blob; r=smaug
dom/canvas/ImageBitmap.cpp
dom/canvas/test/imagebitmap_bug1239300.js
dom/canvas/test/imagebitmap_on_worker.js
dom/canvas/test/mochitest.ini
dom/canvas/test/test_imagebitmap.html
dom/canvas/test/test_imagebitmap_on_worker.html
dom/promise/Promise.cpp
dom/promise/Promise.h
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -1060,17 +1060,17 @@ public:
   }
 
 private:
   already_AddRefed<ImageBitmap> CreateImageBitmap() override
   {
     RefPtr<layers::Image> data = DecodeAndCropBlob(*mBlob, mCropRect);
 
     if (NS_WARN_IF(!data)) {
-      mPromise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
+      mPromise->MaybeRejectWithNull();
       return nullptr;
     }
 
     // Create ImageBitmap object.
     RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data);
     return imageBitmap.forget();
   }
 };
@@ -1138,19 +1138,19 @@ private:
                                          getter_AddRefs(data));
     task->Dispatch(rv); // This is a synchronous call.
 
     if (NS_WARN_IF(rv.Failed())) {
       // XXXbz does this really make sense if we're shutting down?  Ah, well.
       mPromise->MaybeReject(rv);
       return nullptr;
     }
-    
+
     if (NS_WARN_IF(!data)) {
-      mPromise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
+      mPromise->MaybeRejectWithNull();
       return nullptr;
     }
 
     // Create ImageBitmap object.
     RefPtr<ImageBitmap> imageBitmap = new ImageBitmap(mGlobalObject, data);
     return imageBitmap.forget();
   }
 
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/imagebitmap_bug1239300.js
@@ -0,0 +1,19 @@
+function testBug1239300() {
+  return new Promise(function(resolve, reject) {
+    createImageBitmap(new Blob()).then(
+      function() {
+        ok(false, "The promise should be rejected with null.");
+        reject();
+      },
+      function(result) {
+        if (result == null) {
+          ok(true, "The promise should be rejected with null.");
+          resolve();
+        } else {
+          ok(false, "The promise should be rejected with null.");
+          reject();
+        }
+      }
+    );
+  });
+}
\ No newline at end of file
--- a/dom/canvas/test/imagebitmap_on_worker.js
+++ b/dom/canvas/test/imagebitmap_on_worker.js
@@ -1,8 +1,10 @@
+importScripts("imagebitmap_bug1239300.js");
+
 function ok(expect, msg) {
   postMessage({type: "status", status: !!expect, msg: msg});
 }
 
 function doneTask() {
   postMessage({type: "doneTask"});
 }
 
@@ -72,10 +74,13 @@ onmessage = function(event) {
       var sy = event.data.sy;
       var sw = event.data.sw;
       var sh = event.data.sh;
       promiseThrows(createImageBitmap(source, sx, sy, sw, sh), event.data.msg);
     } else {
       promiseThrows(createImageBitmap(source), event.data.msg);
     }
     doneTask();
+  } else if (event.data.type == "testBug1239300") {
+    var promise = testBug1239300();
+    promise.then(doneTask, doneTask);
   }
 };
\ No newline at end of file
--- a/dom/canvas/test/mochitest.ini
+++ b/dom/canvas/test/mochitest.ini
@@ -19,16 +19,17 @@ support-files =
   image_red_crossorigin_credentials.png^headers^
   image_redtransparent.png
   image_rgrg-256x256.png
   image_rrgg-256x256.png
   image_transparent.png
   image_transparent50.png
   image_yellow.png
   image_yellow75.png
+  imagebitmap_bug1239300.js
   imagebitmap_on_worker.js
   imagebitmap_structuredclone.js
   imagebitmap_structuredclone_iframe.html
   offscreencanvas.js
   offscreencanvas_mask.svg
   offscreencanvas_neuter.js
   offscreencanvas_serviceworker_inner.html
 
@@ -242,23 +243,31 @@ skip-if = os == "android" || appname == 
 support-files = captureStream_common.js
 [test_drawImageIncomplete.html]
 [test_drawImage_document_domain.html]
 [test_drawImage_edge_cases.html]
 [test_drawWindow.html]
 support-files = file_drawWindow_source.html file_drawWindow_common.js
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk')
 [test_imagebitmap.html]
+tags = imagebitmap
 [test_imagebitmap_close.html]
+tags = imagebitmap
 [test_imagebitmap_cropping.html]
+tags = imagebitmap
 [test_imagebitmap_on_worker.html]
+tags = imagebitmap
 [test_imagebitmap_structuredclone.html]
+tags = imagebitmap
 [test_imagebitmap_structuredclone_iframe.html]
+tags = imagebitmap
 [test_imagebitmap_structuredclone_window.html]
+tags = imagebitmap
 [test_imagebitmap_transfer.html]
+tags = imagebitmap
 [test_ImageData_ctor.html]
 [test_isPointInStroke.html]
 [test_mozDashOffset.html]
 [test_mozGetAsFile.html]
 [test_strokeText_throw.html]
 skip-if = (e10s && debug && os == 'win')
 [test_toBlob.html]
 skip-if = (e10s && debug && os == 'win') # bug 1236257
--- a/dom/canvas/test/test_imagebitmap.html
+++ b/dom/canvas/test/test_imagebitmap.html
@@ -6,16 +6,17 @@
 <body>
 
 <img src="image_anim-gr.gif" id="image" class="resource">
 <video width="320" height="240" src="http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg&cors=anonymous" id="video" crossOrigin="anonymous" autoplay></video>
 
 <canvas id="c1" class="output" width="128" height="128"></canvas>
 <canvas id="c2" width="128" height="128"></canvas>
 
+<script src="imagebitmap_bug1239300.js"></script>
 <script type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 /**
  * [isPixel description]
  * @param  {[type]}  ctx : canvas context
  * @param  {[type]}  x   : pixel x coordinate
@@ -328,15 +329,16 @@ function runTests() {
   ctx = canvas.getContext('2d');
   ctx2 = document.getElementById('c2').getContext('2d');
 
   testDraw()
     .then(testCreatePattern)
     .then(testSources)
     .then(testExceptions)
     .then(testSecurityErrors)
+    .then(testBug1239300)
     .then(SimpleTest.finish, function(ev) { failed(ev); SimpleTest.finish(); });
 }
 
 addLoadEvent(runTests);
 
 </script>
 </body>
--- a/dom/canvas/test/test_imagebitmap_on_worker.html
+++ b/dom/canvas/test/test_imagebitmap_on_worker.html
@@ -125,15 +125,18 @@ function runTests() {
       WORKER_TASKS.tasks.push(new Task("testException", 0, 0, "createImageBitmap should reject promise with non-image blob", xhr.response));
 
       // start to dispatch tasks to worker
       WORKER_TASKS.dispatch();
     }
     xhr.send();
   }
   getNonImageFile("imagebitmap_on_worker.js");
+
+  // task: test bug : bug 1239300
+  WORKER_TASKS.tasks.push(new Task("testBug1239300"));
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(runTests);
 
 </script>
 </body>
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -537,16 +537,22 @@ Promise::MaybeReject(JSContext* aCx,
   MaybeRejectInternal(aCx, aValue);
 }
 
 void
 Promise::MaybeReject(const RefPtr<MediaStreamError>& aArg) {
   MaybeSomething(aArg, &Promise::MaybeReject);
 }
 
+void
+Promise::MaybeRejectWithNull()
+{
+  MaybeSomething(JS::NullHandleValue, &Promise::MaybeReject);
+}
+
 bool
 Promise::PerformMicroTaskCheckpoint()
 {
   CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
   std::queue<nsCOMPtr<nsIRunnable>>& microtaskQueue =
     runtime->GetPromiseMicroTaskQueue();
 
   if (microtaskQueue.empty()) {
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -128,16 +128,18 @@ public:
 
   inline void MaybeReject(ErrorResult& aArg) {
     MOZ_ASSERT(aArg.Failed());
     MaybeSomething(aArg, &Promise::MaybeReject);
   }
 
   void MaybeReject(const RefPtr<MediaStreamError>& aArg);
 
+  void MaybeRejectWithNull();
+
   // DO NOT USE MaybeRejectBrokenly with in new code.  Promises should be
   // rejected with Error instances.
   // Note: MaybeRejectBrokenly is a template so we can use it with DOMError
   // without instantiating the DOMError specialization of MaybeSomething in
   // every translation unit that includes this header, because that would
   // require use to include DOMError.h either here or in all those translation
   // units.
   template<typename T>