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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 var screenshot = (function() {
6 /** A map of id to pending callback. */
7 var callbackMap = {};
8
9 /** An array of queued requests. They will all be executed when the
10 * 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.
11 var queuedRequests = [];
12
13 /** The next id to assign. Used for mapping id to callback. */
14 var nextId = 0;
15
16 /** This is set to true when the background page injects screenshot code into
17 * this page */
18 var extensionInjected = false;
19
20 /** Generate a new id, which maps to the given callbacks.
21 *
22 * @param {function(string)} onSuccess
23 * @param {function(string)} onError
24 * @return {number} The id.
25 */
26 function addCallback(onSuccess, onError) {
27 var id = nextId++;
28 callbackMap[id] = [onSuccess, onError];
29 return id;
30 }
31
32 /** Call the callback mapped to |id|.
33 *
34 * @param {number} id
35 * @param {boolean} success true to call the success callback, false for the
36 * error callback.
37 * @param {...} A variable number of arguments to pass to the callback.
38 */
39 function callCallback(id, success) {
40 var callbacks = callbackMap[id];
41 if (!callbacks) {
42 console.log('Unknown id: ' + id);
43 return;
44 }
45
46 delete callbackMap[id];
47 var callback = success ? callbacks[0] : callbacks[1];
48 if (callback)
49 callback(Array.prototype.slice.call(arguments, 2));
50 }
51
52 /** Post a message to take a screenshot.
53 *
54 * This message will be enqueued if the extension has not yet injected the
55 * screenshot code.
56 *
57 * @param {number} id An id to associate with this request. When the
58 * screenshot is complete, the background page will return
59 * a result with this id.
60 */
61 function postScreenshotMessage(id) {
62 if (!extensionInjected) {
63 queuedRequests.push(id);
64 return;
65 }
66
67 window.postMessage({id: id, target: 'background'}, '*');
68 }
69
70 /** Post all queued screenshot requests.
71 *
72 * Should only be called after the screenshot code has been injected by the
73 * background page.
74 */
75 function postQueuedRequests() {
76 for (var i = 0; i < queuedRequests.length; ++i) {
77 var id = queuedRequests[i];
78 postScreenshotMessage(id);
79 }
80 queuedRequests = [];
81 }
82
83 /** Predicate whether the extension has injected code yet.
84 *
85 * @return {boolean}
86 */
87 function isInjected() {
88 // NOTE: This attribute name must match the one in injected.js.
89 return document.body &&
90 document.body.getAttribute('screenshot_extension_injected');
91 }
92
93 /** Start an interval that polls for when the extension has injected code
94 * into this page.
95 *
96 * The extension first adds a postMessage handler to listen for requests,
97 * then adds an attribute to the body element. If we see this attribute, we
98 * know the listener is ready.
99 */
100 function pollForInjection() {
101 var intervalId = window.setInterval(function() {
102 if (!isInjected())
103 return;
104
105 // Finally injected!
106 window.clearInterval(intervalId);
107 extensionInjected = true;
108 postQueuedRequests();
109 }, 100); // Every 100ms.
110 }
111
112 // Add a postMessage listener for when the injected code returns a result
113 // from the background page.
114 window.addEventListener('message', function(event) {
115 // If the message comes from another window, or is outbound (i.e.
116 // event.data.target === 'background'), ignore it.
117 if (event.source !== window || event.data.target !== 'page')
118 return;
119
120 var success = event.data.error === undefined;
121 callCallback(event.data.id, success, event.data.data);
122 }, false);
123
124 if (isInjected())
125 extensionInjected = true;
126 else
127 pollForInjection();
128
129 // Public functions.
130
131 /** Capture the current visible area of the tab as a PNG.
132 *
133 * If the request succeeds, |onSuccess| will be called with one parameter:
134 * the image encoded as a data URL.
135 *
136 * If the request fails, |onError| will be called with one parameter: an
137 * informational error message.
138 *
139 * @param {function(string)} onSuccess The success callback.
140 * @param {function(string)} onError The error callback.
141 */
142 function captureTab(onSuccess, onError) {
143 var id = addCallback(onSuccess, onError);
144 postScreenshotMessage(id);
145 }
146
147 /** Capture the current visible area of a given element as a PNG.
148 *
149 * If the request succeeds, |onSuccess| will be called with one parameter:
150 * the image encoded as a data URL.
151 *
152 * If the request fails, |onError| will be called with one parameter: an
153 * informational error message.
154 *
155 * @param {Element} element The element to capture.
156 * @param {function(string)} onSuccess The success callback.
157 * @param {function(string)} onError The error callback.
158 */
159 function captureElement(element, onSuccess, onError) {
160 var elementRect = element.getBoundingClientRect();
161 var elX = elementRect.left;
162 var elY = elementRect.top;
163 var elW = elementRect.width;
164 var elH = elementRect.height;
165
166 function onScreenCaptured(dataURL) {
167 // Create a canvas of the correct size.
168 var canvasEl = document.createElement('canvas');
169 canvasEl.setAttribute('width', elW);
170 canvasEl.setAttribute('height', elH);
171 var ctx = canvasEl.getContext('2d');
172
173 var imgEl = new Image();
174 imgEl.onload = function() {
175 // Draw only the element region of the image.
176 ctx.drawImage(imgEl, elX, elY, elW, elH, 0, 0, elW, elH);
177
178 // Extract the canvas to a new data URL, and return it via the callback.
179 onSuccess(canvasEl.toDataURL());
180 };
181
182 // Load the full screenshot into imgEl.
183 imgEl.src = dataURL;
184 }
185
186 var id = addCallback(onScreenCaptured, onError);
187 postScreenshotMessage(id);
188 }
189
190 return {
191 captureTab: captureTab,
192 captureElement: captureElement
193 };
194 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698