<!DOCTYPE HTML>
<html>
<head>
<title>WebGL in OffscreenCanvas</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/WindowSnapshot.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<script type="text/js-worker">
function ok(expect, msg) {
  postMessage({"type": "status", status: !!expect, msg: msg});
}

onmessage = function(event) {
  var bitmap = event.data.bitmap;
  ok(!!bitmap, "Get the ImageBitmap from the main script.");

  var offscreenCanvas = new OffscreenCanvas(64, 64);
  var ctx = offscreenCanvas.getContext('bitmaprenderer');
  ok(!!ctx, "Get bitmaprenderer context on worker.");

  ctx.transferFromImageBitmap(bitmap);
  var resultBitmap = offscreenCanvas.transferToImageBitmap();
  postMessage({"type": "bitmap", bitmap: resultBitmap}, [resultBitmap]);
}
</script>
<script>

SimpleTest.waitForExplicitFinish();

function createCanvas(width, height) {
  var htmlCanvas = document.createElement('canvas');
  htmlCanvas.width = width;
  htmlCanvas.height = height;
  document.body.appendChild(htmlCanvas);
  return htmlCanvas;
}

function runTest(canvasWidth, canvasHeight, nextTest) {
  var canvas1 = createCanvas(canvasWidth, canvasHeight);
  var ctx = canvas1.getContext("2d");
  ctx.fillStyle = "#00FF00";
  ctx.fillRect(0, 0, canvasWidth, canvasHeight);

  var canvasRef = createCanvas(90, 90);
  var ctx = canvasRef.getContext("2d");
  // Clear with black transparent first
  ctx.fillStyle = "rgba(0, 0, 0, 0)";
  ctx.fillRect(0, 0, 90, 90);

  ctx.fillStyle = "#00FF00";
  ctx.fillRect(0, 0, canvasWidth, canvasHeight);

  createImageBitmap(canvas1).then(async function(bmp) {
    document.body.removeChild(canvas1);

    var canvas2 = createCanvas(90, 90);
    var ctx2 = canvas2.getContext("bitmaprenderer");
    ctx2.transferFromImageBitmap(bmp);

    ok(canvasRef.toDataURL() == canvas2.toDataURL(), "toDataURL should return same result.");

    // Exam render result
    canvasRef.style.display = "none";
    canvas2.style.display = "block";
    var snapshot = await snapshotWindow(window);

    canvasRef.style.display = "block";
    canvas2.style.display = "none";
    var snapshotRef = await snapshotWindow(window);

    // bitmaprenderers use an ImageLayer whereas a normal 2d canvas uses a canvas layer. This
    // can result in some anti-aliasing differences on the edge. We consider slight AA differences
    // to be reasonable when using different codepaths so fuzz a little bit.
    var fuzz = { numDifferentPixels:  0,
                 maxDifference: 0 };
    if (SpecialPowers.Services.appinfo.widgetToolkit == "android") {
      fuzz.maxDifference = 2;
      fuzz.numDifferentPixels = 131;
    }
    var results = compareSnapshots(snapshot, snapshotRef, true, fuzz);
    ok(results[0], "Screenshots should be the same");

    document.body.removeChild(canvasRef);
    document.body.removeChild(canvas2);

    nextTest();
  });
}

function scaleTest() {
  var canvas1 = createCanvas(64, 64);
  var ctx = canvas1.getContext("2d");
  ctx.fillStyle = "#00FF00";
  ctx.fillRect(0, 0, 64, 64);

  var canvas2 = createCanvas(64, 64);
  var ctx2 = canvas2.getContext("2d");
  ctx2.fillStyle = "#00FF00";
  ctx2.fillRect(0, 0, 64, 64);

  var p1 = createImageBitmap(canvas1);
  var p2 = createImageBitmap(canvas2);
  Promise.all([p1, p2]).then(async function(bitmaps) {
    document.body.removeChild(canvas1);
    document.body.removeChild(canvas2);

    // Create a large canvas then shrink.
    var canvas3 = createCanvas(128, 128);
    var ctx3 = canvas3.getContext("bitmaprenderer");
    ctx3.transferFromImageBitmap(bitmaps[0]);
    var snapshotLargeRef = await snapshotWindow(window);

    canvas3.width = 32;
    canvas3.height = 32;
    var snapshotSmall = await snapshotWindow(window);
    document.body.removeChild(canvas3);

    // Create a small canvas then grow.
    var canvas4 = createCanvas(32, 32);
    var ctx4 = canvas4.getContext("bitmaprenderer");
    ctx4.transferFromImageBitmap(bitmaps[1]);
    var snapshotSmallRef = await snapshotWindow(window);

    canvas4.width = 128;
    canvas4.height = 128;
    var snapshotLarge = await snapshotWindow(window);
    document.body.removeChild(canvas4);

    var resultsLarge = compareSnapshots(snapshotLarge, snapshotLargeRef, true);
    ok(resultsLarge[0], "Screenshots should be the same");

    var resultsSmall = compareSnapshots(snapshotSmall, snapshotSmallRef, true);
    ok(resultsSmall[0], "Screenshots should be the same");
    runTestOnWorker();
  });
}

function runTestOnWorker() {
  var canvas1 = createCanvas(64, 64);
  var ctx = canvas1.getContext("2d");
  ctx.fillStyle = "#00FF00";
  ctx.fillRect(0, 0, 64, 64);

  var blob = new Blob(Array.prototype.map.call(document.querySelectorAll("script[type=\"text\/js-worker\"]"), function (oScript) { return oScript.textContent; }),{type: "text/javascript"});

  var worker = new Worker(window.URL.createObjectURL(blob));

  createImageBitmap(canvas1).then(function(bmp) {
    worker.postMessage({bitmap: bmp}, [bmp]);
    worker.onmessage = function(event) {
      if (event.data.type == "status") {
        ok(event.data.status, event.data.msg);
      } else if (event.data.type == "bitmap") {
        var canvas2 = createCanvas(64, 64);
        var ctx2 = canvas2.getContext('bitmaprenderer');
        ctx2.transferFromImageBitmap(event.data.bitmap);
        ok(canvas1.toDataURL() == canvas2.toDataURL(), 'toDataURL should be the same');
        SimpleTest.finish();
      }
    }
  });
}

SpecialPowers.pushPrefEnv({'set': [
  ['gfx.offscreencanvas.enabled', true],
]}, runTest.bind(this, 64, 64, runTest.bind(this, 128, 128, scaleTest)));

</script>
</body>
</html>
