| Index: chrome/test/data/extensions/api_test/tab_capture/presentation.js
|
| diff --git a/chrome/test/data/extensions/api_test/tab_capture/presentation.js b/chrome/test/data/extensions/api_test/tab_capture/presentation.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f4e0cb5fe103f4129070fe940148439371f76111
|
| --- /dev/null
|
| +++ b/chrome/test/data/extensions/api_test/tab_capture/presentation.js
|
| @@ -0,0 +1,172 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Tests that offscreen presentations can be created and captured. The
|
| +// offscreen presentation page generates video test patterns that rotate
|
| +// cyclicly, and the rendering output of the tab is captured into a
|
| +// LocalMediaStream. This stream is then piped into a video element for
|
| +// playback, and a canvas is used to examine the frames of the video for
|
| +// expected content.
|
| +
|
| +// The offscreen page content for this test is provided as a data URI.
|
| +var offscreenPageUri = 'data:text/html;charset=UTF-8,' + encodeURIComponent('\n\
|
| +<html><body></body><script>\n\
|
| +// The test pattern cycles as a color fill of red, then green, then blue.\n\
|
| +var colors = [ [ 255, 0, 0 ], [ 0, 255, 0 ], [ 0, 0, 255 ] ];\n\
|
| +var curIdx = 0;\n\
|
| +\n\
|
| +function updateTestPattern() {\n\
|
| + if (!this.canvas) {\n\
|
| + this.canvas = document.createElement("canvas");\n\
|
| + this.canvas.width = 320;\n\
|
| + this.canvas.height = 200;\n\
|
| + this.canvas.style.position = "absolute";\n\
|
| + this.canvas.style.top = "0px";\n\
|
| + this.canvas.style.left = "0px";\n\
|
| + this.canvas.style.width = "100%";\n\
|
| + this.canvas.style.height = "100%";\n\
|
| + document.body.appendChild(this.canvas);\n\
|
| + }\n\
|
| + var context = this.canvas.getContext("2d");\n\
|
| + // Fill with solid color.\n\
|
| + context.fillStyle = "rgb(" + colors[curIdx] + ")";\n\
|
| + context.fillRect(0, 0, this.canvas.width, this.canvas.height);\n\
|
| + // Draw the circle that moves around the page.\n\
|
| + context.fillStyle = "rgb(" + colors[(curIdx + 1) % colors.length] + ")";\n\
|
| + context.beginPath();\n\
|
| + if (!this.frameNumber) {\n\
|
| + this.frameNumber = 1;\n\
|
| + } else {\n\
|
| + ++this.frameNumber;\n\
|
| + }\n\
|
| + var i = this.frameNumber % 200;\n\
|
| + var t = (this.frameNumber + 3000) * (0.01 + i / 8000.0);\n\
|
| + var x = (Math.sin(t) * 0.45 + 0.5) * this.canvas.width;\n\
|
| + var y = (Math.cos(t * 0.9) * 0.45 + 0.5) * this.canvas.height;\n\
|
| + context.arc(x, y, 16, 0, 2 * Math.PI, false);\n\
|
| + context.closePath();\n\
|
| + context.fill();\n\
|
| +}\n\
|
| +\n\
|
| +function renderTestPatternLoop() {\n\
|
| + requestAnimationFrame(renderTestPatternLoop);\n\
|
| + updateTestPattern();\n\
|
| +\n\
|
| + if (!this.stepTimeMillis) {\n\
|
| + this.stepTimeMillis = 100;\n\
|
| + }\n\
|
| + var now = new Date().getTime();\n\
|
| + if (!this.nextSteppingAt) {\n\
|
| + this.nextSteppingAt = now + this.stepTimeMillis;\n\
|
| + } else if (now >= this.nextSteppingAt) {\n\
|
| + ++curIdx;\n\
|
| + if (curIdx >= colors.length) { // Completed a cycle.\n\
|
| + curIdx = 0;\n\
|
| + // Increase the wait time between switching test patterns for\n\
|
| + // overloaded bots that are not capturing all the frames of video.\n\
|
| + this.stepTimeMillis *= 1.25;\n\
|
| + }\n\
|
| + this.nextSteppingAt = now + this.stepTimeMillis;\n\
|
| + }\n\
|
| +}\n\
|
| +\n\
|
| +renderTestPatternLoop();\n\
|
| +</script></body></html>');
|
| +
|
| +// Capture parameters.
|
| +var width = 64;
|
| +var height = 48;
|
| +var frameRate = 15;
|
| +
|
| +// The stream to playback in the video element.
|
| +var receiveStream = null;
|
| +
|
| +// waitForExpectedColors() removes elements from this array as each is observed.
|
| +// When it becomes empty, the test succeeds.
|
| +var expectedColors = [ [ 255, 0, 0 ], [ 0, 255, 0 ], [ 0, 0, 255 ] ];
|
| +
|
| +function waitForExpectedColors(colorDeviation) {
|
| + // If needed, create the video and canvas elements, but no need to append them
|
| + // to the DOM.
|
| + if (!this.video) {
|
| + this.video = document.createElement("video");
|
| + this.video.width = width;
|
| + this.video.height = height;
|
| + this.video.addEventListener("error", chrome.test.fail);
|
| + this.video.src = URL.createObjectURL(receiveStream);
|
| + this.video.play();
|
| +
|
| + this.readbackCanvas = document.createElement("canvas");
|
| + this.readbackCanvas.width = width;
|
| + this.readbackCanvas.height = height;
|
| + }
|
| +
|
| + // Only bother examining a video frame if the video timestamp has advanced.
|
| + var currentVideoTimestamp = this.video.currentTime;
|
| + if (!this.lastVideoTimestamp ||
|
| + this.lastVideoTimestamp < currentVideoTimestamp) {
|
| + this.lastVideoTimestamp = currentVideoTimestamp;
|
| +
|
| + // Grab a snapshot of the center pixel of the video.
|
| + var ctx = this.readbackCanvas.getContext("2d");
|
| + ctx.drawImage(video, 0, 0, width, height);
|
| + var imageData = ctx.getImageData(width / 2, height / 2, 1, 1);
|
| + var pixel = [ imageData.data[0], imageData.data[1], imageData.data[2] ];
|
| +
|
| + // Does the pixel match one of the expected colors?
|
| + for (var i = 0; i < expectedColors.length; ++i) {
|
| + var curColor = expectedColors[i];
|
| + if (Math.abs(pixel[0] - curColor[0]) <= colorDeviation &&
|
| + Math.abs(pixel[1] - curColor[1]) <= colorDeviation &&
|
| + Math.abs(pixel[2] - curColor[2]) <= colorDeviation) {
|
| + console.debug("Observed expected color RGB(" + curColor +
|
| + ") in the video as RGB(" + pixel + ")");
|
| + expectedColors.splice(i, 1);
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (expectedColors.length == 0) {
|
| + chrome.test.succeed();
|
| + } else {
|
| + setTimeout(function () { waitForExpectedColors(colorDeviation); },
|
| + 1000 / frameRate);
|
| + }
|
| +}
|
| +
|
| +chrome.test.runTests([
|
| + function presentationTest() {
|
| + // Parse colorDeviation query parameter.
|
| + var colorDeviation; // How far from the expected intensity ([0,255] scale)?
|
| + try {
|
| + colorDeviation = parseInt(
|
| + window.location.search.match(/(\?|&)colorDeviation=(\d+)/)[2]);
|
| + chrome.test.assertTrue(colorDeviation >= 0 && colorDeviation <= 255);
|
| + } catch (err) {
|
| + chrome.test.fail("Error parsing query params -- " + err.message);
|
| + return;
|
| + }
|
| +
|
| + chrome.tabCapture.capturePresentation(
|
| + offscreenPageUri,
|
| + "bubbles",
|
| + { video: true,
|
| + audio: false,
|
| + videoConstraints: {
|
| + mandatory: {
|
| + minWidth: width,
|
| + minHeight: height,
|
| + maxWidth: width,
|
| + maxHeight: height,
|
| + maxFrameRate: frameRate,
|
| + }
|
| + }
|
| + },
|
| + function examineTheOffscreenCaptureVideo(captureStream) {
|
| + chrome.test.assertTrue(!!captureStream);
|
| + receiveStream = captureStream;
|
| + waitForExpectedColors(colorDeviation);
|
| + });
|
| + }
|
| +]);
|
|
|