<!DOCTYPE html>
<meta charset="utf-8">
<title>Test Background Video Suspends</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="manifest.js"></script>
<script src="background_video.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
"use strict";

var manager = new MediaTestManager;

function testSameContent(video1, video2) {
  if (video1.videoWidth != video2.videoWidth ||
      video1.videoHeight != video2.videoHeight) {
    ok(false, `${video1.token} video1 and video2 have different dimensions.`);
    return;
  }

  let w = video1.videoWidth;
  let h = video1.videoHeight;
  let c1 = document.createElement('canvas');
  let c2 = document.createElement('canvas');
  c1.width = w;
  c1.height = h;
  c2.width = w;
  c2.height = h;

  let gfx1 = c1.getContext('2d');
  let gfx2 = c2.getContext('2d');
  if (!gfx1 || !gfx2) {
    ok(false, "Unable to obtain context '2d' from canvas");
    return;
  }

  gfx1.drawImage(video1, 0, 0, w, h);
  gfx2.drawImage(video2, 0, 0, w, h);

  // Get content out.
  let contentWidth = 4;
  let contentHeight = 4;
  let imageData1 = gfx1.getImageData(0, 0, contentWidth, contentHeight);
  let imageData2 = gfx2.getImageData(0, 0, contentWidth, contentHeight);
  let pixels1 = imageData1.data;
  let pixels2 = imageData2.data;

  // Check that the content of two video are identical.
  for (let i = 0; i < contentWidth*contentHeight; i++) {
    let pixelCount = 4 * i;
    if (pixels1[pixelCount+0] != pixels2[pixelCount+0] ||
        pixels1[pixelCount+1] != pixels2[pixelCount+1] ||
        pixels1[pixelCount+2] != pixels2[pixelCount+2] ||
        pixels1[pixelCount+3] != pixels2[pixelCount+3]) {
      ok(false, `${video1.token} video1 and video2 have different content.`);
      return;
    }
  }

  ok(true, `${video1.token} video1 and video2 have identical content.`);
}

function waitUntilSeekToLastFrame(video) {
  Log(video.token, "Waiting for seeking to the last frame");
  function callSeekToNextFrame() {
    video.seekToNextFrame().then(
      () => {
        if (!video.seenEnded) {
          callSeekToNextFrame();
        }
      },
      () => {
        // When seek reaches the end, the promise is resolved before 'ended'
        // is fired. The resolver calls callSeekToNextFrame() to schedule
        // another seek and then the 'ended' handler calls finish() to shut
        // down the MediaDecoder which will reject the seek promise. So we don't
        // raise an error in this case.
        ok(video.seenEnded, "seekToNextFrame() failed.");
      }
    );
  }

  return new Promise(function(resolve, reject) {
    video.seenEnded = false;
    video.addEventListener("ended", () => {
      video.seenEnded = true;
      resolve();
    }, true);
    callSeekToNextFrame(video);
  });
}

startTest({
  desc: "Test resume an ended video shows the last frame.",
  prefs: [
    [ "media.test.video-suspend", true ],
    [ "media.suspend-background-video.enabled", true ],
    [ "media.suspend-background-video.delay-ms", 100 ],
    [ "media.dormant-on-pause-timeout-ms", -1],
    [ "media.decoder.skip-to-next-key-frame.enabled", false]
  ],
  tests: gDecodeSuspendTests,

  runTest: async (test, token) => {
    let v = appendVideoToDocWithoutLoad(token);
    let vMuted = appendVideoToDocWithoutLoad(token+"-muted");
    vMuted.muted = true;
    let vReference = appendVideoToDocWithoutLoad(token+"-ref");
    manager.started(token);

    /*
     * This test checks that, after a video element had finished its playback,
     * resuming video decoder should seek to the last frame.
     * This issue was found in bug 1358057.
     */
    await waitUntilVisible(v);
    await Promise.all([
      loadAndWaitUntilLoadedmetadata(v, test.name),
      loadAndWaitUntilLoadedmetadata(vMuted, test.name),
      loadAndWaitUntilLoadedmetadata(vReference, test.name, "auto"),
    ]);
    
    await waitUntilPlaying(v);
    await waitUntilPlaying(vMuted);
    await testVideoSuspendsWhenHidden(v);
    await testVideoSuspendsWhenHidden(vMuted);
    await Promise.all([
      waitUntilEnded(v),
      waitUntilEnded(vMuted),
      waitUntilSeekToLastFrame(vReference),
    ]);
    await testVideoOnlySeekCompletedWhenShown(v);
    await testVideoOnlySeekCompletedWhenShown(vMuted);
    testSameContent(v, vReference);
    testSameContent(vMuted, vReference);
    removeNodeAndSource(v);
    removeNodeAndSource(vMuted);
    removeNodeAndSource(vReference);
    manager.finished(token);
  }
});
</script>
