browser/extensions/shumway/content/web/avm-sandbox.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:2dfb20f03005
1 /* -*- Mode: js; js-indent-level: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
2 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
3 /*
4 * Copyright 2013 Mozilla Foundation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 // Extension communication object
20 var FirefoxCom = (function FirefoxComClosure() {
21 return {
22 /**
23 * Creates an event that the extension is listening for and will
24 * synchronously respond to.
25 * NOTE: It is reccomended to use request() instead since one day we may not
26 * be able to synchronously reply.
27 * @param {String} action The action to trigger.
28 * @param {String} data Optional data to send.
29 * @return {*} The response.
30 */
31 requestSync: function(action, data) {
32 var e = document.createEvent('CustomEvent');
33 e.initCustomEvent('shumway.message', true, false,
34 {action: action, data: data, sync: true});
35 document.dispatchEvent(e);
36 return e.detail.response;
37 },
38 /**
39 * Creates an event that the extension is listening for and will
40 * asynchronously respond by calling the callback.
41 * @param {String} action The action to trigger.
42 * @param {String} data Optional data to send.
43 * @param {Function} callback Optional response callback that will be called
44 * with one data argument.
45 */
46 request: function(action, data, callback) {
47 var e = document.createEvent('CustomEvent');
48 e.initCustomEvent('shumway.message', true, false,
49 {action: action, data: data, sync: false});
50 if (callback) {
51 if ('nextId' in FirefoxCom.request) {
52 FirefoxCom.request.nextId = 1;
53 }
54 var cookie = "requestId" + (FirefoxCom.request.nextId++);
55 e.detail.cookie = cookie;
56 e.detail.callback = true;
57
58 document.addEventListener('shumway.response', function listener(event) {
59 if (cookie !== event.detail.cookie)
60 return;
61
62 document.removeEventListener('shumway.response', listener, false);
63
64 var response = event.detail.response;
65 return callback(response);
66 }, false);
67 }
68 return document.dispatchEvent(e);
69 },
70 initJS: function (callback) {
71 FirefoxCom.request('externalCom', {action: 'init'});
72 document.addEventListener('shumway.remote', function (e) {
73 e.detail.result = callback(e.detail.functionName, e.detail.args);
74 }, false);
75 }
76 };
77 })();
78
79 function fallback() {
80 FirefoxCom.requestSync('fallback', null)
81 }
82
83 var playerglobalInfo = {
84 abcs: SHUMWAY_ROOT + "playerglobal/playerglobal.abcs",
85 catalog: SHUMWAY_ROOT + "playerglobal/playerglobal.json"
86 };
87
88 function runViewer() {
89 var flashParams = JSON.parse(FirefoxCom.requestSync('getPluginParams', null));
90 FileLoadingService.setBaseUrl(flashParams.baseUrl);
91
92 movieUrl = flashParams.url;
93 if (!movieUrl) {
94 console.log("no movie url provided -- stopping here");
95 FirefoxCom.request('endActivation', null);
96 return;
97 }
98
99 movieParams = flashParams.movieParams;
100 objectParams = flashParams.objectParams;
101 var isOverlay = flashParams.isOverlay;
102 pauseExecution = flashParams.isPausedAtStart;
103
104 console.log("url=" + movieUrl + ";params=" + uneval(movieParams));
105 if (movieParams.fmt_list && movieParams.url_encoded_fmt_stream_map) {
106 // HACK removing FLVs from the fmt_list
107 movieParams.fmt_list = movieParams.fmt_list.split(',').filter(function (s) {
108 var fid = s.split('/')[0];
109 return fid !== '5' && fid !== '34' && fid !== '35'; // more?
110 }).join(',');
111 }
112
113 parseSwf(movieUrl, movieParams, objectParams);
114
115 if (isOverlay) {
116 document.getElementById('overlay').className = 'enabled';
117 var fallbackDiv = document.getElementById('fallback');
118 fallbackDiv.addEventListener('click', function(e) {
119 fallback();
120 e.preventDefault();
121 });
122 var reportDiv = document.getElementById('report');
123 reportDiv.addEventListener('click', function(e) {
124 reportIssue();
125 e.preventDefault();
126 });
127 var fallbackMenu = document.getElementById('fallbackMenu');
128 fallbackMenu.removeAttribute('hidden');
129 fallbackMenu.addEventListener('click', fallback);
130 }
131 var showURLMenu = document.getElementById('showURLMenu');
132 showURLMenu.addEventListener('click', showURL);
133 var inspectorMenu = document.getElementById('inspectorMenu');
134 inspectorMenu.addEventListener('click', showInInspector);
135 var reportMenu = document.getElementById('reportMenu');
136 reportMenu.addEventListener('click', reportIssue);
137
138 document.getElementById('copyProfileMenu').addEventListener('click', copyProfile);
139 }
140
141 function showURL() {
142 window.prompt("Copy to clipboard", movieUrl);
143 }
144
145 function showInInspector() {
146 var base = "http://www.areweflashyet.com/shumway/examples/inspector/inspector.html?rfile=";
147 var params = '';
148 for (var k in movieParams) {
149 params += '&' + k + '=' + encodeURIComponent(movieParams[k]);
150 }
151 window.open(base + encodeURIComponent(movieUrl) + params);
152 }
153
154 function reportIssue() {
155 var duplicatesMap = Object.create(null);
156 var prunedExceptions = [];
157 avm2.exceptions.forEach(function(e) {
158 var ident = e.source + e.message + e.stack;
159 var entry = duplicatesMap[ident];
160 if (!entry) {
161 entry = duplicatesMap[ident] = {
162 source: e.source,
163 message: e.message,
164 stack: e.stack,
165 count: 0
166 };
167 prunedExceptions.push(entry);
168 }
169 entry.count++;
170 });
171 FirefoxCom.requestSync('reportIssue', JSON.stringify(prunedExceptions));
172 }
173
174 function copyProfile() {
175 function toArray(v) {
176 var array = [];
177 for (var i = 0; i < v.length; i++) {
178 array.push(v[i]);
179 }
180 return array;
181 }
182 var profile = {
183 loops: {counts: toArray($L), lines: $LL},
184 functions: {counts: toArray($F), lines: $FL},
185 allocations: {counts: toArray($A), lines: $AL}
186 };
187 FirefoxCom.request('unsafeSetClipboard', JSON.stringify(profile));
188 }
189
190 var movieUrl, movieParams, objectParams;
191
192 window.addEventListener("message", function handlerMessage(e) {
193 var args = e.data;
194 switch (args.callback) {
195 case "loadFile":
196 var session = FileLoadingService.sessions[args.sessionId];
197 if (session) {
198 session.notify(args);
199 }
200 break;
201 }
202 }, true);
203
204 var TelemetryService = {
205 reportTelemetry: function (data) {
206 FirefoxCom.request('reportTelemetry', data, null);
207 }
208 };
209
210 var FileLoadingService = {
211 get baseUrl() { return movieUrl; },
212 nextSessionId: 1, // 0 - is reserved
213 sessions: [],
214 createSession: function () {
215 var sessionId = this.nextSessionId++;
216 return this.sessions[sessionId] = {
217 open: function (request) {
218 var self = this;
219 var path = FileLoadingService.resolveUrl(request.url);
220 console.log('Session #' + sessionId +': loading ' + path);
221 FirefoxCom.requestSync('loadFile', {url: path, method: request.method,
222 mimeType: request.mimeType, postData: request.data,
223 checkPolicyFile: request.checkPolicyFile, sessionId: sessionId});
224 },
225 notify: function (args) {
226 switch (args.topic) {
227 case "open": this.onopen(); break;
228 case "close":
229 this.onclose();
230 FileLoadingService.sessions[sessionId] = null;
231 console.log('Session #' + sessionId +': closed');
232 break;
233 case "error":
234 this.onerror && this.onerror(args.error);
235 break;
236 case "progress":
237 console.log('Session #' + sessionId + ': loaded ' + args.loaded + '/' + args.total);
238 this.onprogress && this.onprogress(args.array, {bytesLoaded: args.loaded, bytesTotal: args.total});
239 break;
240 }
241 }
242 };
243 },
244 setBaseUrl: function (url) {
245 var a = document.createElement('a');
246 a.href = url || '#';
247 a.setAttribute('style', 'display: none;');
248 document.body.appendChild(a);
249 FileLoadingService.baseUrl = a.href;
250 document.body.removeChild(a);
251 },
252 resolveUrl: function (url) {
253 if (url.indexOf('://') >= 0) return url;
254
255 var base = FileLoadingService.baseUrl;
256 base = base.lastIndexOf('/') >= 0 ? base.substring(0, base.lastIndexOf('/') + 1) : '';
257 if (url.indexOf('/') === 0) {
258 var m = /^[^:]+:\/\/[^\/]+/.exec(base);
259 if (m) base = m[0];
260 }
261 return base + url;
262 }
263 };
264
265 function parseSwf(url, movieParams, objectParams) {
266 var enableVerifier = Shumway.AVM2.Runtime.enableVerifier;
267 var EXECUTION_MODE = Shumway.AVM2.Runtime.EXECUTION_MODE;
268
269 var compilerSettings = JSON.parse(
270 FirefoxCom.requestSync('getCompilerSettings', null));
271 enableVerifier.value = compilerSettings.verifier;
272
273 // init misc preferences
274 turboMode.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.turboMode', def: false});
275 hud.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.hud', def: false});
276 forceHidpi.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.force_hidpi', def: false});
277 dummyAnimation.value = FirefoxCom.requestSync('getBoolPref', {pref: 'shumway.dummyMode', def: false});
278
279 console.log("Compiler settings: " + JSON.stringify(compilerSettings));
280 console.log("Parsing " + url + "...");
281 function loaded() {
282 FirefoxCom.request('endActivation', null);
283 }
284
285 createAVM2(builtinPath, playerglobalInfo, avm1Path,
286 compilerSettings.sysCompiler ? EXECUTION_MODE.COMPILE : EXECUTION_MODE.INTERPRET,
287 compilerSettings.appCompiler ? EXECUTION_MODE.COMPILE : EXECUTION_MODE.INTERPRET,
288 function (avm2) {
289 console.time("Initialize Renderer");
290 SWF.embed(url, document, document.getElementById("viewer"), {
291 url: url,
292 movieParams: movieParams,
293 objectParams: objectParams,
294 onComplete: loaded,
295 onBeforeFrame: frame
296 });
297 });
298 }
299
300 var pauseExecution = false;
301 var initializeFrameControl = true;
302 function frame(e) {
303 if (initializeFrameControl) {
304 // marking that movie is started
305 document.body.classList.add("started");
306
307 TelemetryService.reportTelemetry({topic: "firstFrame"});
308
309 // skipping frame 0
310 initializeFrameControl = false;
311 return;
312 }
313 if (pauseExecution) {
314 e.cancel = true;
315 }
316 }
317
318 document.addEventListener('keydown', function (e) {
319 if (e.keyCode == 119 && e.ctrlKey) { // Ctrl+F8
320 pauseExecution = !pauseExecution;
321 }
322 }, false);

mercurial