Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4088)

Unified Diff: chrome/test/data/extensions/api_test/tab_capture/presentation.js

Issue 1221483002: New tabCapture.captureOffscreenTab API, initially for Presentation API 1UA mode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);
+ });
+ }
+]);

Powered by Google App Engine
This is Rietveld 408576698