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

Unified Diff: chrome/test/data/extensions/api_test/tab_capture/offscreen_test_harness.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: Mostly revert to Patch Set 6, plus minor tweaks. [and REBASE] Created 5 years, 2 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/offscreen_test_harness.js
diff --git a/chrome/test/data/extensions/api_test/tab_capture/offscreen_test_harness.js b/chrome/test/data/extensions/api_test/tab_capture/offscreen_test_harness.js
new file mode 100644
index 0000000000000000000000000000000000000000..53fa06c0e12814217545e3c2204089528db12c41
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/tab_capture/offscreen_test_harness.js
@@ -0,0 +1,188 @@
+// 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.
+
+// This file contains a test harness for testing the behavior of pages running
+// inside off-screen tabs:
+//
+// 1. It provides a simple way to formulate a data URI containing a full HTML
+// document that executes arbitrary script. The arbitrary script running
+// in the off-screen tab calls setFillColor() to expose its current state
+// by rendering a color fill. In addition, the off-screen tab continuously
+// paints changes that force the tab capture implementation to continuously
+// capture new video frames.
+//
+// 2. In the extension's JavaScript context, a waitAnForExpectedColor()
+// function is provided to sample the video frames of the captured
+// off-screen tab until the center pixel contains one of the colors in a
+// set of expected colors.
+
+// Width/Height of off-screen tab, rendered content, and captured content.
+var width = 160;
+var height = 120;
+
+// Capture frame rate.
+var frameRate = 8;
+
+// Return a full HTML document that executes the |script|. The script calls
+// setFillColor() to expose changes to its internal state.
+function makeOffscreenTabTestDocument(script) {
+ return '\
+<html><body style="background-color:black; margin:0; padding:0;"></body>\n\
+<script>\n\
+var redColor = [255, 0, 0];\n\
+var greenColor = [0, 255, 0];\n\
+var blueColor = [0, 0, 255];\n\
+\n\
+var fillColor = [0, 0, 0];\n\
+function setFillColor(color) {\n\
+ fillColor = color;\n\
+}\n\
+\n\
+var debugMessage = "";\n\
+function setDebugMessage(msg) {\n\
+ debugMessage = msg;\n\
+}\n\
+\n\
+function updateTestPattern() {\n\
+ if (!this.canvas) {\n\
+ this.canvas = document.createElement("canvas");\n\
+ this.canvas.width = ' + width + ';\n\
+ this.canvas.height = ' + height + ';\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(" + fillColor + ")";\n\
+ context.fillRect(0, 0, this.canvas.width, this.canvas.height);\n\
+ // Draw the circle that moves around the page.\n\
+ var inverseColor =\n\
+ [255 - fillColor[0], 255 - fillColor[1], 255 - fillColor[2]];\n\
+ if (debugMessage) {\n\
+ context.fillStyle = "rgb(" + inverseColor + ")";\n\
+ context.font = "xx-small monospace";\n\
+ context.fillText(debugMessage, 0, 0);\n\
+ }\n\
+ context.fillStyle = "rgba(" + inverseColor + ", 0.5)";\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\
+ updateTestPattern();\n\
+ requestAnimationFrame(renderTestPatternLoop);\n\
+}\n\
+renderTestPatternLoop();\n\
+\n' +
+script + '\n\
+</script></html>';
+}
+
+// Return the given |html| document as an encoded data URI.
+function makeDataUriFromDocument(html) {
+ return 'data:text/html;charset=UTF-8,' + encodeURIComponent(html);
+}
+
+// Returns capture options for starting the off-screen tab.
+function getCaptureOptions() {
+ return {
+ video: true,
+ audio: false,
+ videoConstraints: {
+ mandatory: {
+ minWidth: width,
+ minHeight: height,
+ maxWidth: width,
+ maxHeight: height,
+ maxFrameRate: frameRate,
+ }
+ }
+ };
+}
+
+// Samples the video frames from a capture |stream|, testing the color of the
+// center pixel. Once the pixel matches one of the colors in |expectedColors|,
+// run |callback| with the index of the matched color. |colorDeviation| is used
+// to imprecisely match colors.
+function waitForAnExpectedColor(
+ stream, expectedColors, colorDeviation, callback) {
+ chrome.test.assertTrue(!!stream);
+ chrome.test.assertTrue(expectedColors.length > 0);
+ chrome.test.assertTrue(!!callback);
+
+ var video = document.getElementById('video');
+ chrome.test.assertTrue(!!video);
+
+ // If not yet done, plug the LocalMediaStream into the video element.
+ if (!this.stream || this.stream != stream) {
+ this.stream = stream;
+ video.src = URL.createObjectURL(stream);
+ video.play();
+ }
+
+ // Create a canvas to sample frames from the video element.
+ if (!this.canvas) {
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = width;
+ this.canvas.height = height;
+ }
+
+ // Only bother examining a video frame if the video timestamp has advanced.
+ var currentVideoTimestamp = video.currentTime;
+ if (!this.lastVideoTimestamp ||
+ this.lastVideoTimestamp < currentVideoTimestamp) {
+ this.lastVideoTimestamp = currentVideoTimestamp;
+
+ // Grab a snapshot of the center pixel of the video.
+ var ctx = this.canvas.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, end = expectedColors.length; i < end; ++i) {
+ var color = expectedColors[i];
+ if (Math.abs(pixel[0] - color[0]) <= colorDeviation &&
+ Math.abs(pixel[1] - color[1]) <= colorDeviation &&
+ Math.abs(pixel[2] - color[2]) <= colorDeviation) {
+ console.debug("Observed expected color RGB(" + color +
+ ") in the video as RGB(" + pixel + ")");
+ setTimeout(function () { callback(i); }, 0);
+ return;
+ }
+ }
+ }
+
+ // At this point, an expected color has not been observed. Schedule another
+ // check after a short delay.
+ setTimeout(
+ function () {
+ waitForAnExpectedColor(stream, expectedColors, colorDeviation, callback);
+ },
+ 1000 / frameRate);
+}
+
+// Stops all the tracks in a MediaStream.
+function stopAllTracks(stream) {
+ var tracks = stream.getTracks();
+ for (var i = 0, end = tracks.length; i < end; ++i) {
+ tracks[i].stop();
+ }
+ chrome.test.assertFalse(stream.active);
+}

Powered by Google App Engine
This is Rietveld 408576698