<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />

<title>Canvas2D test: CaptureStream()</title>

<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="captureStream_common.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<body>
<script>
SimpleTest.waitForExplicitFinish();
SimpleTest.requestFlakyTimeout("Ensuring nothing happens until timing out with good margin");

// CaptureStreamTestHelper holding utility test functions.
const h = new CaptureStreamTestHelper2D();
// Canvas element captured by streams.
const c = h.createAndAppendElement('canvas', 'c');
// Video element with captureStream stream in automatic mode.
const vauto = h.createAndAppendElement('video', 'vauto');
// Video element with captureStream stream in manual (fps 0) mode.
const vmanual = h.createAndAppendElement('video', 'vmanual');
// Video element with captureStream stream with fixed frame rate.
const vrate = h.createAndAppendElement('video', 'vrate');

async function checkDrawColorInitialRed() {
  info("Checking that all video elements become red when initiated just after the first drawColor(red).");

  h.drawColor(c, h.red);

  vauto.srcObject = c.captureStream();
  vmanual.srcObject = c.captureStream(0);
  vrate.srcObject = c.captureStream(10);

  ok(h.isPixel(h.getPixel(vauto), h.blackTransparent, 0),
     "vauto should not be drawn to before stable state");
  ok(h.isPixel(h.getPixel(vrate), h.blackTransparent, 0),
     "vrate should not be drawn to before stable state");
  ok(h.isPixel(h.getPixel(vmanual), h.blackTransparent, 0),
     "vmanual should not be drawn to before stable state");

  await h.pixelMustBecome(vauto, h.red, {
    infoString: "should become red automatically",
  });
  await h.pixelMustBecome(vrate, h.red, {
    infoString: "should become red automatically",
  });
  await h.pixelMustBecome(vmanual, h.red, {
    infoString: "should become red when we get to stable state (first frame)",
  });
}

async function checkDrawColorGreen() {
  info("Checking that drawing green propagates properly to video elements.");

  const drawing = h.startDrawing(() => h.drawColor(c, h.green));

  try {
    await h.pixelMustBecome(vauto, h.green, {
      infoString: "should become green automatically",
    });
    await h.pixelMustBecome(vrate, h.green, {
      infoString: "should become green automatically",
    });
    await h.pixelMustBecome(vmanual, h.red, {
      infoString: "should still be red",
    });
    h.requestFrame(vmanual);
    await h.pixelMustBecome(vmanual, h.green, {
      infoString: "should become green after requstFrame()",
    });
  }
  catch(err) {
    ok(false, "checkDrawColorGreen failed: ", err);
  }
  drawing.stop();
}

async function checkRequestFrameOrderGuarantee() {
  info("Checking that requestFrame() immediately after a drawColor() " +
       "call results in the expected frame seen in the stream.");

  await h.pixelMustBecome(vmanual, h.green, {
    infoString: "should still be green",
  });
  h.drawColor(c, h.red);   // 1. Draw canvas red
  h.requestFrame(vmanual); // 2. Immediately request a frame
  await h.pixelMustBecome(vmanual, h.red, {
    infoString: "should become red after call order test",
  });
}

async function checkDrawImageNotCleanRed() {
  info("Checking that drawImage with not origin-clean image renders streams useless.");
  const ctx = c.getContext('2d');
  const notCleanRed = new Image();

  await new Promise((resolve, reject) => {
    notCleanRed.onload = resolve;
    notCleanRed.onerror = () => reject(new Error("Failed to load tainted image."));
    notCleanRed.src = "http://example.com/tests/dom/canvas/test/image_red_crossorigin_credentials.png";
    document.body.appendChild(notCleanRed);
  });
  const drawing = h.startDrawing(
    () => ctx.drawImage(notCleanRed, 0, 0, c.width, c.height));
  h.testNotClean(c);
  try {
    await h.pixelMustNotBecome(vauto, h.red, {
      timeout: 1000,
      infoString: "should not become red",
    });
    ok(h.isPixelNot(h.getPixel(vrate), h.red, 250),
       "should not have become red");
    await h.pixelMustBecome(vmanual, h.green, {
      infoString: "should still be green",
    });
    h.requestFrame(vmanual);
    await h.pixelMustNotBecome(vmanual, h.red, {
      timeout: 1000,
      infoString: "should not become red",
    });
  } catch(err) {
    ok(false, "checkDrawImageNotCleanRed failed: ", err);
  }
  drawing.stop();
}

async function checkEndedOnStop() {
  const promises = [vauto, vmanual, vrate].map(elem => {
    elem.srcObject.getTracks()[0].stop();
    return new Promise(resolve =>
      elem.addEventListener("ended", function endedListener(event) {
        ok(true, "Element " + elem.id + " ended.");
        resolve();
        elem.removeEventListener("ended", endedListener);
      }));
  });
  await Promise.all(promises);
}

function finish() {
  ok(true, 'Test complete.');
  SimpleTest.finish();
}

(async () => {
  await checkDrawColorInitialRed();
  await checkDrawColorGreen();
  await checkRequestFrameOrderGuarantee();
  await checkDrawColorGreen(); // Restore video elements to green.
  await checkDrawImageNotCleanRed();
  await checkEndedOnStop();
  finish();
})();
</script>

