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

Unified Diff: native_client_sdk/src/build_tools/screenshot_extension/screenshot.js

Issue 23458018: [NaCl SDK] Screen capture extension for use with SDK visual testing. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 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: native_client_sdk/src/build_tools/screenshot_extension/screenshot.js
diff --git a/native_client_sdk/src/build_tools/screenshot_extension/screenshot.js b/native_client_sdk/src/build_tools/screenshot_extension/screenshot.js
new file mode 100644
index 0000000000000000000000000000000000000000..095c93190b91ff34013377bf2dec258cc0d10b94
--- /dev/null
+++ b/native_client_sdk/src/build_tools/screenshot_extension/screenshot.js
@@ -0,0 +1,194 @@
+// Copyright (c) 2013 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.
+
+var screenshot = (function() {
+ /** A map of id to pending callback. */
+ var callbackMap = {};
+
+ /** An array of queued requests. They will all be executed when the
+ * background page injects screen code into this page */
Sam Clegg 2013/09/05 00:05:31 Be consistent with javadoc style comments here. T
binji 2013/09/06 20:59:48 Done.
+ var queuedRequests = [];
+
+ /** The next id to assign. Used for mapping id to callback. */
+ var nextId = 0;
+
+ /** This is set to true when the background page injects screenshot code into
+ * this page */
+ var extensionInjected = false;
+
+ /** Generate a new id, which maps to the given callbacks.
+ *
+ * @param {function(string)} onSuccess
+ * @param {function(string)} onError
+ * @return {number} The id.
+ */
+ function addCallback(onSuccess, onError) {
+ var id = nextId++;
+ callbackMap[id] = [onSuccess, onError];
+ return id;
+ }
+
+ /** Call the callback mapped to |id|.
+ *
+ * @param {number} id
+ * @param {boolean} success true to call the success callback, false for the
+ * error callback.
+ * @param {...} A variable number of arguments to pass to the callback.
+ */
+ function callCallback(id, success) {
+ var callbacks = callbackMap[id];
+ if (!callbacks) {
+ console.log('Unknown id: ' + id);
+ return;
+ }
+
+ delete callbackMap[id];
+ var callback = success ? callbacks[0] : callbacks[1];
+ if (callback)
+ callback(Array.prototype.slice.call(arguments, 2));
+ }
+
+ /** Post a message to take a screenshot.
+ *
+ * This message will be enqueued if the extension has not yet injected the
+ * screenshot code.
+ *
+ * @param {number} id An id to associate with this request. When the
+ * screenshot is complete, the background page will return
+ * a result with this id.
+ */
+ function postScreenshotMessage(id) {
+ if (!extensionInjected) {
+ queuedRequests.push(id);
+ return;
+ }
+
+ window.postMessage({id: id, target: 'background'}, '*');
+ }
+
+ /** Post all queued screenshot requests.
+ *
+ * Should only be called after the screenshot code has been injected by the
+ * background page.
+ */
+ function postQueuedRequests() {
+ for (var i = 0; i < queuedRequests.length; ++i) {
+ var id = queuedRequests[i];
+ postScreenshotMessage(id);
+ }
+ queuedRequests = [];
+ }
+
+ /** Predicate whether the extension has injected code yet.
+ *
+ * @return {boolean}
+ */
+ function isInjected() {
+ // NOTE: This attribute name must match the one in injected.js.
+ return document.body &&
+ document.body.getAttribute('screenshot_extension_injected');
+ }
+
+ /** Start an interval that polls for when the extension has injected code
+ * into this page.
+ *
+ * The extension first adds a postMessage handler to listen for requests,
+ * then adds an attribute to the body element. If we see this attribute, we
+ * know the listener is ready.
+ */
+ function pollForInjection() {
+ var intervalId = window.setInterval(function() {
+ if (!isInjected())
+ return;
+
+ // Finally injected!
+ window.clearInterval(intervalId);
+ extensionInjected = true;
+ postQueuedRequests();
+ }, 100); // Every 100ms.
+ }
+
+ // Add a postMessage listener for when the injected code returns a result
+ // from the background page.
+ window.addEventListener('message', function(event) {
+ // If the message comes from another window, or is outbound (i.e.
+ // event.data.target === 'background'), ignore it.
+ if (event.source !== window || event.data.target !== 'page')
+ return;
+
+ var success = event.data.error === undefined;
+ callCallback(event.data.id, success, event.data.data);
+ }, false);
+
+ if (isInjected())
+ extensionInjected = true;
+ else
+ pollForInjection();
+
+ // Public functions.
+
+ /** Capture the current visible area of the tab as a PNG.
+ *
+ * If the request succeeds, |onSuccess| will be called with one parameter:
+ * the image encoded as a data URL.
+ *
+ * If the request fails, |onError| will be called with one parameter: an
+ * informational error message.
+ *
+ * @param {function(string)} onSuccess The success callback.
+ * @param {function(string)} onError The error callback.
+ */
+ function captureTab(onSuccess, onError) {
+ var id = addCallback(onSuccess, onError);
+ postScreenshotMessage(id);
+ }
+
+ /** Capture the current visible area of a given element as a PNG.
+ *
+ * If the request succeeds, |onSuccess| will be called with one parameter:
+ * the image encoded as a data URL.
+ *
+ * If the request fails, |onError| will be called with one parameter: an
+ * informational error message.
+ *
+ * @param {Element} element The element to capture.
+ * @param {function(string)} onSuccess The success callback.
+ * @param {function(string)} onError The error callback.
+ */
+ function captureElement(element, onSuccess, onError) {
+ var elementRect = element.getBoundingClientRect();
+ var elX = elementRect.left;
+ var elY = elementRect.top;
+ var elW = elementRect.width;
+ var elH = elementRect.height;
+
+ function onScreenCaptured(dataURL) {
+ // Create a canvas of the correct size.
+ var canvasEl = document.createElement('canvas');
+ canvasEl.setAttribute('width', elW);
+ canvasEl.setAttribute('height', elH);
+ var ctx = canvasEl.getContext('2d');
+
+ var imgEl = new Image();
+ imgEl.onload = function() {
+ // Draw only the element region of the image.
+ ctx.drawImage(imgEl, elX, elY, elW, elH, 0, 0, elW, elH);
+
+ // Extract the canvas to a new data URL, and return it via the callback.
+ onSuccess(canvasEl.toDataURL());
+ };
+
+ // Load the full screenshot into imgEl.
+ imgEl.src = dataURL;
+ }
+
+ var id = addCallback(onScreenCaptured, onError);
+ postScreenshotMessage(id);
+ }
+
+ return {
+ captureTab: captureTab,
+ captureElement: captureElement
+ };
+})();

Powered by Google App Engine
This is Rietveld 408576698