Bug 1141979 - part15 - mochitest - basic operations; r=jrmuizel draft
authorKaku Kuo <tkuo@mozilla.com>
Wed, 18 Nov 2015 15:43:46 +0800
changeset 373854 f6d2323fc722d73b9dbed25cf4992e3978b2cc0a
parent 373853 8e2c969b224f0c38828ea943a5ae0879545a450c
child 373855 e16b5ba233e2aa9b029f8896fae2185c436c641d
push id19853
push usertkuo@mozilla.com
push dateWed, 01 Jun 2016 09:17:41 +0000
reviewersjrmuizel
bugs1141979
milestone49.0a1
Bug 1141979 - part15 - mochitest - basic operations; r=jrmuizel MozReview-Commit-ID: 9AXLGuZ5I2t
dom/canvas/test/imagebitmap_extensions.html
dom/canvas/test/imagebitmap_extensions.js
dom/canvas/test/imagebitmap_extensions_on_worker.js
dom/canvas/test/imagebitmap_extensions_prepareSources.js
dom/canvas/test/mochitest.ini
dom/canvas/test/test_imagebitmap_extensions.html
dom/canvas/test/test_imagebitmap_extensions_on_worker.html
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/imagebitmap_extensions.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<head>
+  <title>Test ImageBitmap Extensions (Bug 1141979)</title>
+  <meta charset="utf-8">
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+<script src="imagebitmap_extensions_prepareSources.js"></script>
+<script src="imagebitmap_extensions.js"></script>
+<script type="text/javascript">
+
+runTests();
+
+function ok(expect, msg) {
+  window.parent.postMessage({"type": "status", status: !!expect, msg: msg}, "*");
+}
+
+function runTests() {
+
+  prepareSources().
+    then(testExceptions).
+    then( function() { return Promise.all([testAccessing_randomTest("Video", gVideo, 20), // video might use slightly different frames
+                                           testAccessing_randomTest("Image", gImage, 0),
+                                           testAccessing_randomTest("Canvas", gCanvas, 0),
+                                           testAccessing_randomTest("Ctx", gCtx, 0),
+                                           testAccessing_randomTest("ImageData", gImageData, 0),
+                                           testAccessing_randomTest("ImageBitmap", gImageBitmap, 0),
+                                           testAccessing_randomTest("PNG", gPNGBlob, 0),
+                                           testAccessing_randomTest("JPEG", gJPEGBlob, 10) // JPEG loses information
+                                          ]); }).
+    then( function() { return Promise.all([testCreateFromArrayBffer_randomTest("Video", gVideo, 20), // video might use slightly different frames
+                                           testCreateFromArrayBffer_randomTest("Image", gImage, 0),
+                                           testCreateFromArrayBffer_randomTest("Canvas", gCanvas, 0),
+                                           testCreateFromArrayBffer_randomTest("Ctx", gCtx, 0),
+                                           testCreateFromArrayBffer_randomTest("ImageData", gImageData, 0),
+                                           testCreateFromArrayBffer_randomTest("ImageBitmap", gImageBitmap, 0),
+                                           testCreateFromArrayBffer_randomTest("PNG", gPNGBlob, 0),
+                                           testCreateFromArrayBffer_randomTest("JPEG", gJPEGBlob, 10) // JPEG loses information
+                                          ]); }).
+    then(function() {window.parent.postMessage({"type": "finish"}, "*");}, function(ev) { failed(ev); window.parent.postMessage({"type": "finish"}, "*"); });
+}
+
+</script>
+</body>
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/imagebitmap_extensions.js
@@ -0,0 +1,171 @@
+function failed(ex) {
+  ok(false, "Promise failure: " + ex);
+}
+
+function isPixel(sourceType, bitmapFormat, imageData, bitmapImageData, x, y, tolerance) {
+  if (imageData.width != bitmapImageData.width ||
+    imageData.height != bitmapImageData.height) {
+    ok(false, "Wrong dimension");
+  }
+
+  var index = 4 * (y * imageData.width + x);
+
+  var pr = imageData.data[index+0],
+      pg = imageData.data[index+1],
+      pb = imageData.data[index+2],
+      pa = imageData.data[index+3];
+
+  if (bitmapFormat == "RGBA32" || bitmapFormat == "RGBX32") {
+    var bpr = bitmapImageData.data[index+0],
+        bpg = bitmapImageData.data[index+1],
+        bpb = bitmapImageData.data[index+2],
+        bpa = bitmapImageData.data[index+3];
+  }
+  else if (bitmapFormat == "BGRA32" || bitmapFormat == "BGRX32") {
+    var bpb = bitmapImageData.data[index+0],
+        bpg = bitmapImageData.data[index+1],
+        bpr = bitmapImageData.data[index+2],
+        bpa = bitmapImageData.data[index+3];
+  }
+  else {
+    // format might be one of the followings: "R5G6B5", "A8", "YUV", ""
+    ok(false, "Not supported ImageFormat: " + bitmapFormat);
+  }
+
+  ok(pr - tolerance <= bpr && bpr <= pr + tolerance &&
+     pg - tolerance <= bpg && bpg <= pg + tolerance &&
+     pb - tolerance <= bpb && bpb <= pb + tolerance &&
+     pa - tolerance <= bpa && bpa <= pa + tolerance,
+     "pixel[" + x + "][" + y + "]: " + sourceType + " is "+pr+","+pg+","+pb+","+pa+"; ImageBitmap is "+ bpr + "," + bpg + "," + bpb + "," + bpa);
+}
+
+function promiseThrows(p, name) {
+  var didThrow;
+  return p.then(function() { didThrow = false; },
+                function() { didThrow = true; })
+          .then(function() { ok(didThrow, name); });
+}
+
+function testExceptions() {
+
+  function callMappedDataLengthWithUnsupportedFormat(format) {
+    return new Promise(function(resolve, reject) {
+      var p = createImageBitmap(gImageData);
+      p.then(
+        function(bitmap) {
+          try {
+            bitmap.mappedDataLength(format);
+            resolve();
+          }
+          catch (e) {
+            reject(e);
+          }
+        },
+        function() { resolve(); });
+    });
+  }
+
+  return Promise.all([
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("RGB24"), "[Exception] RGB24 is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("BGR24"), "[Exception] BGR24 is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("GRAY8"), "[Exception] GRAY8 is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("YUV444P"), "[Exception] GRYUV444PAY is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("YUV422P"), "[Exception] YUV422P is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("YUV420SP_NV12"), "[Exception] YUV420SP_NV12 is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("YUV420SP_NV21"), "[Exception] YUV420SP_NV21 is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("HSV"), "[Exception] HSV is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("Lab"), "[Exception] Lab is not supported yet."),
+    promiseThrows(callMappedDataLengthWithUnsupportedFormat("DEPTH"), "[Exception] DEPTH is not supported yet.")
+  ]);
+}
+
+// Create an ImageBitmap, _bitmap_, from the _source_.
+// Read the underlying data of _bitmap_ into _bitmapBuffer_.
+// Compare the _bitmapBuffer_ with gGroundTruthImageData.
+function testAccessing_randomTest(sourceType, source, duration) {
+  return new Promise(function(resolve, reject) {
+    var p  = createImageBitmap(source);
+    p.then(
+      function(bitmap) {
+        bitmapFormat = "RGBA32";
+        var bitmapBufferLength = bitmap.mappedDataLength(bitmapFormat);
+
+        var bitmapBuffer = new ArrayBuffer(bitmapBufferLength);
+        var bitmapBufferView = new Uint8ClampedArray(bitmapBuffer, 0, bitmapBufferLength);
+        var promise = bitmap.mapDataInto(bitmapFormat, bitmapBuffer, 0);
+        promise.then(
+          function(bitmapPixelLayout) {
+            // Prepare.
+            bitmapImageData = new ImageData(bitmapBufferView, bitmap.width, bitmap.height);
+
+            // Test.
+            for (var t = 0; t < 50; ++t) {
+              var randomX = Math.floor(Math.random() * 240);
+              var randomY = Math.floor(Math.random() * 175);
+              isPixel(sourceType, "RGBA32", gGroundTruthImageData, bitmapImageData, randomX, randomY, duration);
+            }
+
+            resolve();
+          },
+          function(ev) { failed(ev); reject(); });
+      },
+      function(ev) { failed(ev); reject(); });
+  });
+}
+
+// Create an ImageBitmap, _bitmap_, from the _source_.
+// Read the underlying data of _bitmap_ into _bitmapBuffer_.
+// Create another ImageBitmap, _bitmap2_, from _bitmapBuffer_.
+// Read the underlying data of _bitmap2_ into _bitmapBuffer2_.
+// Compare the _bitmapBuffer2_ with gGroundTruthImageData.
+function testCreateFromArrayBffer_randomTest(sourceType, source, duration) {
+  return new Promise(function(resolve, reject) {
+    var p  = createImageBitmap(source);
+    p.then(
+      function(bitmap) {
+        bitmapFormat = "RGBA32";
+        var bitmapBufferLength = bitmap.mappedDataLength(bitmapFormat);
+
+        var bitmapBuffer = new ArrayBuffer(bitmapBufferLength);
+        var bitmapBufferView = new Uint8ClampedArray(bitmapBuffer, 0, bitmapBufferLength);
+        var promiseMapDataInto = bitmap.mapDataInto(bitmapFormat, bitmapBuffer, 0);
+        promiseMapDataInto.then(
+          function(bitmapPixelLayout) {
+            // Create a new ImageBitmap from an ArrayBuffer.
+            var p2 = createImageBitmap(bitmapBufferView,
+                                       0,
+                                       bitmapBufferLength,
+                                       bitmapFormat,
+                                       bitmapPixelLayout);
+
+            p2.then(
+              function(bitmap2) {
+                bitmapFormat2 = "RGBA32";
+                var bitmapBufferLength2 = bitmap2.mappedDataLength(bitmapFormat2);
+
+                var bitmapBuffer2 = new ArrayBuffer(bitmapBufferLength2);
+                var bitmapBufferView2 = new Uint8ClampedArray(bitmapBuffer2, 0, bitmapBufferLength2);
+                var promise2 = bitmap2.mapDataInto(bitmapFormat2, bitmapBuffer2, 0);
+                promise2.then(
+                  function(bitmapPixelLayout2) {
+                    // Prepare.
+                    var bitmapImageData2 = new ImageData(bitmapBufferView2, bitmap2.width, bitmap2.height);
+
+                    // Test.
+                    for (var t = 0; t < 50; ++t) {
+                      var randomX = Math.floor(Math.random() * 240);
+                      var randomY = Math.floor(Math.random() * 175);
+                      isPixel(sourceType, "RGBA32", gGroundTruthImageData, bitmapImageData2, randomX, randomY, duration);
+                    }
+
+                    resolve();
+                  },
+                  function(ev) { failed(ev); reject(); });
+              },
+              function(ev) { console.log("p2 rejected!"); failed(ev); reject(); });
+          },
+          function(ev) { console.log("promiseMapDataInto rejected!"); failed(ev); reject(); });
+      },
+      function(ev) { failed(ev); reject(); });
+  });
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/imagebitmap_extensions_on_worker.js
@@ -0,0 +1,44 @@
+importScripts("imagebitmap_extensions.js");
+
+var gGroundTruthImageData;
+var gImageData;
+var gImageBitmap;
+var gPNGBlob;
+var gJPEGBlob;
+
+onmessage = function(event) {
+  if (event.data.type == "setSources") {
+    gGroundTruthImageData = event.data.groundTruthImageData;
+    gImageData = event.data.imageData;
+    gImageBitmap = event.data.imageBitmap;
+    gPNGBlob = event.data.pngBlob;
+    gJPEGBlob = event.data.jpegBlob;
+
+    ok(!!gGroundTruthImageData, "Get gGroundTruthImageData!");
+    ok(!!gImageData, "Get gImageData!");
+    ok(!!gImageBitmap, "Get gImageBitmap!");
+    ok(!!gPNGBlob, "Get gPNGBlob!");
+    ok(!!gJPEGBlob, "Get gJPEGBlob!");
+
+    runTests();
+  }
+};
+
+function ok(expect, msg) {
+  postMessage({"type": "status", status: !!expect, msg: msg});
+}
+
+function runTests() {
+  testExceptions().
+  then( function() { return Promise.all([testAccessing_randomTest("ImageData", gImageData, 0),
+                                         testAccessing_randomTest("ImageBitmap", gImageBitmap, 0),
+                                         testAccessing_randomTest("PNG", gPNGBlob, 0),
+                                         testAccessing_randomTest("JPEG", gJPEGBlob, 10) // JPEG loses information
+                                        ]); }).
+  then( function() { return Promise.all([testCreateFromArrayBffer_randomTest("ImageData", gImageData, 0),
+                                         testCreateFromArrayBffer_randomTest("ImageBitmap", gImageBitmap, 0),
+                                         testCreateFromArrayBffer_randomTest("PNG", gPNGBlob, 0),
+                                         testCreateFromArrayBffer_randomTest("JPEG", gJPEGBlob, 10) // JPEG loses information
+                                        ]); }).
+  then(function() {postMessage({"type": "finish"});}, function(ev) { failed(ev); postMessage({"type": "finish"}); });
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/imagebitmap_extensions_prepareSources.js
@@ -0,0 +1,94 @@
+var gImage;
+var gVideo;
+var gCanvas;
+var gCtx;
+var gImageData;
+var gImageBitmap;
+var gPNGBlob;
+var gJPEGBlob;
+
+var gGroundTruthImageData;
+
+function prepareSources() {
+  gVideo = document.createElement("video");
+  gVideo.src = "http://example.com/tests/dom/canvas/test/crossorigin/video.sjs?name=tests/dom/media/test/320x240.ogv&type=video/ogg&cors=anonymous";
+  gVideo.crossOrigin = "anonymous";
+  gVideo.autoplay = "true"
+
+
+  gCanvas = document.createElement("canvas");
+  gCtx = gCanvas.getContext("2d");
+
+  var resolver;
+  var promise = new Promise(function(resolve, reject) {
+    resolver = resolve;
+  });
+
+  // Prepare video.
+  gVideo.onloadeddata = function() {
+    ok(gVideo, "[Prepare Sources] gVideo is ok.");
+
+    // Prepare canvas.
+    gCanvas.width = gVideo.videoWidth;
+    gCanvas.height = gVideo.videoHeight;
+    gCtx.drawImage(gVideo, 0, 0);
+    ok(gCanvas, "[Prepare Sources] gCanvas is ok.");
+    ok(gCtx, "[Prepare Sources] gCtx is ok.");
+
+    // Prepare gGroundTruthImageData.
+    gGroundTruthImageData = gCtx.getImageData(0, 0, gCanvas.width, gCanvas.height);
+    ok(gGroundTruthImageData, "[Prepare Sources] gGroundTruthImageData is ok.");
+
+    // Prepare image.
+    gImage = document.createElement("img");
+    gImage.src = gCanvas.toDataURL();
+    var resolverImage;
+    var promiseImage = new Promise(function(resolve, reject) {
+      resolverImage = resolve;
+    });
+    gImage.onload = function() {
+      resolverImage(true);
+    }
+
+    // Prepare ImageData.
+    gImageData = gCtx.getImageData(0, 0, gCanvas.width, gCanvas.height);
+    ok(gImageData, "[Prepare Sources] gImageData is ok.");
+
+    // Prepapre PNG Blob.
+    var promisePNGBlob = new Promise(function(resolve, reject) {
+      gCanvas.toBlob(function(blob) {
+        gPNGBlob = blob;
+        ok(gPNGBlob, "[Prepare Sources] gPNGBlob is ok.");
+        resolve(true);
+      });
+    });
+
+    // Prepare JPEG Blob.
+    var promiseJPEGBlob = new Promise(function(resolve, reject) {
+      gCanvas.toBlob(function(blob) {
+        gJPEGBlob = blob;
+        ok(gJPEGBlob, "[Prepare Sources] gJPEGBlob is ok.");
+        resolve(true);
+      }, "image/jpeg", 1.00);
+    });
+
+    // Prepare ImageBitmap.
+    var promiseImageBitmap = new Promise(function(resolve, reject) {
+      var p = createImageBitmap(gCanvas);
+      p.then(function(bitmap) {
+        gImageBitmap = bitmap;
+        ok(gImageBitmap, "[Prepare Sources] gImageBitmap is ok.");
+        resolve(true);
+      });
+    });
+
+    resolver(Promise.all([
+      promiseImage,
+      promisePNGBlob,
+      promiseJPEGBlob,
+      promiseImageBitmap
+    ]))
+  }
+
+  return promise;
+}
\ No newline at end of file
--- a/dom/canvas/test/mochitest.ini
+++ b/dom/canvas/test/mochitest.ini
@@ -21,16 +21,20 @@ support-files =
   image_rgrg-256x256.png
   image_rrgg-256x256.png
   image_transparent.png
   image_transparent50.png
   image_yellow.png
   image_yellow75.png
   imagebitmap_bug1239300.js
   imagebitmap_bug1239752.js
+  imagebitmap_extensions.html
+  imagebitmap_extensions.js
+  imagebitmap_extensions_on_worker.js
+  imagebitmap_extensions_prepareSources.js
   imagebitmap_on_worker.js
   imagebitmap_structuredclone.js
   imagebitmap_structuredclone_iframe.html
   imagebitmap_structuredclone_utils.js
   offscreencanvas.js
   offscreencanvas_mask.svg
   offscreencanvas_neuter.js
   offscreencanvas_serviceworker_inner.html
@@ -225,16 +229,20 @@ support-files = captureStream_common.js
 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_extensions.html]
+tags = imagebitmap
+[test_imagebitmap_extensions_on_worker.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
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/test_imagebitmap_extensions.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<heand>
+  <title>Test ImageBitmap Extensions (Bug 1141979)</title>
+  <meta charset="utf-8">
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+  <div id="content"><div>
+  <script type="text/javascript">
+    SimpleTest.waitForExplicitFinish();
+
+    // The createImageBitmap() method is part of Window whose
+    // prototype was created before the preference is set. So I create another
+    // iframe with the right preference setting so that the
+    // createImageBitmap() will be visible.
+    SpecialPowers.pushPrefEnv({'set': [
+      ['canvas.imagebitmap_extensions.enabled', true]
+    ]}, function() {
+      var div = document.getElementById("content");
+      ok(div, "Parent exists");
+
+      var ifr = document.createElement("iframe");
+      ifr.setAttribute('src', "imagebitmap_extensions.html");
+      div.appendChild(ifr);
+    });
+
+    window.onmessage = function(event) {
+      if (event.data.type == "status") {
+        ok(event.data.status, event.data.msg);
+      } else if (event.data.type == "finish") {
+        SimpleTest.finish();
+      }
+    }
+  </script>
+</body>
new file mode 100644
--- /dev/null
+++ b/dom/canvas/test/test_imagebitmap_extensions_on_worker.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<heand>
+  <title>Test ImageBitmap Extensions On Worker (Bug 1141979)</title>
+  <meta charset="utf-8">
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+  <div id="content"><div>
+  <script src="imagebitmap_extensions_prepareSources.js"></script>
+  <script type="text/javascript">
+
+    var worker;
+
+    SimpleTest.waitForExplicitFinish();
+    SpecialPowers.pushPrefEnv({'set': [
+      ['canvas.imagebitmap_extensions.enabled', true]
+    ]}, function() {
+          worker = new Worker("imagebitmap_extensions_on_worker.js");
+          worker.onmessage = function(event) {
+            if (event.data.type == "status") {
+              ok(event.data.status, event.data.msg);
+            } else if (event.data.type == "finish") {
+              SimpleTest.finish();
+            }
+          };
+
+          ok(!!worker, "Worker created successfully.");
+          prepareSources().then(function() {
+            worker.postMessage({"type": "setSources",
+                                "groundTruthImageData": gGroundTruthImageData,
+                                "imageData": gImageData,
+                                "imageBitmap": gImageBitmap,
+                                "pngBlob": gPNGBlob,
+                                "jpegBlob": gJPEGBlob});
+          });
+    });
+  </script>
+</body>