mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1250046
- Remove Shumway core files. r=till
This commit is contained in:
parent
4c1b965308
commit
d3e1f74458
@ -72,7 +72,6 @@ browser/components/tabview/**
|
||||
browser/components/translation/**
|
||||
browser/extensions/pdfjs/**
|
||||
browser/extensions/pocket/content/panels/js/vendor/**
|
||||
browser/extensions/shumway/**
|
||||
browser/locales/**
|
||||
|
||||
# Ignore all of loop since it is imported from github and checked at source.
|
||||
|
@ -1397,11 +1397,6 @@ pref("pdfjs.firstRun", true);
|
||||
pref("pdfjs.previousHandler.preferredAction", 0);
|
||||
pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
|
||||
|
||||
// Shumway is only bundled in Nightly.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("shumway.disabled", true);
|
||||
#endif
|
||||
|
||||
// The maximum amount of decoded image data we'll willingly keep around (we
|
||||
// might keep around more than this, but we'll try to get down to this value).
|
||||
// (This is intentionally on the high side; see bug 746055.)
|
||||
|
@ -64,11 +64,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PdfJs",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ProcessHangMonitor",
|
||||
"resource:///modules/ProcessHangMonitor.jsm");
|
||||
|
||||
if (AppConstants.NIGHTLY_BUILD) {
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ShumwayUtils",
|
||||
"resource://shumway/ShumwayUtils.jsm");
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "webrtcUI",
|
||||
"resource:///modules/webrtcUI.jsm");
|
||||
|
||||
@ -995,13 +990,6 @@ BrowserGlue.prototype = {
|
||||
// passively.
|
||||
Services.ppmm.loadProcessScript("resource://pdf.js/pdfjschildbootstrap.js", true);
|
||||
|
||||
if (AppConstants.NIGHTLY_BUILD) {
|
||||
// Registering Shumway bootstrap script the child processes.
|
||||
Services.ppmm.loadProcessScript("chrome://shumway/content/bootstrap-content.js", true);
|
||||
// Initializing Shumway (shall be run after child script registration).
|
||||
ShumwayUtils.init();
|
||||
}
|
||||
|
||||
if (AppConstants.platform == "win") {
|
||||
// For Windows 7, initialize the jump list module.
|
||||
const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
|
||||
|
@ -8,5 +8,4 @@ DIRS += [
|
||||
'loop',
|
||||
'pdfjs',
|
||||
'pocket',
|
||||
'shumway',
|
||||
]
|
||||
|
@ -1,178 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
@ -1,2 +0,0 @@
|
||||
content shumway chrome/
|
||||
resource shumway content/
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['ExternalInterface'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
// Helper class to forward external interface messages between chrome code and
|
||||
// content window / object element.
|
||||
function ExternalInterface(window, embedTag, callback) {
|
||||
this.window = window;
|
||||
this.embedTag = embedTag;
|
||||
this.callback = callback;
|
||||
this.externalComInitialized = false;
|
||||
}
|
||||
ExternalInterface.prototype = {
|
||||
processAction: function (data) {
|
||||
var parentWindow = this.window;
|
||||
var embedTag = this.embedTag;
|
||||
|
||||
switch (data.action) {
|
||||
case 'init':
|
||||
if (this.externalComInitialized)
|
||||
return;
|
||||
|
||||
this.externalComInitialized = true;
|
||||
this.initExternalCom(parentWindow, embedTag, this.callback);
|
||||
return;
|
||||
case 'getId':
|
||||
return embedTag.id;
|
||||
case 'eval':
|
||||
return this.__flash__eval(data.expression);
|
||||
case 'call':
|
||||
return this.__flash__call(data.request);
|
||||
case 'register':
|
||||
return this.__flash__registerCallback(data.functionName);
|
||||
case 'unregister':
|
||||
return this.__flash__unregisterCallback(data.functionName);
|
||||
}
|
||||
},
|
||||
|
||||
initExternalCom: function (window, embedTag, onExternalCallback) {
|
||||
var traceExternalInterface = getBoolPref('shumway.externalInterface.trace', false);
|
||||
// Initialize convenience functions. Notice that these functions are
|
||||
// exposed to the content via Cu.exportFunction, so be careful (e.g. don't
|
||||
// use `this` pointer).
|
||||
this.__flash__toXML = function __flash__toXML(obj) {
|
||||
switch (typeof obj) {
|
||||
case 'boolean':
|
||||
return obj ? '<true/>' : '<false/>';
|
||||
case 'number':
|
||||
return '<number>' + obj + '</number>';
|
||||
case 'object':
|
||||
if (obj === null) {
|
||||
return '<null/>';
|
||||
}
|
||||
if ('hasOwnProperty' in obj && obj.hasOwnProperty('length')) {
|
||||
// array
|
||||
var xml = '<array>';
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
xml += '<property id="' + i + '">' + __flash__toXML(obj[i]) + '</property>';
|
||||
}
|
||||
return xml + '</array>';
|
||||
}
|
||||
var xml = '<object>';
|
||||
for (var i in obj) {
|
||||
xml += '<property id="' + i + '">' + __flash__toXML(obj[i]) + '</property>';
|
||||
}
|
||||
return xml + '</object>';
|
||||
case 'string':
|
||||
return '<string>' + obj.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') + '</string>';
|
||||
case 'undefined':
|
||||
return '<undefined/>';
|
||||
}
|
||||
};
|
||||
this.__flash__eval = function (expr) {
|
||||
traceExternalInterface && window.console.log('__flash__eval: ' + expr);
|
||||
// allowScriptAccess protects page from unwanted swf scripts,
|
||||
// we can execute script in the page context without restrictions.
|
||||
var result = window.eval(expr);
|
||||
traceExternalInterface && window.console.log('__flash__eval (result): ' + result);
|
||||
return result;
|
||||
};
|
||||
this.__flash__call = function (expr) {
|
||||
traceExternalInterface && window.console.log('__flash__call (ignored): ' + expr);
|
||||
};
|
||||
|
||||
this.__flash__registerCallback = function (functionName) {
|
||||
traceExternalInterface && window.console.log('__flash__registerCallback: ' + functionName);
|
||||
Components.utils.exportFunction(function () {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
traceExternalInterface && window.console.log('__flash__callIn: ' + functionName);
|
||||
var result;
|
||||
if (onExternalCallback) {
|
||||
result = onExternalCallback({functionName: functionName, args: args});
|
||||
traceExternalInterface && window.console.log('__flash__callIn (result): ' + result);
|
||||
}
|
||||
return window.eval(result);
|
||||
}, embedTag.wrappedJSObject, {defineAs: functionName});
|
||||
};
|
||||
this.__flash__unregisterCallback = function (functionName) {
|
||||
traceExternalInterface && window.console.log('__flash__unregisterCallback: ' + functionName);
|
||||
delete embedTag.wrappedJSObject[functionName];
|
||||
};
|
||||
|
||||
this.exportInterfaceFunctions();
|
||||
},
|
||||
|
||||
exportInterfaceFunctions: function () {
|
||||
var window = this.window;
|
||||
// We need to export window functions only once.
|
||||
if (!window.wrappedJSObject.__flash__initialized) {
|
||||
window.wrappedJSObject.__flash__initialized = true;
|
||||
// JavaScript eval'ed code use those functions.
|
||||
// TODO find the case when JavaScript code patches those
|
||||
// __flash__toXML will be called by the eval'ed code.
|
||||
Components.utils.exportFunction(this.__flash__toXML, window.wrappedJSObject,
|
||||
{defineAs: '__flash__toXML'});
|
||||
// The functions below are used for compatibility and are not called by chrome code.
|
||||
Components.utils.exportFunction(this.__flash__eval, window.wrappedJSObject,
|
||||
{defineAs: '__flash__eval'});
|
||||
Components.utils.exportFunction(this.__flash__call, window.wrappedJSObject,
|
||||
{defineAs: '__flash__call'});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getBoolPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['FileLoader'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
Components.utils.import('resource://gre/modules/Promise.jsm');
|
||||
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Components.utils.import('resource://gre/modules/NetUtil.jsm');
|
||||
|
||||
function FileLoaderSession(sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
this.xhr = null;
|
||||
}
|
||||
FileLoaderSession.prototype = {
|
||||
abort() {
|
||||
if (this.xhr) {
|
||||
this.xhr.abort();
|
||||
this.xhr = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function FileLoader(swfUrl, baseUrl, refererUrl, callback) {
|
||||
this.swfUrl = swfUrl;
|
||||
this.baseUrl = baseUrl;
|
||||
this.refererUrl = refererUrl;
|
||||
this.callback = callback;
|
||||
this.activeSessions = Object.create(null);
|
||||
|
||||
this.crossdomainRequestsCache = Object.create(null);
|
||||
}
|
||||
|
||||
FileLoader.prototype = {
|
||||
load: function (data) {
|
||||
function notifyLoadFileListener(data) {
|
||||
if (!onLoadFileCallback) {
|
||||
return;
|
||||
}
|
||||
onLoadFileCallback(data);
|
||||
}
|
||||
|
||||
var onLoadFileCallback = this.callback;
|
||||
var crossdomainRequestsCache = this.crossdomainRequestsCache;
|
||||
var baseUrl = this.baseUrl;
|
||||
var swfUrl = this.swfUrl;
|
||||
|
||||
var url = data.url;
|
||||
var checkPolicyFile = data.checkPolicyFile;
|
||||
var sessionId = data.sessionId;
|
||||
var limit = data.limit || 0;
|
||||
var method = data.method || "GET";
|
||||
var mimeType = data.mimeType;
|
||||
var postData = data.postData || null;
|
||||
var sendReferer = canSendReferer(swfUrl, this.refererUrl);
|
||||
|
||||
var session = new FileLoaderSession(sessionId);
|
||||
this.activeSessions[sessionId] = session;
|
||||
var self = this;
|
||||
|
||||
var performXHR = function () {
|
||||
// Load has been aborted before we reached this point.
|
||||
if (!self.activeSessions[sessionId]) {
|
||||
return;
|
||||
}
|
||||
var xhr = session.xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
xhr.open(method, url, true);
|
||||
xhr.responseType = "moz-chunked-arraybuffer";
|
||||
|
||||
if (sendReferer) {
|
||||
// Setting the referer uri, some site doing checks if swf is embedded
|
||||
// on the original page.
|
||||
xhr.setRequestHeader("Referer", self.refererUrl);
|
||||
}
|
||||
|
||||
// TODO apply range request headers if limit is specified
|
||||
|
||||
var lastPosition = 0;
|
||||
xhr.onprogress = function (e) {
|
||||
var position = e.loaded;
|
||||
var total = e.total;
|
||||
var data = new Uint8Array(xhr.response);
|
||||
// The event's `loaded` and `total` properties are sometimes lower than the actual
|
||||
// number of loaded bytes. In that case, increase them to that value.
|
||||
position = Math.max(position, data.byteLength);
|
||||
total = Math.max(total, data.byteLength);
|
||||
|
||||
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId,
|
||||
topic: "progress", array: data, loaded: position, total: total});
|
||||
lastPosition = position;
|
||||
if (limit && total >= limit) {
|
||||
xhr.abort();
|
||||
}
|
||||
};
|
||||
xhr.onreadystatechange = function(event) {
|
||||
if (xhr.readyState === 4) {
|
||||
delete self.activeSessions[sessionId];
|
||||
if (xhr.status !== 200 && xhr.status !== 0) {
|
||||
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId, topic: "error", error: xhr.statusText});
|
||||
}
|
||||
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId, topic: "close"});
|
||||
}
|
||||
};
|
||||
if (mimeType)
|
||||
xhr.setRequestHeader("Content-Type", mimeType);
|
||||
xhr.send(postData);
|
||||
notifyLoadFileListener({callback:"loadFile", sessionId: sessionId, topic: "open"});
|
||||
};
|
||||
|
||||
canDownloadFile(url, checkPolicyFile, swfUrl, crossdomainRequestsCache).then(function () {
|
||||
performXHR();
|
||||
}, function (reason) {
|
||||
log("data access is prohibited to " + url + " from " + baseUrl);
|
||||
delete self.activeSessions[sessionId];
|
||||
notifyLoadFileListener({
|
||||
callback: "loadFile", sessionId: sessionId, topic: "error",
|
||||
error: "only original swf file or file from the same origin loading supported (XDOMAIN)"
|
||||
});
|
||||
});
|
||||
},
|
||||
abort: function(sessionId) {
|
||||
var session = this.activeSessions[sessionId];
|
||||
if (!session) {
|
||||
log("Warning: trying to abort invalid session " + sessionId);
|
||||
return;
|
||||
}
|
||||
session.abort();
|
||||
delete this.activeSessions[sessionId];
|
||||
}
|
||||
};
|
||||
|
||||
function log(aMsg) {
|
||||
let msg = 'FileLoader.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
|
||||
Services.console.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
function getStringPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getComplexValue(pref, Components.interfaces.nsISupportsString).data;
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function disableXHRRedirect(xhr) {
|
||||
var listener = {
|
||||
asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
|
||||
// TODO perform URL check?
|
||||
callback.onRedirectVerifyCallback(Components.results.NS_ERROR_ABORT);
|
||||
},
|
||||
getInterface: function(iid) {
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIChannelEventSink])
|
||||
};
|
||||
xhr.channel.notificationCallbacks = listener;
|
||||
}
|
||||
|
||||
function canSendReferer(url, refererUrl) {
|
||||
if (!refererUrl) {
|
||||
return false;
|
||||
}
|
||||
// Allow sending HTTPS referer only to HTTPS.
|
||||
var parsedUrl, parsedRefererUrl;
|
||||
try {
|
||||
parsedRefererUrl = NetUtil.newURI(refererUrl);
|
||||
} catch (ex) { /* skipping invalid urls */ }
|
||||
if (!parsedRefererUrl ||
|
||||
parsedRefererUrl.scheme.toLowerCase() !== 'https') {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
parsedUrl = NetUtil.newURI(url);
|
||||
} catch (ex) { /* skipping invalid urls */ }
|
||||
return !!parsedUrl && parsedUrl.scheme.toLowerCase() === 'https';
|
||||
}
|
||||
|
||||
function canDownloadFile(url, checkPolicyFile, swfUrl, cache) {
|
||||
// TODO flash cross-origin request
|
||||
if (url === swfUrl) {
|
||||
// Allows downloading for the original file.
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Allows downloading from the same origin.
|
||||
var parsedUrl, parsedBaseUrl;
|
||||
try {
|
||||
parsedUrl = NetUtil.newURI(url);
|
||||
} catch (ex) { /* skipping invalid urls */ }
|
||||
try {
|
||||
parsedBaseUrl = NetUtil.newURI(swfUrl);
|
||||
} catch (ex) { /* skipping invalid urls */ }
|
||||
|
||||
if (parsedUrl && parsedBaseUrl &&
|
||||
parsedUrl.prePath === parsedBaseUrl.prePath) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// Additionally using internal whitelist.
|
||||
var whitelist = getStringPref('shumway.whitelist', '');
|
||||
if (whitelist && parsedUrl) {
|
||||
var whitelisted = whitelist.split(',').some(function (i) {
|
||||
return domainMatches(parsedUrl.host, i);
|
||||
});
|
||||
if (whitelisted) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
if (!parsedUrl || !parsedBaseUrl) {
|
||||
return Promise.reject('Invalid or non-specified URL or Base URL.');
|
||||
}
|
||||
|
||||
if (!checkPolicyFile) {
|
||||
return Promise.reject('Check of the policy file is not allowed.');
|
||||
}
|
||||
|
||||
// We can request crossdomain.xml.
|
||||
return fetchPolicyFile(parsedUrl.prePath + '/crossdomain.xml', cache).
|
||||
then(function (policy) {
|
||||
|
||||
if (policy.siteControl === 'none') {
|
||||
throw 'Site control is set to \"none\"';
|
||||
}
|
||||
// TODO assuming master-only, there are also 'by-content-type', 'all', etc.
|
||||
|
||||
var allowed = policy.allowAccessFrom.some(function (i) {
|
||||
return domainMatches(parsedBaseUrl.host, i.domain) &&
|
||||
(!i.secure || parsedBaseUrl.scheme.toLowerCase() === 'https');
|
||||
});
|
||||
if (!allowed) {
|
||||
throw 'crossdomain.xml does not contain source URL.';
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
function domainMatches(host, pattern) {
|
||||
if (!pattern) return false;
|
||||
if (pattern === '*') return true;
|
||||
host = host.toLowerCase();
|
||||
var parts = pattern.toLowerCase().split('*');
|
||||
if (host.indexOf(parts[0]) !== 0) return false;
|
||||
var p = parts[0].length;
|
||||
for (var i = 1; i < parts.length; i++) {
|
||||
var j = host.indexOf(parts[i], p);
|
||||
if (j === -1) return false;
|
||||
p = j + parts[i].length;
|
||||
}
|
||||
return parts[parts.length - 1] === '' || p === host.length;
|
||||
}
|
||||
|
||||
function fetchPolicyFile(url, cache) {
|
||||
if (url in cache) {
|
||||
return cache[url];
|
||||
}
|
||||
|
||||
var deferred = Promise.defer();
|
||||
|
||||
log('Fetching policy file at ' + url);
|
||||
var MAX_POLICY_SIZE = 8192;
|
||||
var xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
xhr.open('GET', url, true);
|
||||
disableXHRRedirect(xhr);
|
||||
xhr.overrideMimeType('text/xml');
|
||||
xhr.onprogress = function (e) {
|
||||
if (e.loaded >= MAX_POLICY_SIZE) {
|
||||
xhr.abort();
|
||||
cache[url] = false;
|
||||
deferred.reject('Max policy size');
|
||||
}
|
||||
};
|
||||
xhr.onreadystatechange = function(event) {
|
||||
if (xhr.readyState === 4) {
|
||||
// TODO disable redirects
|
||||
var doc = xhr.responseXML;
|
||||
if (xhr.status !== 200 || !doc) {
|
||||
deferred.reject('Invalid HTTP status: ' + xhr.statusText);
|
||||
return;
|
||||
}
|
||||
// parsing params
|
||||
var params = doc.documentElement.childNodes;
|
||||
var policy = { siteControl: null, allowAccessFrom: []};
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
switch (params[i].localName) {
|
||||
case 'site-control':
|
||||
policy.siteControl = params[i].getAttribute('permitted-cross-domain-policies');
|
||||
break;
|
||||
case 'allow-access-from':
|
||||
var access = {
|
||||
domain: params[i].getAttribute('domain'),
|
||||
security: params[i].getAttribute('security') === 'true'
|
||||
};
|
||||
policy.allowAccessFrom.push(access);
|
||||
break;
|
||||
default:
|
||||
// TODO allow-http-request-headers-from and other
|
||||
break;
|
||||
}
|
||||
}
|
||||
deferred.resolve(policy);
|
||||
}
|
||||
};
|
||||
xhr.send(null);
|
||||
return (cache[url] = deferred.promise);
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['LocalConnectionService'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/NetUtil.jsm');
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
const localConnectionsRegistry = Object.create(null);
|
||||
|
||||
function isConnectionNameValid(connectionName) {
|
||||
return typeof connectionName === 'string' &&
|
||||
(connectionName[0] === '_' || connectionName.split(':').length === 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a trusted qualified connection name from an already qualified name and a swfUrl.
|
||||
*
|
||||
* While connection names are already qualified at this point, the qualification happens in
|
||||
* untrusted code. To ensure that the name is correctly qualified, this function compares the
|
||||
* qualification domain with the current SWF's URL and substitutes that URL's domain if
|
||||
* required. A warning is logged in that case.
|
||||
*/
|
||||
function _getQualifiedConnectionName(connectionName, swfUrl) {
|
||||
// Already syntactically invalid connection names mustn't get here.
|
||||
if (!isConnectionNameValid(connectionName)) {
|
||||
// TODO: add telemetry
|
||||
throw new Error('Syntactically invalid local-connection name encountered', connectionName,
|
||||
swfUrl);
|
||||
}
|
||||
var [domain, name] = connectionName.split(':');
|
||||
var parsedURL = NetUtil.newURI(swfUrl);
|
||||
if (domain !== parsedURL.host) {
|
||||
// TODO: add telemetry
|
||||
log('Warning: invalid local-connection name qualification found: ' + connectionName);
|
||||
return parsedURL.host + ':' + swfUrl;
|
||||
}
|
||||
return connectionName;
|
||||
}
|
||||
|
||||
function _getLocalConnection(connectionName) {
|
||||
// Treat invalid connection names as non-existent. This can only happen if player code
|
||||
// misbehaves, though.
|
||||
if (!isConnectionNameValid(connectionName)) {
|
||||
// TODO: add telemetry
|
||||
return null;
|
||||
}
|
||||
var connection = localConnectionsRegistry[connectionName];
|
||||
if (connection && Components.utils.isDeadWrapper(connection.callback)) {
|
||||
delete localConnectionsRegistry[connectionName];
|
||||
return null;
|
||||
}
|
||||
return localConnectionsRegistry[connectionName];
|
||||
}
|
||||
|
||||
function LocalConnectionService(content, environment) {
|
||||
var traceLocalConnection = getBoolPref('shumway.localConnection.trace', false);
|
||||
var api = {
|
||||
createLocalConnection: function (connectionName, callback) {
|
||||
connectionName = connectionName + '';
|
||||
traceLocalConnection && content.console.log(`Creating local connection "${connectionName}" ` +
|
||||
`for SWF with URL ${environment.swfUrl}`);
|
||||
|
||||
if (!isConnectionNameValid(connectionName)) {
|
||||
// TODO: add telemetry
|
||||
traceLocalConnection && content.console.warn(`Invalid localConnection name `);
|
||||
return -1; // LocalConnectionConnectResult.InvalidName
|
||||
}
|
||||
if (typeof callback !== 'function') {
|
||||
// TODO: add telemetry
|
||||
traceLocalConnection && content.console.warn(`Invalid callback for localConnection`);
|
||||
return -3; // LocalConnectionConnectResult.InvalidCallback
|
||||
}
|
||||
connectionName = _getQualifiedConnectionName(connectionName, environment.swfUrl);
|
||||
if (_getLocalConnection(connectionName)) {
|
||||
traceLocalConnection && content.console.log(`localConnection ` +
|
||||
`name "${connectionName}" already taken`);
|
||||
return -2; // LocalConnectionConnectResult.AlreadyTaken
|
||||
}
|
||||
|
||||
var parsedURL = NetUtil.newURI(environment.swfUrl);
|
||||
|
||||
var connection = {
|
||||
callback,
|
||||
domain: parsedURL.host,
|
||||
environment: environment,
|
||||
secure: parsedURL.protocol === 'https:',
|
||||
allowedSecureDomains: Object.create(null),
|
||||
allowedInsecureDomains: Object.create(null)
|
||||
};
|
||||
localConnectionsRegistry[connectionName] = connection;
|
||||
return 0; // LocalConnectionConnectResult.Success
|
||||
},
|
||||
hasLocalConnection: function (connectionName) {
|
||||
connectionName = _getQualifiedConnectionName(connectionName + '', environment.swfUrl);
|
||||
|
||||
var result = !!_getLocalConnection(connectionName);
|
||||
traceLocalConnection && content.console.log(`hasLocalConnection "${connectionName}"? ` +
|
||||
result);
|
||||
return result;
|
||||
},
|
||||
closeLocalConnection: function (connectionName) {
|
||||
connectionName = _getQualifiedConnectionName(connectionName + '', environment.swfUrl);
|
||||
traceLocalConnection && content.console.log(`Closing local connection "${connectionName}" ` +
|
||||
`for SWF with URL ${environment.swfUrl}`);
|
||||
|
||||
var connection = _getLocalConnection(connectionName);
|
||||
if (!connection) {
|
||||
traceLocalConnection && content.console.log(`localConnection "${connectionName}" not ` +
|
||||
`connected`);
|
||||
return -1; // LocalConnectionCloseResult.NotConnected
|
||||
} else if (connection.environment !== environment) {
|
||||
// Attempts to close connections from a SWF instance that didn't create them shouldn't
|
||||
// happen. If they do, we treat them as if the connection didn't exist.
|
||||
traceLocalConnection && content.console.warn(`Ignored attempt to close localConnection ` +
|
||||
`"${connectionName}" from SWF instance that ` +
|
||||
`didn't create it`);
|
||||
return -1; // LocalConnectionCloseResult.NotConnected
|
||||
}
|
||||
delete localConnectionsRegistry[connectionName];
|
||||
return 0; // LocalConnectionCloseResult.Success
|
||||
},
|
||||
sendLocalConnectionMessage: function (connectionName, methodName, argsBuffer, sender,
|
||||
senderDomain, senderIsSecure) {
|
||||
connectionName = connectionName + '';
|
||||
methodName = methodName + '';
|
||||
senderDomain = senderDomain + '';
|
||||
senderIsSecure = !!senderIsSecure;
|
||||
// TODO: sanitize argsBuffer argument. Ask bholley how to do so.
|
||||
traceLocalConnection && content.console.log(`sending localConnection message ` +
|
||||
`"${methodName}" to "${connectionName}"`);
|
||||
|
||||
// Since we don't currently trust the sender information passed in here, we use the
|
||||
// currently running SWF's URL instead.
|
||||
var parsedURL = NetUtil.newURI(environment.swfUrl);
|
||||
var parsedURLIsSecure = parsedURL.protocol === 'https:';
|
||||
if (parsedURL.host !== senderDomain || parsedURLIsSecure !== senderIsSecure) {
|
||||
traceLocalConnection && content.console.warn(`sending localConnection message ` +
|
||||
`"${methodName}" to "${connectionName}"`);
|
||||
}
|
||||
senderDomain = parsedURL.host;
|
||||
senderIsSecure = parsedURLIsSecure;
|
||||
|
||||
var connection = _getLocalConnection(connectionName);
|
||||
if (!connection) {
|
||||
traceLocalConnection && content.console.log(`localConnection "${connectionName}" not ` +
|
||||
`connected`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var allowed = false;
|
||||
if (connection.secure) {
|
||||
// If the receiver is secure, the sender has to be, too, or it has to be whitelisted
|
||||
// with allowInsecureDomain.
|
||||
if (senderIsSecure) {
|
||||
if (senderDomain === connection.domain ||
|
||||
senderDomain in connection.allowedSecureDomains ||
|
||||
'*' in connection.allowedSecureDomains) {
|
||||
allowed = true;
|
||||
}
|
||||
} else {
|
||||
if (senderDomain in connection.allowedInsecureDomains ||
|
||||
'*' in connection.allowedInsecureDomains) {
|
||||
allowed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For non-secure connections, allowedSecureDomains is expected to contain all allowed
|
||||
// domains, secure on non-secure, so we don't have to check both.
|
||||
if (senderDomain === connection.domain ||
|
||||
senderDomain in connection.allowedSecureDomains ||
|
||||
'*' in connection.allowedSecureDomains) {
|
||||
allowed = true;
|
||||
}
|
||||
}
|
||||
if (!allowed) {
|
||||
traceLocalConnection && content.console.warn(`LocalConnection message rejected: domain ` +
|
||||
`${senderDomain} not allowed.`);
|
||||
return {
|
||||
name: 'SecurityError',
|
||||
$Bgmessage: "The current security context does not allow this operation.",
|
||||
_errorID: 3315
|
||||
};
|
||||
}
|
||||
var callback = connection.callback;
|
||||
var clonedArgs = Components.utils.cloneInto(argsBuffer, callback);
|
||||
callback(methodName, clonedArgs);
|
||||
} catch (e) {
|
||||
// TODO: add telemetry
|
||||
content.console.warn('Unexpected error encountered while sending LocalConnection message.');
|
||||
}
|
||||
},
|
||||
allowDomainsForLocalConnection: function (connectionName, domains, secure) {
|
||||
connectionName = _getQualifiedConnectionName(connectionName + '', environment.swfUrl);
|
||||
secure = !!secure;
|
||||
var connection = _getLocalConnection(connectionName);
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
domains = Components.utils.cloneInto(domains, connection);
|
||||
} catch (e) {
|
||||
log('error in allowDomainsForLocalConnection: ' + e);
|
||||
return;
|
||||
}
|
||||
traceLocalConnection && content.console.log(`allowing ${secure ? '' : 'in'}secure domains ` +
|
||||
`[${domains}] for localConnection ` +
|
||||
`"${connectionName}"`);
|
||||
function validateDomain(domain) {
|
||||
if (typeof domain !== 'string') {
|
||||
return false;
|
||||
}
|
||||
if (domain === '*') {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
var uri = NetUtil.newURI('http://' + domain);
|
||||
return uri.host === domain;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(domains) || !domains.every(validateDomain)) {
|
||||
traceLocalConnection && content.console.warn(`Invalid domains rejected`);
|
||||
return;
|
||||
}
|
||||
var allowedDomains = secure ?
|
||||
connection.allowedSecureDomains :
|
||||
connection.allowedInsecureDomains;
|
||||
domains.forEach(domain => allowedDomains[domain] = true);
|
||||
}
|
||||
};
|
||||
|
||||
// Don't return `this` even though this function is treated as a ctor. Makes cloning into the
|
||||
// content compartment an internal operation the client code doesn't have to worry about.
|
||||
return Components.utils.cloneInto(api, content, {cloneFunctions:true});
|
||||
}
|
||||
|
||||
function getBoolPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['RtmpUtils'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
var RtmpUtils = {
|
||||
get isRtmpEnabled() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref('shumway.rtmp.enabled');
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
createSocket: function (sandbox, params) {
|
||||
var host = params.host, port = params.port, ssl = params.ssl;
|
||||
|
||||
var baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
|
||||
var socket = baseSocket.open(host, port, {useSecureTransport: ssl, binaryType: 'arraybuffer'});
|
||||
if (!socket) {
|
||||
return null;
|
||||
}
|
||||
|
||||
socket.onopen = function () {
|
||||
if (wrapperOnOpen) {
|
||||
wrapperOnOpen(new sandbox.Object());
|
||||
}
|
||||
};
|
||||
socket.ondata = function (e) {
|
||||
if (wrapperOnData) {
|
||||
var wrappedE = new sandbox.Object();
|
||||
wrappedE.data = Components.utils.cloneInto(e.data, sandbox);
|
||||
wrapperOnData(wrappedE);
|
||||
}
|
||||
};
|
||||
socket.ondrain = function () {
|
||||
if (wrapperOnDrain) {
|
||||
wrapperOnDrain(new sandbox.Object());
|
||||
}
|
||||
};
|
||||
socket.onerror = function (e) {
|
||||
if (wrapperOnError) {
|
||||
var wrappedE = new sandbox.Object();
|
||||
wrappedE.data = Components.utils.cloneInto(e.data, sandbox);
|
||||
wrapperOnError(wrappedE);
|
||||
}
|
||||
};
|
||||
socket.onclose = function () {
|
||||
if (wrapperOnClose) {
|
||||
wrapperOnClose(new sandbox.Object());
|
||||
}
|
||||
};
|
||||
|
||||
var wrapperOnOpen, wrapperOnData, wrapperOnDrain, wrapperOnError, wrapperOnClose;
|
||||
var wrapper = Components.utils.cloneInto({
|
||||
setOpenCallback: function (callback) {
|
||||
wrapperOnOpen = callback;
|
||||
},
|
||||
setDataCallback: function (callback) {
|
||||
wrapperOnData = callback;
|
||||
},
|
||||
setDrainCallback: function (callback) {
|
||||
wrapperOnDrain = callback;
|
||||
},
|
||||
setErrorCallback: function (callback) {
|
||||
wrapperOnError = callback;
|
||||
},
|
||||
setCloseCallback: function (callback) {
|
||||
wrapperOnClose = callback;
|
||||
},
|
||||
|
||||
send: function (buffer, offset, count) {
|
||||
return socket.send(buffer, offset, count);
|
||||
},
|
||||
|
||||
close: function () {
|
||||
socket.close();
|
||||
}
|
||||
}, sandbox, {cloneFunctions:true});
|
||||
return wrapper;
|
||||
},
|
||||
|
||||
createXHR: function (sandbox) {
|
||||
var xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
|
||||
xhr.onload = function () {
|
||||
wrapper.status = xhr.status;
|
||||
wrapper.response = Components.utils.cloneInto(xhr.response, sandbox);
|
||||
if (wrapperOnLoad) {
|
||||
wrapperOnLoad(new sandbox.Object());
|
||||
}
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
wrapper.status = xhr.status;
|
||||
if (wrapperOnError) {
|
||||
wrapperOnError(new sandbox.Object());
|
||||
}
|
||||
};
|
||||
|
||||
var wrapperOnLoad, wrapperOnError;
|
||||
var wrapper = Components.utils.cloneInto({
|
||||
status: 0,
|
||||
response: undefined,
|
||||
responseType: 'text',
|
||||
|
||||
setLoadCallback: function (callback) {
|
||||
wrapperOnLoad = callback;
|
||||
},
|
||||
setErrorCallback: function (callback) {
|
||||
wrapperOnError = callback;
|
||||
},
|
||||
|
||||
open: function (method, path, async) {
|
||||
if (method !== 'POST' || !path || (async !== undefined && !async)) {
|
||||
throw new Error('invalid open() arguments');
|
||||
}
|
||||
// TODO check path
|
||||
xhr.open('POST', path, true);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-fcs');
|
||||
},
|
||||
|
||||
setRequestHeader: function (header, value) {
|
||||
if (header !== 'Content-Type' || value !== 'application/x-fcs') {
|
||||
throw new Error('invalid setRequestHeader() arguments');
|
||||
}
|
||||
},
|
||||
|
||||
send: function (data) {
|
||||
if (wrapper.responseType !== 'arraybuffer') {
|
||||
throw new Error('Invalid responseType.');
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
}, sandbox, {cloneFunctions:true});
|
||||
return wrapper;
|
||||
}
|
||||
};
|
@ -1,777 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['ShumwayCom'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/NetUtil.jsm');
|
||||
Components.utils.import('resource://gre/modules/Promise.jsm');
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
|
||||
Components.utils.import('chrome://shumway/content/SpecialInflate.jsm');
|
||||
Components.utils.import('chrome://shumway/content/SpecialStorage.jsm');
|
||||
Components.utils.import('chrome://shumway/content/RtmpUtils.jsm');
|
||||
Components.utils.import('chrome://shumway/content/ExternalInterface.jsm');
|
||||
Components.utils.import('chrome://shumway/content/FileLoader.jsm');
|
||||
Components.utils.import('chrome://shumway/content/LocalConnection.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'ShumwayTelemetry',
|
||||
'resource://shumway/ShumwayTelemetry.jsm');
|
||||
|
||||
const MAX_USER_INPUT_TIMEOUT = 250; // ms
|
||||
|
||||
function getBoolPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function getCharPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getCharPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function log(aMsg) {
|
||||
let msg = 'ShumwayCom.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
|
||||
Services.console.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
function sanitizeTelemetryArgs(args) {
|
||||
var request = {
|
||||
topic: String(args.topic)
|
||||
};
|
||||
switch (request.topic) {
|
||||
case 'firstFrame':
|
||||
break;
|
||||
case 'parseInfo':
|
||||
request.info = {
|
||||
parseTime: +args.parseTime,
|
||||
size: +args.bytesTotal,
|
||||
swfVersion: args.swfVersion | 0,
|
||||
frameRate: +args.frameRate,
|
||||
width: args.width | 0,
|
||||
height: args.height | 0,
|
||||
bannerType: args.bannerType | 0,
|
||||
isAvm2: !!args.isAvm2
|
||||
};
|
||||
break;
|
||||
case 'feature':
|
||||
request.featureType = args.feature | 0;
|
||||
break;
|
||||
case 'loadResource':
|
||||
request.resultType = args.resultType | 0;
|
||||
break;
|
||||
case 'error':
|
||||
request.errorType = args.error | 0;
|
||||
break;
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
function sanitizeLoadFileArgs(args) {
|
||||
return {
|
||||
url: String(args.url || ''),
|
||||
checkPolicyFile: !!args.checkPolicyFile,
|
||||
sessionId: +args.sessionId,
|
||||
limit: +args.limit || 0,
|
||||
mimeType: String(args.mimeType || ''),
|
||||
method: (args.method + '') || 'GET',
|
||||
postData: args.postData || null
|
||||
};
|
||||
}
|
||||
|
||||
function sanitizeExternalComArgs(args) {
|
||||
var request = {
|
||||
action: String(args.action)
|
||||
};
|
||||
switch (request.action) {
|
||||
case 'eval':
|
||||
request.expression = String(args.expression);
|
||||
break;
|
||||
case 'call':
|
||||
request.expression = String(args.request);
|
||||
break;
|
||||
case 'register':
|
||||
case 'unregister':
|
||||
request.functionName = String(args.functionName);
|
||||
break;
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
var cloneIntoFromContent = (function () {
|
||||
// waiveXrays are used due to bug 1150771, checking if we are affected
|
||||
// TODO remove workaround after Firefox 40 is released (2015-08-11)
|
||||
let sandbox1 = new Components.utils.Sandbox(null);
|
||||
let sandbox2 = new Components.utils.Sandbox(null);
|
||||
let arg = Components.utils.evalInSandbox('({buf: new ArrayBuffer(2)})', sandbox1);
|
||||
let clonedArg = Components.utils.cloneInto(arg, sandbox2);
|
||||
if (!Components.utils.waiveXrays(clonedArg).buf) {
|
||||
return function (obj, contentSandbox) {
|
||||
return Components.utils.cloneInto(
|
||||
Components.utils.waiveXrays(obj), contentSandbox);
|
||||
};
|
||||
}
|
||||
|
||||
return function (obj, contentSandbox) {
|
||||
return Components.utils.cloneInto(obj, contentSandbox);
|
||||
};
|
||||
})();
|
||||
|
||||
var ShumwayEnvironment = {
|
||||
DEBUG: 'debug',
|
||||
DEVELOPMENT: 'dev',
|
||||
RELEASE: 'release',
|
||||
TEST: 'test'
|
||||
};
|
||||
|
||||
var ShumwayCom = {
|
||||
environment: getCharPref('shumway.environment', 'dev'),
|
||||
|
||||
createAdapter: function (content, callbacks, hooks) {
|
||||
// Exposing ShumwayCom object/adapter to the unprivileged content -- setting
|
||||
// up Xray wrappers.
|
||||
var wrapped = {
|
||||
environment: ShumwayCom.environment,
|
||||
|
||||
enableDebug: function () {
|
||||
callbacks.enableDebug()
|
||||
},
|
||||
|
||||
fallback: function () {
|
||||
callbacks.sendMessage('fallback', null, false);
|
||||
},
|
||||
|
||||
getSettings: function () {
|
||||
return Components.utils.cloneInto(
|
||||
callbacks.sendMessage('getSettings', null, true), content);
|
||||
},
|
||||
|
||||
getPluginParams: function () {
|
||||
return Components.utils.cloneInto(
|
||||
callbacks.sendMessage('getPluginParams', null, true), content);
|
||||
},
|
||||
|
||||
reportIssue: function () {
|
||||
callbacks.sendMessage('reportIssue', null, false);
|
||||
},
|
||||
|
||||
reportTelemetry: function (args) {
|
||||
var request = sanitizeTelemetryArgs(args);
|
||||
callbacks.sendMessage('reportTelemetry', request, false);
|
||||
},
|
||||
|
||||
setupGfxComBridge: function (gfxWindow) {
|
||||
// Creates ShumwayCom adapter for the gfx iframe exposing only subset
|
||||
// of the privileged function. Removing Xrays to setup the ShumwayCom
|
||||
// property and for usage as a sandbox for cloneInto operations.
|
||||
var gfxContent = gfxWindow.contentWindow.wrappedJSObject;
|
||||
ShumwayCom.createGfxAdapter(gfxContent, callbacks, hooks);
|
||||
|
||||
setupUserInput(gfxWindow.contentWindow, callbacks);
|
||||
},
|
||||
|
||||
setupPlayerComBridge: function (playerWindow) {
|
||||
// Creates ShumwayCom adapter for the player iframe exposing only subset
|
||||
// of the privileged function. Removing Xrays to setup the ShumwayCom
|
||||
// property and for usage as a sandbox for cloneInto operations.
|
||||
var playerContent = playerWindow.contentWindow.wrappedJSObject;
|
||||
ShumwayCom.createPlayerAdapter(playerContent, callbacks, hooks);
|
||||
}
|
||||
};
|
||||
|
||||
var shumwayComAdapter = Components.utils.cloneInto(wrapped, content, {cloneFunctions:true});
|
||||
content.ShumwayCom = shumwayComAdapter;
|
||||
},
|
||||
|
||||
createGfxAdapter: function (content, callbacks, hooks) {
|
||||
// Exposing ShumwayCom object/adapter to the unprivileged content -- setting
|
||||
// up Xray wrappers.
|
||||
var wrapped = {
|
||||
environment: ShumwayCom.environment,
|
||||
|
||||
setFullscreen: function (value) {
|
||||
value = !!value;
|
||||
callbacks.sendMessage('setFullscreen', value, false);
|
||||
},
|
||||
|
||||
reportTelemetry: function (args) {
|
||||
var request = sanitizeTelemetryArgs(args);
|
||||
callbacks.sendMessage('reportTelemetry', request, false);
|
||||
},
|
||||
|
||||
postAsyncMessage: function (msg) {
|
||||
if (hooks.onPlayerAsyncMessageCallback) {
|
||||
hooks.onPlayerAsyncMessageCallback(msg);
|
||||
}
|
||||
},
|
||||
|
||||
setSyncMessageCallback: function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
log('error: attempt to set non-callable as callback in setSyncMessageCallback');
|
||||
return;
|
||||
}
|
||||
hooks.onGfxSyncMessageCallback = function (msg, sandbox) {
|
||||
var reclonedMsg = cloneIntoFromContent(msg, content);
|
||||
var result = callback(reclonedMsg);
|
||||
return cloneIntoFromContent(result, sandbox);
|
||||
};
|
||||
},
|
||||
|
||||
setAsyncMessageCallback: function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
log('error: attempt to set non-callable as callback in setAsyncMessageCallback');
|
||||
return;
|
||||
}
|
||||
hooks.onGfxAsyncMessageCallback = function (msg) {
|
||||
var reclonedMsg = cloneIntoFromContent(msg, content);
|
||||
callback(reclonedMsg);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
if (ShumwayCom.environment === ShumwayEnvironment.TEST) {
|
||||
wrapped.processFrame = function () {
|
||||
callbacks.sendMessage('processFrame');
|
||||
};
|
||||
|
||||
wrapped.processFSCommand = function (command, args) {
|
||||
callbacks.sendMessage('processFSCommand', command, args);
|
||||
};
|
||||
|
||||
wrapped.setScreenShotCallback = function (callback) {
|
||||
callbacks.sendMessage('setScreenShotCallback', callback);
|
||||
};
|
||||
}
|
||||
|
||||
var shumwayComAdapter = Components.utils.cloneInto(wrapped, content, {cloneFunctions:true});
|
||||
content.ShumwayCom = shumwayComAdapter;
|
||||
},
|
||||
|
||||
createPlayerAdapter: function (content, callbacks, hooks) {
|
||||
// Exposing ShumwayCom object/adapter to the unprivileged content -- setting
|
||||
// up Xray wrappers.
|
||||
var wrapped = {
|
||||
environment: ShumwayCom.environment,
|
||||
|
||||
externalCom: function (args) {
|
||||
var request = sanitizeExternalComArgs(args);
|
||||
var result = String(callbacks.sendMessage('externalCom', request, true));
|
||||
return result;
|
||||
},
|
||||
|
||||
loadFile: function (args) {
|
||||
var request = sanitizeLoadFileArgs(args);
|
||||
callbacks.sendMessage('loadFile', request, false);
|
||||
},
|
||||
|
||||
abortLoad: function (sessionId) {
|
||||
sessionId = sessionId|0;
|
||||
callbacks.sendMessage('abortLoad', sessionId, false);
|
||||
},
|
||||
|
||||
reportTelemetry: function (args) {
|
||||
var request = sanitizeTelemetryArgs(args);
|
||||
callbacks.sendMessage('reportTelemetry', request, false);
|
||||
},
|
||||
|
||||
setClipboard: function (args) {
|
||||
if (typeof args !== 'string') {
|
||||
return; // ignore non-string argument
|
||||
}
|
||||
callbacks.sendMessage('setClipboard', args, false);
|
||||
},
|
||||
|
||||
navigateTo: function (args) {
|
||||
var request = {
|
||||
url: String(args.url || ''),
|
||||
target: String(args.target || '')
|
||||
};
|
||||
callbacks.sendMessage('navigateTo', request, false);
|
||||
},
|
||||
|
||||
loadSystemResource: function (id) {
|
||||
loadShumwaySystemResource(id).then(function (data) {
|
||||
if (onSystemResourceCallback) {
|
||||
onSystemResourceCallback(id, Components.utils.cloneInto(data, content));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
sendSyncMessage: function (msg) {
|
||||
var result;
|
||||
if (hooks.onGfxSyncMessageCallback) {
|
||||
result = hooks.onGfxSyncMessageCallback(msg, content);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
postAsyncMessage: function (msg) {
|
||||
if (hooks.onGfxAsyncMessageCallback) {
|
||||
hooks.onGfxAsyncMessageCallback(msg);
|
||||
}
|
||||
},
|
||||
|
||||
setAsyncMessageCallback: function (callback) {
|
||||
if (typeof callback !== 'function') {
|
||||
log('error: attempt to set non-callable as callback in setAsyncMessageCallback');
|
||||
return;
|
||||
}
|
||||
hooks.onPlayerAsyncMessageCallback = function (msg) {
|
||||
var reclonedMsg = cloneIntoFromContent(msg, content);
|
||||
callback(reclonedMsg);
|
||||
};
|
||||
},
|
||||
|
||||
createSpecialStorage: function () {
|
||||
var environment = callbacks.getEnvironment();
|
||||
return SpecialStorageUtils.createWrappedSpecialStorage(content,
|
||||
environment.swfUrl, environment.privateBrowsing);
|
||||
},
|
||||
|
||||
getWeakMapKeys: function (weakMap) {
|
||||
var keys = ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(weakMap);
|
||||
var result = new content.Array();
|
||||
keys.forEach(function (key) {
|
||||
result.push(key);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
setLoadFileCallback: function (callback) {
|
||||
if (callback !== null && typeof callback !== 'function') {
|
||||
return;
|
||||
}
|
||||
onLoadFileCallback = callback;
|
||||
},
|
||||
setExternalCallback: function (callback) {
|
||||
if (callback !== null && typeof callback !== 'function') {
|
||||
return;
|
||||
}
|
||||
onExternalCallback = callback;
|
||||
},
|
||||
setSystemResourceCallback: function (callback) {
|
||||
if (callback !== null && typeof callback !== 'function') {
|
||||
return;
|
||||
}
|
||||
onSystemResourceCallback = callback;
|
||||
},
|
||||
|
||||
getLocalConnectionService: function() {
|
||||
if (!wrappedLocalConnectionService) {
|
||||
wrappedLocalConnectionService = new LocalConnectionService(content,
|
||||
callbacks.getEnvironment());
|
||||
}
|
||||
return wrappedLocalConnectionService;
|
||||
}
|
||||
};
|
||||
|
||||
// Exposing createSpecialInflate function for DEFLATE stream decoding using
|
||||
// Gecko API.
|
||||
if (SpecialInflateUtils.isSpecialInflateEnabled) {
|
||||
wrapped.createSpecialInflate = function () {
|
||||
return SpecialInflateUtils.createWrappedSpecialInflate(content);
|
||||
};
|
||||
}
|
||||
|
||||
// Exposing createRtmpSocket/createRtmpXHR functions to support RTMP stream
|
||||
// functionality.
|
||||
if (RtmpUtils.isRtmpEnabled) {
|
||||
wrapped.createRtmpSocket = function (params) {
|
||||
return RtmpUtils.createSocket(content, params);
|
||||
};
|
||||
wrapped.createRtmpXHR = function () {
|
||||
return RtmpUtils.createXHR(content);
|
||||
};
|
||||
}
|
||||
|
||||
if (ShumwayCom.environment === ShumwayEnvironment.TEST) {
|
||||
wrapped.print = function(msg) {
|
||||
callbacks.sendMessage('print', msg);
|
||||
}
|
||||
}
|
||||
|
||||
var onSystemResourceCallback = null;
|
||||
var onExternalCallback = null;
|
||||
var onLoadFileCallback = null;
|
||||
|
||||
var wrappedLocalConnectionService = null;
|
||||
|
||||
hooks.onLoadFileCallback = function (arg) {
|
||||
if (onLoadFileCallback) {
|
||||
onLoadFileCallback(Components.utils.cloneInto(arg, content));
|
||||
}
|
||||
};
|
||||
hooks.onExternalCallback = function (call) {
|
||||
if (onExternalCallback) {
|
||||
return onExternalCallback(Components.utils.cloneInto(call, content));
|
||||
}
|
||||
};
|
||||
|
||||
var shumwayComAdapter = Components.utils.cloneInto(wrapped, content, {cloneFunctions:true});
|
||||
content.ShumwayCom = shumwayComAdapter;
|
||||
},
|
||||
|
||||
createActions: function (startupInfo, window, document) {
|
||||
return new ShumwayChromeActions(startupInfo, window, document);
|
||||
}
|
||||
};
|
||||
|
||||
function loadShumwaySystemResource(id) {
|
||||
var url, type;
|
||||
switch (id) {
|
||||
case 0: // BuiltinAbc
|
||||
url = 'resource://shumway/libs/builtin.abc';
|
||||
type = 'arraybuffer';
|
||||
break;
|
||||
case 1: // PlayerglobalAbcs
|
||||
url = 'resource://shumway/playerglobal/playerglobal.abcs';
|
||||
type = 'arraybuffer';
|
||||
break;
|
||||
case 2: // PlayerglobalManifest
|
||||
url = 'resource://shumway/playerglobal/playerglobal.json';
|
||||
type = 'json';
|
||||
break;
|
||||
default:
|
||||
return Promise.reject('Unsupported system resource id');
|
||||
}
|
||||
|
||||
var deferred = Promise.defer();
|
||||
|
||||
var xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = type;
|
||||
xhr.onload = function () {
|
||||
deferred.resolve(xhr.response);
|
||||
};
|
||||
xhr.send(null);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function setupUserInput(contentWindow, callbacks) {
|
||||
function notifyUserInput() {
|
||||
callbacks.sendMessage('userInput', null, true);
|
||||
}
|
||||
|
||||
// Ignoring the untrusted events by providing the 4th argument for addEventListener.
|
||||
contentWindow.document.addEventListener('mousedown', notifyUserInput, true, false);
|
||||
contentWindow.document.addEventListener('mouseup', notifyUserInput, true, false);
|
||||
contentWindow.document.addEventListener('keydown', notifyUserInput, true, false);
|
||||
contentWindow.document.addEventListener('keyup', notifyUserInput, true, false);
|
||||
}
|
||||
|
||||
// All the privileged actions.
|
||||
function ShumwayChromeActions(startupInfo, window, document) {
|
||||
this.url = startupInfo.url;
|
||||
this.objectParams = startupInfo.objectParams;
|
||||
this.movieParams = startupInfo.movieParams;
|
||||
this.baseUrl = startupInfo.baseUrl;
|
||||
this.isOverlay = startupInfo.isOverlay;
|
||||
this.embedTag = startupInfo.embedTag;
|
||||
this.isPausedAtStart = startupInfo.isPausedAtStart;
|
||||
this.initStartTime = startupInfo.initStartTime;
|
||||
this.window = window;
|
||||
this.document = document;
|
||||
this.allowScriptAccess = startupInfo.allowScriptAccess;
|
||||
this.lastUserInput = 0;
|
||||
this.telemetry = {
|
||||
startTime: Date.now(),
|
||||
features: [],
|
||||
errors: []
|
||||
};
|
||||
|
||||
this.fileLoader = new FileLoader(startupInfo.url, startupInfo.baseUrl, startupInfo.refererUrl,
|
||||
function (args) { this.onLoadFileCallback(args); }.bind(this));
|
||||
this.onLoadFileCallback = null;
|
||||
|
||||
this.externalInterface = null;
|
||||
this.onExternalCallback = null;
|
||||
}
|
||||
|
||||
ShumwayChromeActions.prototype = {
|
||||
// The method is created for convenience of routing messages from the OOP
|
||||
// handler or remote debugger adapter. All method calls are originated from
|
||||
// the ShumwayCom adapter (see above), or from the debugger adapter.
|
||||
// See viewerWrapper.js for these usages near sendMessage calls.
|
||||
invoke: function (name, args) {
|
||||
return this[name].call(this, args);
|
||||
},
|
||||
|
||||
getBoolPref: function (data) {
|
||||
if (!/^shumway\./.test(data.pref)) {
|
||||
return null;
|
||||
}
|
||||
return getBoolPref(data.pref, data.def);
|
||||
},
|
||||
|
||||
getSettings: function getSettings() {
|
||||
return {
|
||||
compilerSettings: {
|
||||
appCompiler: getBoolPref('shumway.appCompiler', true),
|
||||
sysCompiler: getBoolPref('shumway.sysCompiler', false),
|
||||
verifier: getBoolPref('shumway.verifier', true)
|
||||
},
|
||||
playerSettings: {
|
||||
turboMode: getBoolPref('shumway.turboMode', false),
|
||||
hud: getBoolPref('shumway.hud', false),
|
||||
forceHidpi: getBoolPref('shumway.force_hidpi', false)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getPluginParams: function getPluginParams() {
|
||||
return {
|
||||
url: this.url,
|
||||
baseUrl : this.baseUrl,
|
||||
movieParams: this.movieParams,
|
||||
objectParams: this.objectParams,
|
||||
isOverlay: this.isOverlay,
|
||||
isPausedAtStart: this.isPausedAtStart,
|
||||
initStartTime: this.initStartTime,
|
||||
isDebuggerEnabled: getBoolPref('shumway.debug.enabled', false)
|
||||
};
|
||||
},
|
||||
|
||||
loadFile: function loadFile(data) {
|
||||
this.fileLoader.load(data);
|
||||
},
|
||||
|
||||
abortLoad: function abortLoad(sessionId) {
|
||||
this.fileLoader.abort(sessionId);
|
||||
},
|
||||
|
||||
navigateTo: function (data) {
|
||||
// Our restrictions are a little bit different from Flash's: let's enable
|
||||
// only http(s) and only when script execution is allowed.
|
||||
// See https://helpx.adobe.com/flash/kb/control-access-scripts-host-web.html
|
||||
var url = data.url || 'about:blank';
|
||||
var target = data.target || '_self';
|
||||
var isWhitelistedProtocol = /^(http|https):\/\//i.test(url);
|
||||
if (!isWhitelistedProtocol || !this.allowScriptAccess) {
|
||||
return;
|
||||
}
|
||||
// ...and only when user input is in-progress.
|
||||
if (!this.isUserInputInProgress()) {
|
||||
return;
|
||||
}
|
||||
var embedTag = this.embedTag;
|
||||
var window = embedTag ? embedTag.ownerDocument.defaultView : this.window;
|
||||
window.open(url, target);
|
||||
},
|
||||
|
||||
fallback: function(automatic) {
|
||||
automatic = !!automatic;
|
||||
var event = this.document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('shumwayFallback', true, true, {
|
||||
automatic: automatic
|
||||
});
|
||||
this.window.dispatchEvent(event);
|
||||
},
|
||||
|
||||
userInput: function() {
|
||||
// Recording time of last user input for isUserInputInProgress below.
|
||||
this.lastUserInput = Date.now();
|
||||
},
|
||||
|
||||
isUserInputInProgress: function () {
|
||||
// We don't trust our Shumway non-privileged code just yet to verify the
|
||||
// user input -- using userInput function above to track that.
|
||||
if ((Date.now() - this.lastUserInput) > MAX_USER_INPUT_TIMEOUT) {
|
||||
return false;
|
||||
}
|
||||
// TODO other security checks?
|
||||
return true;
|
||||
},
|
||||
|
||||
setClipboard: function (data) {
|
||||
if (!this.isUserInputInProgress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let clipboard = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
|
||||
.getService(Components.interfaces.nsIClipboardHelper);
|
||||
clipboard.copyString(data);
|
||||
},
|
||||
|
||||
setFullscreen: function (enabled) {
|
||||
if (!this.isUserInputInProgress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var target = this.embedTag || this.document.body;
|
||||
if (enabled) {
|
||||
target.mozRequestFullScreen();
|
||||
} else {
|
||||
target.ownerDocument.mozCancelFullScreen();
|
||||
}
|
||||
},
|
||||
|
||||
reportTelemetry: function (request) {
|
||||
switch (request.topic) {
|
||||
case 'firstFrame':
|
||||
var time = Date.now() - this.telemetry.startTime;
|
||||
ShumwayTelemetry.onFirstFrame(time);
|
||||
break;
|
||||
case 'parseInfo':
|
||||
ShumwayTelemetry.onParseInfo(request.info);
|
||||
break;
|
||||
case 'feature':
|
||||
var featureType = request.featureType;
|
||||
var MIN_FEATURE_TYPE = 0, MAX_FEATURE_TYPE = 999;
|
||||
if (featureType >= MIN_FEATURE_TYPE && featureType <= MAX_FEATURE_TYPE &&
|
||||
!this.telemetry.features[featureType]) {
|
||||
this.telemetry.features[featureType] = true; // record only one feature per SWF
|
||||
ShumwayTelemetry.onFeature(featureType);
|
||||
}
|
||||
break;
|
||||
case 'loadResource':
|
||||
var resultType = request.resultType;
|
||||
var MIN_RESULT_TYPE = 0, MAX_RESULT_TYPE = 10;
|
||||
if (resultType >= MIN_RESULT_TYPE && resultType <= MAX_RESULT_TYPE) {
|
||||
ShumwayTelemetry.onLoadResource(resultType);
|
||||
}
|
||||
break;
|
||||
case 'error':
|
||||
var errorType = request.errorType;
|
||||
var MIN_ERROR_TYPE = 0, MAX_ERROR_TYPE = 2;
|
||||
if (errorType >= MIN_ERROR_TYPE && errorType <= MAX_ERROR_TYPE &&
|
||||
!this.telemetry.errors[errorType]) {
|
||||
this.telemetry.errors[errorType] = true; // record only one report per SWF
|
||||
ShumwayTelemetry.onError(errorType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
reportIssue: function (exceptions) {
|
||||
var urlTemplate = "https://bugzilla.mozilla.org/enter_bug.cgi?op_sys=All&priority=--" +
|
||||
"&rep_platform=All&target_milestone=---&version=Trunk&product=Firefox" +
|
||||
"&component=Shumway&short_desc=&comment={comment}" +
|
||||
"&bug_file_loc={url}";
|
||||
var windowUrl = this.window.parent.location.href + '';
|
||||
var url = urlTemplate.split('{url}').join(encodeURIComponent(windowUrl));
|
||||
var params = {
|
||||
swf: encodeURIComponent(this.url)
|
||||
};
|
||||
getVersionInfo().then(function (versions) {
|
||||
params.versions = versions;
|
||||
}).then(function () {
|
||||
var ffbuild = params.versions.geckoVersion + ' (' + params.versions.geckoBuildID + ')';
|
||||
//params.exceptions = encodeURIComponent(exceptions);
|
||||
var comment = '+++ Initially filed via the problem reporting functionality in Shumway +++\n' +
|
||||
'Please add any further information that you deem helpful here:\n\n\n\n' +
|
||||
'----------------------\n\n' +
|
||||
'Technical Information:\n' +
|
||||
'Firefox version: ' + ffbuild + '\n' +
|
||||
'Shumway version: ' + params.versions.shumwayVersion;
|
||||
url = url.split('{comment}').join(encodeURIComponent(comment));
|
||||
this.window.open(url);
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
externalCom: function (data) {
|
||||
if (!this.allowScriptAccess)
|
||||
return;
|
||||
|
||||
// TODO check more security stuff ?
|
||||
if (!this.externalInterface) {
|
||||
var parentWindow = this.window.parent; // host page -- parent of PlayPreview frame
|
||||
var embedTag = this.embedTag;
|
||||
this.externalInterface = new ExternalInterface(parentWindow, embedTag, function (call) {
|
||||
return this.onExternalCallback(call);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return this.externalInterface.processAction(data);
|
||||
},
|
||||
|
||||
postMessage: function (type, data) {
|
||||
var embedTag = this.embedTag;
|
||||
var event = embedTag.ownerDocument.createEvent('CustomEvent');
|
||||
var detail = Components.utils.cloneInto({ type: type, data: data }, embedTag.ownerDocument.wrappedJSObject);
|
||||
event.initCustomEvent('message', false, false, detail);
|
||||
embedTag.dispatchEvent(event);
|
||||
},
|
||||
|
||||
processFrame: function () {
|
||||
this.postMessage('processFrame');
|
||||
},
|
||||
|
||||
processFSCommand: function (command, data) {
|
||||
this.postMessage('processFSCommand', { command: command, data: data });
|
||||
},
|
||||
|
||||
print: function (msg) {
|
||||
this.postMessage('print', msg);
|
||||
},
|
||||
|
||||
setScreenShotCallback: function (callback) {
|
||||
var embedTag = this.embedTag;
|
||||
Components.utils.exportFunction(function () {
|
||||
// `callback` can be wrapped in a CPOW and thus cause a slow synchronous cross-process operation.
|
||||
var result = callback();
|
||||
return Components.utils.cloneInto(result, embedTag.ownerDocument);
|
||||
}, embedTag.wrappedJSObject, {defineAs: 'getCanvasData'});
|
||||
}
|
||||
};
|
||||
|
||||
function getVersionInfo() {
|
||||
var deferred = Promise.defer();
|
||||
var versionInfo = {
|
||||
geckoVersion: 'unknown',
|
||||
geckoBuildID: 'unknown',
|
||||
shumwayVersion: 'unknown'
|
||||
};
|
||||
try {
|
||||
var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Components.interfaces.nsIXULAppInfo);
|
||||
versionInfo.geckoVersion = appInfo.version;
|
||||
versionInfo.geckoBuildID = appInfo.appBuildID;
|
||||
} catch (e) {
|
||||
log('Error encountered while getting platform version info: ' + e);
|
||||
}
|
||||
var xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Components.interfaces.nsIXMLHttpRequest);
|
||||
xhr.open('GET', 'resource://shumway/version.txt', true);
|
||||
xhr.overrideMimeType('text/plain');
|
||||
xhr.onload = function () {
|
||||
try {
|
||||
// Trying to merge version.txt lines into something like:
|
||||
// "version (sha) details"
|
||||
var lines = xhr.responseText.split(/\n/g);
|
||||
lines[1] = '(' + lines[1] + ')';
|
||||
versionInfo.shumwayVersion = lines.join(' ');
|
||||
} catch (e) {
|
||||
log('Error while parsing version info: ' + e);
|
||||
}
|
||||
deferred.resolve(versionInfo);
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
log('Error while reading version info: ' + xhr.error);
|
||||
deferred.resolve(versionInfo);
|
||||
};
|
||||
xhr.send();
|
||||
|
||||
return deferred.promise;
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['SpecialInflate', 'SpecialInflateUtils'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
function SimpleStreamListener() {
|
||||
this.binaryStream = Cc['@mozilla.org/binaryinputstream;1']
|
||||
.createInstance(Ci.nsIBinaryInputStream);
|
||||
this.onData = null;
|
||||
this.buffer = null;
|
||||
}
|
||||
SimpleStreamListener.prototype = {
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Ci.nsIStreamListener) ||
|
||||
iid.equals(Ci.nsIRequestObserver) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
onStartRequest: function (aRequest, aContext) {
|
||||
return Cr.NS_OK;
|
||||
},
|
||||
onStopRequest: function (aRequest, aContext, sStatusCode) {
|
||||
return Cr.NS_OK;
|
||||
},
|
||||
onDataAvailable: function (aRequest, aContext, aInputStream, aOffset, aCount) {
|
||||
this.binaryStream.setInputStream(aInputStream);
|
||||
if (!this.buffer || aCount > this.buffer.byteLength) {
|
||||
this.buffer = new ArrayBuffer(aCount);
|
||||
}
|
||||
this.binaryStream.readArrayBuffer(aCount, this.buffer);
|
||||
this.onData(new Uint8Array(this.buffer, 0, aCount));
|
||||
return Cr.NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
function SpecialInflate() {
|
||||
var listener = new SimpleStreamListener();
|
||||
listener.onData = function (data) {
|
||||
this.onData(data);
|
||||
}.bind(this);
|
||||
|
||||
var converterService = Cc["@mozilla.org/streamConverters;1"].getService(Ci.nsIStreamConverterService);
|
||||
var converter = converterService.asyncConvertData("deflate", "uncompressed", listener, null);
|
||||
converter.onStartRequest(null, null);
|
||||
this.converter = converter;
|
||||
|
||||
var binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream);
|
||||
var pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
|
||||
pipe.init(true, true, 0, 0xFFFFFFFF, null);
|
||||
binaryStream.setOutputStream(pipe.outputStream);
|
||||
this.binaryStream = binaryStream;
|
||||
|
||||
this.pipeInputStream = pipe.inputStream;
|
||||
|
||||
this.onData = null;
|
||||
}
|
||||
SpecialInflate.prototype = {
|
||||
push: function (data) {
|
||||
this.binaryStream.writeByteArray(data, data.length);
|
||||
this.converter.onDataAvailable(null, null, this.pipeInputStream, 0, data.length);
|
||||
},
|
||||
close: function () {
|
||||
this.binaryStream.close();
|
||||
this.converter.onStopRequest(null, null, Cr.NS_OK);
|
||||
}
|
||||
};
|
||||
|
||||
var SpecialInflateUtils = {
|
||||
get isSpecialInflateEnabled() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref('shumway.specialInflate');
|
||||
} catch (ex) {
|
||||
return false; // TODO true;
|
||||
}
|
||||
},
|
||||
|
||||
createWrappedSpecialInflate: function (sandbox) {
|
||||
var wrapped = new SpecialInflate();
|
||||
var wrapperOnData;
|
||||
wrapped.onData = function(data) {
|
||||
if (wrapperOnData) {
|
||||
wrapperOnData(Components.utils.cloneInto(data, sandbox));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// We will return object created in the sandbox/content, with some exposed
|
||||
// properties/methods, so we can send data between wrapped object and
|
||||
// and sandbox/content.
|
||||
var wrapper = Components.utils.cloneInto({
|
||||
setDataCallback: function (callback) {
|
||||
wrapperOnData = callback;
|
||||
},
|
||||
|
||||
push: function (data) {
|
||||
// Uint8Array is expected in the data parameter.
|
||||
// SpecialInflate.push() fails with other argument types.
|
||||
return wrapped.push(data);
|
||||
},
|
||||
close: function () {
|
||||
return wrapped.close();
|
||||
}
|
||||
}, sandbox, {cloneFunctions:true});
|
||||
return wrapper;
|
||||
}
|
||||
};
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['SpecialStorageUtils'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var SpecialStorageUtils = {
|
||||
createWrappedSpecialStorage: function (sandbox, swfUrl, privateBrowsing) {
|
||||
// Creating internal localStorage object based on url and privateBrowsing setting.
|
||||
var uri = Services.io.newURI(swfUrl, null, null);
|
||||
var ssm = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager);
|
||||
var principal = ssm.createCodebasePrincipal(uri, {});
|
||||
var dsm = Components.classes["@mozilla.org/dom/localStorage-manager;1"]
|
||||
.getService(Components.interfaces.nsIDOMStorageManager);
|
||||
var storage = dsm.createStorage(null, principal, privateBrowsing);
|
||||
|
||||
// We will return object created in the sandbox/content, with some exposed
|
||||
// properties/methods, so we can send data between wrapped object and
|
||||
// and sandbox/content.
|
||||
var wrapper = Components.utils.cloneInto({
|
||||
getItem: function (key) {
|
||||
return storage.getItem(key);
|
||||
},
|
||||
setItem: function (key, value) {
|
||||
storage.setItem(key, value);
|
||||
},
|
||||
removeItem: function (key) {
|
||||
storage.removeItem(key);
|
||||
}
|
||||
}, sandbox, {cloneFunctions:true});
|
||||
return wrapper;
|
||||
}
|
||||
};
|
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ['getStartupInfo', 'parseQueryString', 'isContentWindowPrivate'];
|
||||
|
||||
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
Components.utils.import('chrome://shumway/content/ShumwayCom.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
|
||||
'resource://gre/modules/PrivateBrowsingUtils.jsm');
|
||||
|
||||
function flashUnescape(s) {
|
||||
return decodeURIComponent(s.split('+').join(' '));
|
||||
}
|
||||
|
||||
function parseQueryString(qs) {
|
||||
if (!qs)
|
||||
return {};
|
||||
|
||||
if (qs.charAt(0) == '?')
|
||||
qs = qs.slice(1);
|
||||
|
||||
var values = qs.split('&');
|
||||
var obj = {};
|
||||
for (var i = 0; i < values.length; i++) {
|
||||
var pair = values[i], j = pair.indexOf('=');
|
||||
if (j < 0) {
|
||||
continue; // skipping invalid values
|
||||
}
|
||||
var key = pair.substring(0, j), value = pair.substring(j + 1);
|
||||
obj[flashUnescape(key)] = flashUnescape(value);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function isContentWindowPrivate(win) {
|
||||
if (!('isContentWindowPrivate' in PrivateBrowsingUtils)) {
|
||||
return PrivateBrowsingUtils.isWindowPrivate(win);
|
||||
}
|
||||
return PrivateBrowsingUtils.isContentWindowPrivate(win);
|
||||
}
|
||||
|
||||
function isStandardEmbedWrapper(embedElement) {
|
||||
try {
|
||||
if (embedElement.tagName !== 'EMBED') {
|
||||
return false;
|
||||
}
|
||||
var swfUrl = embedElement.src;
|
||||
var document = embedElement.ownerDocument;
|
||||
var docUrl = document.location.href;
|
||||
if (swfUrl !== docUrl) {
|
||||
return false; // document URL shall match embed src
|
||||
}
|
||||
if (document.body.children.length !== 1 ||
|
||||
document.body.firstChild !== embedElement) {
|
||||
return false; // not the only child
|
||||
}
|
||||
if (document.defaultView.top !== document.defaultView) {
|
||||
return false; // not a top window
|
||||
}
|
||||
// Looks like a standard wrapper
|
||||
return true;
|
||||
} catch (e) {
|
||||
// Declare that is not a standard fullscreen plugin wrapper for any error
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isScriptAllowed(allowScriptAccessParameter, url, pageUrl) {
|
||||
if (!allowScriptAccessParameter) {
|
||||
allowScriptAccessParameter = 'sameDomain';
|
||||
}
|
||||
var allowScriptAccess = false;
|
||||
switch (allowScriptAccessParameter.toLowerCase()) { // ignoring case here
|
||||
case 'always':
|
||||
allowScriptAccess = true;
|
||||
break;
|
||||
case 'never':
|
||||
allowScriptAccess = false;
|
||||
break;
|
||||
default: // 'samedomain'
|
||||
if (!pageUrl)
|
||||
break;
|
||||
try {
|
||||
// checking if page is in same domain (? same protocol and port)
|
||||
allowScriptAccess =
|
||||
Services.io.newURI('/', null, Services.io.newURI(pageUrl, null, null)).spec ==
|
||||
Services.io.newURI('/', null, Services.io.newURI(url, null, null)).spec;
|
||||
} catch (ex) {}
|
||||
break;
|
||||
}
|
||||
return allowScriptAccess;
|
||||
}
|
||||
|
||||
function getStartupInfo(element) {
|
||||
var initStartTime = Date.now();
|
||||
var baseUrl;
|
||||
var pageUrl;
|
||||
var isOverlay = false;
|
||||
var objectParams = {};
|
||||
|
||||
// Getting absolute URL from the EMBED tag
|
||||
var url = element.srcURI && element.srcURI.spec;
|
||||
|
||||
pageUrl = element.ownerDocument.location.href; // proper page url?
|
||||
|
||||
var tagName = element.nodeName;
|
||||
if (tagName == 'EMBED') {
|
||||
for (var i = 0; i < element.attributes.length; ++i) {
|
||||
var paramName = element.attributes[i].localName.toLowerCase();
|
||||
objectParams[paramName] = element.attributes[i].value;
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < element.childNodes.length; ++i) {
|
||||
var paramElement = element.childNodes[i];
|
||||
if (paramElement.nodeType != 1 ||
|
||||
paramElement.nodeName != 'PARAM') {
|
||||
continue;
|
||||
}
|
||||
var paramName = paramElement.getAttribute('name').toLowerCase();
|
||||
objectParams[paramName] = paramElement.getAttribute('value');
|
||||
}
|
||||
}
|
||||
|
||||
baseUrl = pageUrl;
|
||||
if (objectParams.base) {
|
||||
try {
|
||||
// Verifying base URL, passed in object parameters. It shall be okay to
|
||||
// ignore bad/corrupted base.
|
||||
var parsedPageUrl = Services.io.newURI(pageUrl, null, null);
|
||||
baseUrl = Services.io.newURI(objectParams.base, null, parsedPageUrl).spec;
|
||||
} catch (e) { /* it's okay to ignore any exception */ }
|
||||
}
|
||||
|
||||
var movieParams = {};
|
||||
if (objectParams.flashvars) {
|
||||
movieParams = parseQueryString(objectParams.flashvars);
|
||||
}
|
||||
var queryStringMatch = url && /\?([^#]+)/.exec(url);
|
||||
if (queryStringMatch) {
|
||||
var queryStringParams = parseQueryString(queryStringMatch[1]);
|
||||
for (var i in queryStringParams) {
|
||||
if (!(i in movieParams)) {
|
||||
movieParams[i] = queryStringParams[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var allowScriptAccess = !!url &&
|
||||
isScriptAllowed(objectParams.allowscriptaccess, url, pageUrl);
|
||||
var isFullscreenSwf = isStandardEmbedWrapper(element);
|
||||
|
||||
var document = element.ownerDocument;
|
||||
var window = document.defaultView;
|
||||
|
||||
var startupInfo = {};
|
||||
startupInfo.window = window;
|
||||
startupInfo.url = url;
|
||||
startupInfo.privateBrowsing = isContentWindowPrivate(window);
|
||||
startupInfo.objectParams = objectParams;
|
||||
startupInfo.movieParams = movieParams;
|
||||
startupInfo.baseUrl = baseUrl || url;
|
||||
startupInfo.isOverlay = isOverlay;
|
||||
startupInfo.refererUrl = !isFullscreenSwf ? baseUrl : null;
|
||||
startupInfo.embedTag = element;
|
||||
startupInfo.initStartTime = initStartTime;
|
||||
startupInfo.allowScriptAccess = allowScriptAccess;
|
||||
startupInfo.pageIndex = 0;
|
||||
return startupInfo;
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
(function contentScriptClosure() {
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cm = Components.manager;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
// we need to use closure here -- we are running in the global context
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var isRemote = Services.appinfo.processType ===
|
||||
Services.appinfo.PROCESS_TYPE_CONTENT;
|
||||
var isStarted = false;
|
||||
|
||||
function startup() {
|
||||
if (isStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
isStarted = true;
|
||||
Cu.import('resource://shumway/ShumwayBootstrapUtils.jsm');
|
||||
ShumwayBootstrapUtils.register();
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
if (!isStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
isStarted = false;
|
||||
ShumwayBootstrapUtils.unregister();
|
||||
Cu.unload('resource://shumway/ShumwayBootstrapUtils.jsm');
|
||||
}
|
||||
|
||||
|
||||
function updateSettings() {
|
||||
let mm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
var results = mm.sendSyncMessage('Shumway:Chrome:isEnabled');
|
||||
var isEnabled = results.some(function (item) {
|
||||
return item;
|
||||
});
|
||||
|
||||
if (isEnabled) {
|
||||
startup();
|
||||
} else {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
if (isRemote && typeof ShumwayBootstrapUtils !== 'undefined') {
|
||||
// Treat content as non-remote when bootstrap.js or ShumwayUtils.jsm
|
||||
// already registered the Shumway components for current content scope.
|
||||
isRemote = false;
|
||||
}
|
||||
|
||||
if (isRemote) {
|
||||
addMessageListener('Shumway:Child:refreshSettings', updateSettings);
|
||||
updateSettings();
|
||||
|
||||
addMessageListener('Shumway:Child:shutdown', function shutdownListener(e) {
|
||||
removeMessageListener('Shumway:Child:refreshSettings', updateSettings);
|
||||
removeMessageListener('Shumway:Child:shutdown', shutdownListener);
|
||||
|
||||
shutdown();
|
||||
});
|
||||
}
|
||||
})();
|
@ -1,56 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2015 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
iframe {
|
||||
position:fixed !important;
|
||||
left:0;top:0;bottom:0;right:0;
|
||||
overflow: hidden;
|
||||
line-height: 0;
|
||||
border: 0px none;
|
||||
}
|
||||
|
||||
body.remoteStopped {
|
||||
background-color: red;
|
||||
}
|
||||
body.remoteDebug {
|
||||
background-color: green;
|
||||
}
|
||||
body.remoteReload {
|
||||
background-color: yellow;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<iframe id="viewer" src="resource://shumway/web/viewer.html" width="100%" height="100%"></iframe>
|
||||
<script src="chrome://shumway/content/content.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
Components.utils.import('resource://gre/modules/Promise.jsm');
|
||||
|
||||
Components.utils.import('chrome://shumway/content/ShumwayCom.jsm');
|
||||
|
||||
var messageManager, viewerReady;
|
||||
// Checking if we loading content.js in the OOP/mozbrowser or jsplugins.
|
||||
// TODO remove mozbrowser logic when we switch to jsplugins only support
|
||||
if (typeof document === 'undefined') { // mozbrowser OOP frame script
|
||||
messageManager = this;
|
||||
viewerReady = Promise.resolve(content);
|
||||
messageManager.sendAsyncMessage('Shumway:constructed', null);
|
||||
} else { // jsplugins instance
|
||||
messageManager = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDocShell)
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIContentFrameMessageManager);
|
||||
|
||||
var viewer = document.getElementById('viewer');
|
||||
viewerReady = new Promise(function (resolve) {
|
||||
viewer.addEventListener('load', function () {
|
||||
messageManager.sendAsyncMessage('Shumway:constructed', null);
|
||||
resolve(viewer.contentWindow);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var externalInterfaceWrapper = {
|
||||
callback: function (call) {
|
||||
if (!shumwayComAdapterHooks.onExternalCallback) {
|
||||
return undefined;
|
||||
}
|
||||
return shumwayComAdapterHooks.onExternalCallback(
|
||||
Components.utils.cloneInto(JSON.parse(call), content));
|
||||
}
|
||||
};
|
||||
|
||||
var shumwayComAdapterHooks = {};
|
||||
|
||||
function sendMessage(action, data, sync) {
|
||||
var detail = {action: action, data: data, sync: sync};
|
||||
if (!sync) {
|
||||
messageManager.sendAsyncMessage('Shumway:message', detail);
|
||||
return;
|
||||
}
|
||||
var result = String(messageManager.sendSyncMessage('Shumway:message', detail));
|
||||
result = result == 'undefined' ? undefined : JSON.parse(result);
|
||||
return Components.utils.cloneInto(result, content);
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
messageManager.sendAsyncMessage('Shumway:enableDebug', null);
|
||||
}
|
||||
|
||||
messageManager.addMessageListener('Shumway:init', function (message) {
|
||||
var environment = message.data;
|
||||
|
||||
messageManager.sendAsyncMessage('Shumway:running', {}, {
|
||||
externalInterface: externalInterfaceWrapper
|
||||
});
|
||||
|
||||
viewerReady.then(function (viewerWindow) {
|
||||
ShumwayCom.createAdapter(viewerWindow.wrappedJSObject, {
|
||||
sendMessage: sendMessage,
|
||||
enableDebug: enableDebug,
|
||||
getEnvironment: function () { return environment; }
|
||||
}, shumwayComAdapterHooks);
|
||||
|
||||
viewerWindow.wrappedJSObject.runViewer();
|
||||
});
|
||||
});
|
||||
|
||||
messageManager.addMessageListener('Shumway:loadFile', function (message) {
|
||||
if (!shumwayComAdapterHooks.onLoadFileCallback) {
|
||||
return;
|
||||
}
|
||||
shumwayComAdapterHooks.onLoadFileCallback(Components.utils.cloneInto(message.data, content));
|
||||
});
|
@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Simple class for synchronous XHR communication.
|
||||
// See also examples/inspector/debug/server.js.
|
||||
|
||||
var PingPongConnection = (function () {
|
||||
function PingPongConnection(url, onlySend) {
|
||||
this.url = url;
|
||||
this.onData = null;
|
||||
this.onError = null;
|
||||
this.currentXhr = null;
|
||||
this.closed = false;
|
||||
|
||||
if (!onlySend) {
|
||||
this.idle();
|
||||
}
|
||||
}
|
||||
|
||||
PingPongConnection.prototype = {
|
||||
idle: function () {
|
||||
function requestIncoming(connection) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', connection.url + '?idle', true);
|
||||
xhr.onload = function () {
|
||||
if (xhr.status === 204 &&
|
||||
xhr.getResponseHeader('X-PingPong-Error') === 'timeout') {
|
||||
requestIncoming(connection);
|
||||
return;
|
||||
}
|
||||
if (xhr.status === 200) {
|
||||
var result;
|
||||
if (connection.onData) {
|
||||
var response = xhr.responseText;
|
||||
result = connection.onData(response ? JSON.parse(response) : undefined);
|
||||
}
|
||||
if (xhr.getResponseHeader('X-PingPong-Async') === '1') {
|
||||
requestIncoming(connection);
|
||||
} else {
|
||||
sendResponse(connection, result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.statusText);
|
||||
}
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.error);
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
connection.currentXhr = xhr;
|
||||
}
|
||||
function sendResponse(connection, result) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', connection.url + '?response', false);
|
||||
xhr.onload = function () {
|
||||
if (xhr.status !== 204) {
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.statusText);
|
||||
}
|
||||
}
|
||||
requestIncoming(connection);
|
||||
};
|
||||
xhr.onerror = function () {
|
||||
if (connection.onError) {
|
||||
connection.onError(xhr.error);
|
||||
}
|
||||
};
|
||||
xhr.send(result === undefined ? '' : JSON.stringify(result));
|
||||
connection.currentXhr = xhr;
|
||||
}
|
||||
requestIncoming(this);
|
||||
},
|
||||
send: function (data, async, timeout) {
|
||||
if (this.closed) {
|
||||
throw new Error('connection closed');
|
||||
}
|
||||
|
||||
async = !!async;
|
||||
timeout |= 0;
|
||||
|
||||
var encoded = data === undefined ? '' : JSON.stringify(data);
|
||||
if (async) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', this.url + '?async', true);
|
||||
xhr.send(encoded);
|
||||
return;
|
||||
} else {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', this.url, false);
|
||||
if (timeout > 0) {
|
||||
xhr.setRequestHeader('X-PingPong-Timeout', timeout);
|
||||
}
|
||||
xhr.send(encoded);
|
||||
if (xhr.status === 204 &&
|
||||
xhr.getResponseHeader('X-PingPong-Error') === 'timeout') {
|
||||
throw new Error('sync request timeout');
|
||||
}
|
||||
var response = xhr.responseText;
|
||||
return response ? JSON.parse(response) : undefined;
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
if (this.currentXhr) {
|
||||
this.currentXhr.abort();
|
||||
this.currentXhr = null;
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
};
|
||||
|
||||
return PingPongConnection;
|
||||
})();
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
Components.utils.import('resource://gre/modules/Promise.jsm');
|
||||
|
||||
Components.utils.import('chrome://shumway/content/StartupInfo.jsm');
|
||||
Components.utils.import('chrome://shumway/content/ShumwayCom.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
|
||||
'resource://gre/modules/PrivateBrowsingUtils.jsm');
|
||||
|
||||
function log(str) {
|
||||
var msg = 'plugin.js: ' + str;
|
||||
Services.console.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
function runViewer() {
|
||||
function handlerOOP() {
|
||||
var frameLoader = pluginElement.frameLoader;
|
||||
var messageManager = frameLoader.messageManager;
|
||||
|
||||
var externalInterface;
|
||||
|
||||
messageManager.addMessageListener('Shumway:running', function (message) {
|
||||
externalInterface = message.objects.externalInterface;
|
||||
});
|
||||
|
||||
messageManager.addMessageListener('Shumway:message', function (message) {
|
||||
var data = message.data;
|
||||
var result = shumwayActions.invoke(data.action, data.data);
|
||||
if (message.sync) {
|
||||
return result === undefined ? 'undefined' : JSON.stringify(result);
|
||||
}
|
||||
});
|
||||
|
||||
messageManager.addMessageListener('Shumway:enableDebug', function (message) {
|
||||
enableDebug();
|
||||
});
|
||||
|
||||
shumwayActions.onExternalCallback = function (call) {
|
||||
return externalInterface.callback(JSON.stringify(call));
|
||||
};
|
||||
|
||||
shumwayActions.onLoadFileCallback = function (args) {
|
||||
messageManager.sendAsyncMessage('Shumway:loadFile', args);
|
||||
};
|
||||
|
||||
messageManager.addMessageListener('Shumway:constructed', function (message) {
|
||||
messageManager.sendAsyncMessage('Shumway:init', getEnvironment());
|
||||
});
|
||||
}
|
||||
|
||||
function getEnvironment() {
|
||||
return {
|
||||
swfUrl: startupInfo.url,
|
||||
privateBrowsing: startupInfo.privateBrowsing
|
||||
};
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
DebugUtils.enableDebug(startupInfo.url);
|
||||
setTimeout(function () {
|
||||
// TODO fix plugin instance reloading for jsplugins
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
var startupInfo = getStartupInfo(pluginElement);
|
||||
if (!startupInfo.url) {
|
||||
// Special case when movie URL is not specified, e.g. swfobject
|
||||
// checks only version. No need to instantiate the flash plugin.
|
||||
if (startupInfo.embedTag) {
|
||||
setupSimpleExternalInterface(startupInfo.embedTag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var document = pluginElement.ownerDocument;
|
||||
var window = document.defaultView;
|
||||
var shumwayActions = ShumwayCom.createActions(startupInfo, window, document);
|
||||
|
||||
handlerOOP();
|
||||
|
||||
// TODO fix remote debugging for jsplugins
|
||||
}
|
||||
|
||||
function setupSimpleExternalInterface(embedTag) {
|
||||
Components.utils.exportFunction(function (variable) {
|
||||
switch (variable) {
|
||||
case '$version':
|
||||
return 'SHUMWAY 10,0,0';
|
||||
default:
|
||||
log('Unsupported GetVariable() call: ' + variable);
|
||||
return undefined;
|
||||
}
|
||||
}, embedTag.wrappedJSObject, {defineAs: 'GetVariable'});
|
||||
}
|
||||
|
||||
runViewer();
|
||||
|
@ -1,58 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2013 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
iframe {
|
||||
position:fixed !important;
|
||||
left:0;top:0;bottom:0;right:0;
|
||||
overflow: hidden;
|
||||
line-height: 0;
|
||||
border: 0px none;
|
||||
}
|
||||
|
||||
body.remoteStopped {
|
||||
background-color: red;
|
||||
}
|
||||
body.remoteDebug {
|
||||
background-color: green;
|
||||
}
|
||||
body.remoteReload {
|
||||
background-color: yellow;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<iframe id="viewer" src="resource://shumway/web/viewer.html" width="100%" height="100%" mozbrowser remote="true"></iframe>
|
||||
<script src="chrome://shumway/content/pingpong.js"></script>
|
||||
<script src="chrome://shumway/content/viewerDebugger.js"></script>
|
||||
<script src="chrome://shumway/content/viewerWrapper.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
Components.utils.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var DebugUtils = (function () {
|
||||
var baseUrl = null;
|
||||
|
||||
function getBaseUrl() {
|
||||
if (baseUrl === null) {
|
||||
try {
|
||||
baseUrl = Services.prefs.getCharPref('shumway.debug.url');
|
||||
} catch (e) {
|
||||
baseUrl = 'http://localhost:8010';
|
||||
}
|
||||
}
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
var uniqueId = (Date.now() % 888888) * 2 + 1;
|
||||
|
||||
function getEnabledDebuggerId(swfUrl) {
|
||||
return new Promise(function (resolve) {
|
||||
var url = getBaseUrl() + '/debugController/' + uniqueId;
|
||||
var connection = new PingPongConnection(url);
|
||||
connection.onData = function (data) {
|
||||
if (data.action === 'setDebugger' && data.swfUrl === swfUrl) {
|
||||
resolve(data.debuggerId);
|
||||
}
|
||||
};
|
||||
try {
|
||||
connection.send({action: 'getDebugger', swfUrl: swfUrl, swfId: uniqueId}, true);
|
||||
} catch (e) {
|
||||
// ignoring failed send request
|
||||
}
|
||||
setTimeout(function () {
|
||||
resolve(0);
|
||||
connection.close();
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
function enableDebug(swfUrl) {
|
||||
var url = getBaseUrl() + '/debugController/' + uniqueId;
|
||||
var connection = new PingPongConnection(url, true);
|
||||
try {
|
||||
connection.send({action: 'enableDebugging', swfUrl: swfUrl}, true);
|
||||
} catch (e) {
|
||||
// ignoring failed send request
|
||||
}
|
||||
connection.close();
|
||||
}
|
||||
|
||||
function createDebuggerConnection(swfUrl) {
|
||||
return getEnabledDebuggerId(swfUrl).then(function (debuggerId) {
|
||||
if (!debuggerId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var url = getBaseUrl() + '/debug/' + uniqueId + '/' + debuggerId;
|
||||
console.log('Starting remote debugger with ' + url);
|
||||
return new PingPongConnection(url);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
get isEnabled() {
|
||||
try {
|
||||
return Services.prefs.getBoolPref('shumway.debug.enabled');
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
enableDebug: enableDebug,
|
||||
createDebuggerConnection: createDebuggerConnection
|
||||
};
|
||||
})();
|
@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var viewer = document.getElementById('viewer'), onLoaded;
|
||||
var promise = new Promise(function (resolve) {
|
||||
onLoaded = resolve;
|
||||
});
|
||||
viewer.addEventListener('load', function () {
|
||||
onLoaded(false);
|
||||
});
|
||||
viewer.addEventListener('mozbrowserloadend', function () {
|
||||
onLoaded(true);
|
||||
});
|
||||
|
||||
Components.utils.import('chrome://shumway/content/ShumwayCom.jsm');
|
||||
|
||||
function runViewer() {
|
||||
function handler() {
|
||||
function sendMessage(action, data, sync) {
|
||||
var result = shumwayActions.invoke(action, data);
|
||||
return Components.utils.cloneInto(result, childWindow);
|
||||
}
|
||||
|
||||
var childWindow = viewer.contentWindow.wrappedJSObject;
|
||||
|
||||
var shumwayComAdapterHooks = {};
|
||||
ShumwayCom.createAdapter(childWindow, {
|
||||
sendMessage: sendMessage,
|
||||
enableDebug: enableDebug,
|
||||
getEnvironment: getEnvironment,
|
||||
}, shumwayComAdapterHooks);
|
||||
|
||||
shumwayActions.onExternalCallback = function (call) {
|
||||
return shumwayComAdapterHooks.onExternalCallback(Components.utils.cloneInto(call, childWindow));
|
||||
};
|
||||
|
||||
shumwayActions.onLoadFileCallback = function (args) {
|
||||
shumwayComAdapterHooks.onLoadFileCallback(Components.utils.cloneInto(args, childWindow));
|
||||
};
|
||||
|
||||
childWindow.runViewer();
|
||||
}
|
||||
|
||||
function handlerOOP() {
|
||||
var frameLoader = viewer.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
|
||||
var messageManager = frameLoader.messageManager;
|
||||
messageManager.loadFrameScript('chrome://shumway/content/content.js', false);
|
||||
|
||||
var externalInterface;
|
||||
|
||||
messageManager.addMessageListener('Shumway:running', function (message) {
|
||||
externalInterface = message.objects.externalInterface;
|
||||
});
|
||||
|
||||
messageManager.addMessageListener('Shumway:message', function (message) {
|
||||
var data = message.data;
|
||||
var result = shumwayActions.invoke(data.action, data.data);
|
||||
if (message.sync) {
|
||||
return result === undefined ? 'undefined' : JSON.stringify(result);
|
||||
}
|
||||
});
|
||||
|
||||
messageManager.addMessageListener('Shumway:enableDebug', function (message) {
|
||||
enableDebug();
|
||||
});
|
||||
|
||||
shumwayActions.onExternalCallback = function (call) {
|
||||
return externalInterface.callback(JSON.stringify(call));
|
||||
};
|
||||
|
||||
shumwayActions.onLoadFileCallback = function (args) {
|
||||
messageManager.sendAsyncMessage('Shumway:loadFile', args);
|
||||
};
|
||||
|
||||
messageManager.sendAsyncMessage('Shumway:init', getEnvironment());
|
||||
}
|
||||
|
||||
|
||||
function handleDebug(connection) {
|
||||
viewer.parentNode.removeChild(viewer); // we don't need viewer anymore
|
||||
document.body.className = 'remoteDebug';
|
||||
|
||||
function sendMessage(data) {
|
||||
return shumwayActions.invoke(data.id, data.data);
|
||||
}
|
||||
|
||||
connection.onData = function (data) {
|
||||
switch (data.action) {
|
||||
case 'sendMessage':
|
||||
return sendMessage(data);
|
||||
case 'reload':
|
||||
document.body.className = 'remoteReload';
|
||||
setTimeout(function () {
|
||||
window.top.location.reload();
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
shumwayActions.onExternalCallback = function (call) {
|
||||
return connection.send({action: 'onExternalCallback', detail: call});
|
||||
};
|
||||
|
||||
shumwayActions.onLoadFileCallback = function (args) {
|
||||
if (args.array) {
|
||||
args.array = Array.prototype.slice.call(args.array, 0);
|
||||
}
|
||||
return connection.send({action: 'onLoadFileCallback', detail: args}, true);
|
||||
};
|
||||
|
||||
connection.send({action: 'runViewer'}, true);
|
||||
}
|
||||
|
||||
function getEnvironment() {
|
||||
return {
|
||||
swfUrl: window.shumwayStartupInfo.url,
|
||||
privateBrowsing: window.shumwayStartupInfo.privateBrowsing
|
||||
};
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
DebugUtils.enableDebug(window.shumwayStartupInfo.url);
|
||||
setTimeout(function () {
|
||||
window.top.location.reload();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
var startupInfo = window.shumwayStartupInfo;
|
||||
var shumwayActions = ShumwayCom.createActions(startupInfo, window, document);
|
||||
|
||||
promise.then(function (oop) {
|
||||
if (DebugUtils.isEnabled) {
|
||||
DebugUtils.createDebuggerConnection(window.shumwayStartupInfo.url).then(
|
||||
function (debuggerConnection) {
|
||||
if (debuggerConnection) {
|
||||
handleDebug(debuggerConnection);
|
||||
} else if (oop) {
|
||||
handlerOOP();
|
||||
} else {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (oop) {
|
||||
handlerOOP();
|
||||
} else {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
}
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var EXPORTED_SYMBOLS = ['ShumwayBootstrapUtils'];
|
||||
|
||||
const PREF_PREFIX = 'shumway.';
|
||||
const PREF_IGNORE_CTP = PREF_PREFIX + 'ignoreCTP';
|
||||
const PREF_WHITELIST = PREF_PREFIX + 'swf.whitelist';
|
||||
const SWF_CONTENT_TYPE = 'application/x-shockwave-flash';
|
||||
const PLUGIN_HANLDER_URI = 'chrome://shumway/content/content.html';
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cm = Components.manager;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
var Ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
|
||||
|
||||
function getBoolPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function getStringPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getComplexValue(pref, Ci.nsISupportsString).data;
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function log(str) {
|
||||
var msg = 'ShumwayBootstrapUtils.jsm: ' + str;
|
||||
Services.console.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
// Register/unregister a constructor as a factory.
|
||||
function Factory() {}
|
||||
Factory.prototype = {
|
||||
register: function register(targetConstructor) {
|
||||
var proto = targetConstructor.prototype;
|
||||
this._classID = proto.classID;
|
||||
|
||||
var factory = XPCOMUtils._getFactory(targetConstructor);
|
||||
this._factory = factory;
|
||||
|
||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(proto.classID, proto.classDescription,
|
||||
proto.contractID, factory);
|
||||
|
||||
if (proto.classID2) {
|
||||
this._classID2 = proto.classID2;
|
||||
registrar.registerFactory(proto.classID2, proto.classDescription,
|
||||
proto.contractID2, factory);
|
||||
}
|
||||
},
|
||||
|
||||
unregister: function unregister() {
|
||||
var registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.unregisterFactory(this._classID, this._factory);
|
||||
if (this._classID2) {
|
||||
registrar.unregisterFactory(this._classID2, this._factory);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function allowedPlatformForMedia() {
|
||||
var oscpu = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler).oscpu;
|
||||
if (oscpu.indexOf('Windows NT') === 0) {
|
||||
return oscpu.indexOf('Windows NT 5') < 0; // excluding Windows XP
|
||||
}
|
||||
if (oscpu.indexOf('Intel Mac OS X') === 0) {
|
||||
return true;
|
||||
}
|
||||
// Other platforms are not supported yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
var ShumwayBootstrapUtils = {
|
||||
isRegistered: false,
|
||||
isJSPluginsSupported: false,
|
||||
|
||||
register: function () {
|
||||
if (this.isRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRegistered = true;
|
||||
|
||||
// Register the components.
|
||||
this.isJSPluginsSupported = !!Ph.registerFakePlugin &&
|
||||
getBoolPref('shumway.jsplugins', false);
|
||||
|
||||
if (this.isJSPluginsSupported) {
|
||||
let initPluginDict = {
|
||||
handlerURI: PLUGIN_HANLDER_URI,
|
||||
mimeEntries: [
|
||||
{
|
||||
type: SWF_CONTENT_TYPE,
|
||||
description: 'Shockwave Flash',
|
||||
extension: 'swf'
|
||||
}
|
||||
],
|
||||
niceName: 'Shumway plugin',
|
||||
name: 'Shumway',
|
||||
supersedeExisting: true, // TODO verify when jsplugins (bug 558184) is implemented
|
||||
sandboxScript: 'chrome://shumway/content/plugin.js', // TODO verify when jsplugins (bug 558184) is implemented
|
||||
version: '10.0.0.0'
|
||||
};
|
||||
Ph.registerFakePlugin(initPluginDict);
|
||||
} else {
|
||||
Cu.import('resource://shumway/ShumwayStreamConverter.jsm');
|
||||
|
||||
let converterFactory = new Factory();
|
||||
converterFactory.register(ShumwayStreamConverter);
|
||||
this.converterFactory = converterFactory;
|
||||
}
|
||||
},
|
||||
|
||||
unregister: function () {
|
||||
if (!this.isRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isRegistered = false;
|
||||
|
||||
// Remove the contract/component.
|
||||
if (this.isJSPluginsSupported) {
|
||||
Ph.unregisterFakePlugin(PLUGIN_HANLDER_URI);
|
||||
} else {
|
||||
this.converterFactory.unregister();
|
||||
this.converterFactory = null;
|
||||
}
|
||||
}
|
||||
};
|
@ -1,415 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var EXPORTED_SYMBOLS = ['ShumwayStreamConverter', 'ShumwayStreamOverlayConverter'];
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const SHUMWAY_CONTENT_TYPE = 'application/x-shockwave-flash';
|
||||
const EXPECTED_PLAYPREVIEW_URI_PREFIX = 'data:application/x-moz-playpreview;,' +
|
||||
SHUMWAY_CONTENT_TYPE;
|
||||
|
||||
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
|
||||
const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}';
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/NetUtil.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
|
||||
'resource://gre/modules/PrivateBrowsingUtils.jsm');
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, 'ShumwayTelemetry',
|
||||
'resource://shumway/ShumwayTelemetry.jsm');
|
||||
|
||||
Components.utils.import('chrome://shumway/content/StartupInfo.jsm');
|
||||
|
||||
function getBoolPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function log(aMsg) {
|
||||
let msg = 'ShumwayStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
|
||||
Services.console.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
}
|
||||
|
||||
function getDOMWindow(aChannel) {
|
||||
var requestor = aChannel.notificationCallbacks ||
|
||||
aChannel.loadGroup.notificationCallbacks;
|
||||
var win = requestor.getInterface(Components.interfaces.nsIDOMWindow);
|
||||
return win;
|
||||
}
|
||||
|
||||
function isShumwayEnabledFor(startupInfo) {
|
||||
// disabled for PrivateBrowsing windows
|
||||
if (isContentWindowPrivate(startupInfo.window) &&
|
||||
!getBoolPref('shumway.enableForPrivate', false)) {
|
||||
return false;
|
||||
}
|
||||
// disabled if embed tag specifies shumwaymode (for testing purpose)
|
||||
if (startupInfo.objectParams['shumwaymode'] === 'off') {
|
||||
return false;
|
||||
}
|
||||
|
||||
var url = startupInfo.url;
|
||||
var baseUrl = startupInfo.baseUrl;
|
||||
|
||||
// blacklisting well known sites with issues
|
||||
if (/\.ytimg\.com\//i.test(url) /* youtube movies */ ||
|
||||
/\/vui.swf\b/i.test(url) /* vidyo manager */ ||
|
||||
/soundcloud\.com\/player\/assets\/swf/i.test(url) /* soundcloud */ ||
|
||||
/sndcdn\.com\/assets\/swf/.test(url) /* soundcloud */ ||
|
||||
/vimeocdn\.com/.test(url) /* vimeo */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function activateShumwayScripts(window) {
|
||||
function initScripts() {
|
||||
window.wrappedJSObject.runViewer();
|
||||
|
||||
var parentWindow = window.parent;
|
||||
var viewerWindow = window.viewer.contentWindow;
|
||||
|
||||
function activate(e) {
|
||||
e.preventDefault();
|
||||
viewerWindow.removeEventListener('mousedown', activate, true);
|
||||
|
||||
parentWindow.addEventListener('keydown', forwardKeyEvent, true);
|
||||
parentWindow.addEventListener('keyup', forwardKeyEvent, true);
|
||||
|
||||
sendFocusEvent('focus');
|
||||
|
||||
parentWindow.addEventListener('blur', deactivate, true);
|
||||
parentWindow.addEventListener('mousedown', deactivate, true);
|
||||
viewerWindow.addEventListener('unload', deactivate, true);
|
||||
}
|
||||
|
||||
function deactivate() {
|
||||
parentWindow.removeEventListener('blur', deactivate, true);
|
||||
parentWindow.removeEventListener('mousedown', deactivate, true);
|
||||
viewerWindow.removeEventListener('unload', deactivate, true);
|
||||
|
||||
parentWindow.removeEventListener('keydown', forwardKeyEvent, true);
|
||||
parentWindow.removeEventListener('keyup', forwardKeyEvent, true);
|
||||
|
||||
sendFocusEvent('blur');
|
||||
|
||||
viewerWindow.addEventListener('mousedown', activate, true);
|
||||
}
|
||||
|
||||
function forwardKeyEvent(e) {
|
||||
var event = viewerWindow.document.createEvent('KeyboardEvent');
|
||||
event.initKeyEvent(e.type,
|
||||
e.bubbles,
|
||||
e.cancelable,
|
||||
e.view,
|
||||
e.ctrlKey,
|
||||
e.altKey,
|
||||
e.shiftKey,
|
||||
e.metaKey,
|
||||
e.keyCode,
|
||||
e.charCode);
|
||||
viewerWindow.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function sendFocusEvent(type) {
|
||||
var event = viewerWindow.document.createEvent("UIEvent");
|
||||
event.initEvent(type, false, true);
|
||||
viewerWindow.dispatchEvent(event);
|
||||
}
|
||||
|
||||
if (viewerWindow) {
|
||||
viewerWindow.addEventListener('mousedown', activate, true);
|
||||
}
|
||||
|
||||
window.addEventListener('shumwayFallback', function (e) {
|
||||
var automatic = !!e.detail.automatic;
|
||||
fallbackToNativePlugin(window, !automatic, automatic);
|
||||
});
|
||||
}
|
||||
|
||||
if (window.document.readyState === "interactive" ||
|
||||
window.document.readyState === "complete") {
|
||||
initScripts();
|
||||
} else {
|
||||
window.document.addEventListener('DOMContentLoaded', initScripts);
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackToNativePlugin(window, userAction, activateCTP) {
|
||||
var obj = window.frameElement;
|
||||
var doc = obj.ownerDocument;
|
||||
var e = doc.createEvent("CustomEvent");
|
||||
e.initCustomEvent("MozPlayPlugin", true, true, activateCTP);
|
||||
obj.dispatchEvent(e);
|
||||
|
||||
ShumwayTelemetry.onFallback(userAction);
|
||||
}
|
||||
|
||||
function ShumwayStreamConverterBase() {
|
||||
}
|
||||
|
||||
ShumwayStreamConverterBase.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsISupports,
|
||||
Ci.nsIStreamConverter,
|
||||
Ci.nsIStreamListener,
|
||||
Ci.nsIRequestObserver
|
||||
]),
|
||||
|
||||
/*
|
||||
* This component works as such:
|
||||
* 1. asyncConvertData stores the listener
|
||||
* 2. onStartRequest creates a new channel, streams the viewer and cancels
|
||||
* the request so Shumway can do the request
|
||||
* Since the request is cancelled onDataAvailable should not be called. The
|
||||
* onStopRequest does nothing. The convert function just returns the stream,
|
||||
* it's just the synchronous version of asyncConvertData.
|
||||
*/
|
||||
|
||||
// nsIStreamConverter::convert
|
||||
convert: function(aFromStream, aFromType, aToType, aCtxt) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
getUrlHint: function(requestUrl) {
|
||||
return requestUrl.spec;
|
||||
},
|
||||
|
||||
getStartupInfo: function(window, url) {
|
||||
var initStartTime = Date.now();
|
||||
var element = window.frameElement;
|
||||
var isOverlay = false;
|
||||
if (element) {
|
||||
// PlayPreview overlay "belongs" to the embed/object tag and consists of
|
||||
// DIV and IFRAME. Starting from IFRAME and looking for first object tag.
|
||||
var tagName = element.nodeName, containerElement;
|
||||
while (tagName != 'EMBED' && tagName != 'OBJECT') {
|
||||
// plugin overlay skipping until the target plugin is found
|
||||
isOverlay = true;
|
||||
containerElement = element;
|
||||
element = element.parentNode;
|
||||
if (!element) {
|
||||
throw new Error('Plugin element is not found');
|
||||
}
|
||||
tagName = element.nodeName;
|
||||
}
|
||||
|
||||
if (isOverlay) {
|
||||
// HACK For Facebook, CSS embed tag rescaling -- iframe (our overlay)
|
||||
// has no styling in document. Shall removed with jsplugins.
|
||||
for (var child = window.frameElement; child !== element; child = child.parentNode) {
|
||||
child.setAttribute('style', 'max-width: 100%; max-height: 100%');
|
||||
}
|
||||
|
||||
// Checking if overlay is a proper PlayPreview overlay.
|
||||
for (var i = 0; i < element.children.length; i++) {
|
||||
if (element.children[i] === containerElement) {
|
||||
throw new Error('Plugin element is invalid');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (element) {
|
||||
return getStartupInfo(element);
|
||||
}
|
||||
|
||||
// Stream converter is used in top level window, just providing basic
|
||||
// information about SWF.
|
||||
|
||||
var objectParams = {};
|
||||
var movieParams = {};
|
||||
var queryStringMatch = url && /\?([^#]+)/.exec(url);
|
||||
if (queryStringMatch) {
|
||||
var queryStringParams = parseQueryString(queryStringMatch[1]);
|
||||
for (var i in queryStringParams) {
|
||||
if (!(i in movieParams)) {
|
||||
movieParams[i] = queryStringParams[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Using the same data structure as we return in StartupInfo.jsm and
|
||||
// assigning constant values for fields that is not applicable for
|
||||
// the stream converter when it is used in a top level window.
|
||||
var startupInfo = {};
|
||||
startupInfo.window = window;
|
||||
startupInfo.url = url;
|
||||
startupInfo.privateBrowsing = isContentWindowPrivate(window);
|
||||
startupInfo.objectParams = objectParams;
|
||||
startupInfo.movieParams = movieParams;
|
||||
startupInfo.baseUrl = url;
|
||||
startupInfo.isOverlay = false;
|
||||
startupInfo.refererUrl = null;
|
||||
startupInfo.embedTag = null;
|
||||
startupInfo.isPausedAtStart = /\bpaused=true$/.test(url);
|
||||
startupInfo.initStartTime = initStartTime;
|
||||
startupInfo.allowScriptAccess = false;
|
||||
return startupInfo;
|
||||
},
|
||||
|
||||
// nsIStreamConverter::asyncConvertData
|
||||
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
|
||||
// Store the listener passed to us
|
||||
this.listener = aListener;
|
||||
},
|
||||
|
||||
// nsIStreamListener::onDataAvailable
|
||||
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
|
||||
// Do nothing since all the data loading is handled by the viewer.
|
||||
log('SANITY CHECK: onDataAvailable SHOULD NOT BE CALLED!');
|
||||
},
|
||||
|
||||
// nsIRequestObserver::onStartRequest
|
||||
onStartRequest: function(aRequest, aContext) {
|
||||
// Setup the request so we can use it below.
|
||||
aRequest.QueryInterface(Ci.nsIChannel);
|
||||
|
||||
aRequest.QueryInterface(Ci.nsIWritablePropertyBag);
|
||||
|
||||
// Change the content type so we don't get stuck in a loop.
|
||||
aRequest.setProperty('contentType', aRequest.contentType);
|
||||
aRequest.contentType = 'text/html';
|
||||
|
||||
// TODO For now suspending request, however we can continue fetching data
|
||||
aRequest.suspend();
|
||||
|
||||
var originalURI = aRequest.URI;
|
||||
|
||||
// Create a new channel that loads the viewer as a chrome resource.
|
||||
var viewerUrl = 'chrome://shumway/content/viewer.wrapper.html';
|
||||
var channel = NetUtil.newChannel({
|
||||
uri: viewerUrl,
|
||||
loadUsingSystemPrincipal: true
|
||||
});
|
||||
|
||||
var converter = this;
|
||||
var listener = this.listener;
|
||||
// Proxy all the request observer calls, when it gets to onStopRequest
|
||||
// we can get the dom window.
|
||||
var proxy = {
|
||||
onStartRequest: function(request, context) {
|
||||
listener.onStartRequest(aRequest, context);
|
||||
},
|
||||
onDataAvailable: function(request, context, inputStream, offset, count) {
|
||||
listener.onDataAvailable(aRequest, context, inputStream, offset, count);
|
||||
},
|
||||
onStopRequest: function(request, context, statusCode) {
|
||||
// Cancel the request so the viewer can handle it.
|
||||
aRequest.resume();
|
||||
aRequest.cancel(Cr.NS_BINDING_ABORTED);
|
||||
|
||||
var domWindow = getDOMWindow(channel);
|
||||
let startupInfo = converter.getStartupInfo(domWindow, converter.getUrlHint(originalURI));
|
||||
|
||||
listener.onStopRequest(aRequest, context, statusCode);
|
||||
|
||||
if (!startupInfo.url) {
|
||||
// Special case when movie URL is not specified, e.g. swfobject
|
||||
// checks only version. No need to instantiate the flash plugin.
|
||||
if (startupInfo.embedTag) {
|
||||
setupSimpleExternalInterface(startupInfo.embedTag);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isShumwayEnabledFor(startupInfo)) {
|
||||
fallbackToNativePlugin(domWindow, false, true);
|
||||
return;
|
||||
}
|
||||
|
||||
domWindow.shumwayStartupInfo = startupInfo;
|
||||
|
||||
// TODO Report telemetry on amount of swfs on the page
|
||||
// ShumwayTelemetry.onPageIndex(pageIndex);
|
||||
|
||||
activateShumwayScripts(domWindow);
|
||||
}
|
||||
};
|
||||
|
||||
// Keep the URL the same so the browser sees it as the same.
|
||||
channel.originalURI = aRequest.URI;
|
||||
channel.loadGroup = aRequest.loadGroup;
|
||||
|
||||
// We can use all powerful principal: we are opening chrome:// web page,
|
||||
// which will need lots of permission.
|
||||
var securityManager = Cc['@mozilla.org/scriptsecuritymanager;1']
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
var resourcePrincipal = securityManager.getSystemPrincipal();
|
||||
aRequest.owner = resourcePrincipal;
|
||||
channel.asyncOpen2(proxy);
|
||||
},
|
||||
|
||||
// nsIRequestObserver::onStopRequest
|
||||
onStopRequest: function(aRequest, aContext, aStatusCode) {
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
|
||||
function setupSimpleExternalInterface(embedTag) {
|
||||
Components.utils.exportFunction(function (variable) {
|
||||
switch (variable) {
|
||||
case '$version':
|
||||
return 'SHUMWAY 10,0,0';
|
||||
default:
|
||||
log('Unsupported GetVariable() call: ' + variable);
|
||||
return undefined;
|
||||
}
|
||||
}, embedTag.wrappedJSObject, {defineAs: 'GetVariable'});
|
||||
}
|
||||
|
||||
// properties required for XPCOM registration:
|
||||
function copyProperties(obj, template) {
|
||||
for (var prop in template) {
|
||||
obj[prop] = template[prop];
|
||||
}
|
||||
}
|
||||
|
||||
function ShumwayStreamConverter() {}
|
||||
ShumwayStreamConverter.prototype = new ShumwayStreamConverterBase();
|
||||
copyProperties(ShumwayStreamConverter.prototype, {
|
||||
classID: Components.ID('{4c6030f7-e20a-264f-5b0e-ada3a9e97384}'),
|
||||
classDescription: 'Shumway Content Converter Component',
|
||||
contractID: '@mozilla.org/streamconv;1?from=application/x-shockwave-flash&to=*/*',
|
||||
|
||||
classID2: Components.ID('{4c6030f8-e20a-264f-5b0e-ada3a9e97384}'),
|
||||
contractID2: '@mozilla.org/streamconv;1?from=application/x-shockwave-flash&to=text/html'
|
||||
});
|
||||
|
||||
function ShumwayStreamOverlayConverter() {}
|
||||
ShumwayStreamOverlayConverter.prototype = new ShumwayStreamConverterBase();
|
||||
copyProperties(ShumwayStreamOverlayConverter.prototype, {
|
||||
classID: Components.ID('{4c6030f7-e20a-264f-5f9b-ada3a9e97384}'),
|
||||
classDescription: 'Shumway PlayPreview Component',
|
||||
contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*'
|
||||
});
|
||||
ShumwayStreamOverlayConverter.prototype.getUrlHint = function (requestUrl) {
|
||||
return '';
|
||||
};
|
@ -1,75 +0,0 @@
|
||||
/* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* jshint esnext:true */
|
||||
|
||||
'use strict';
|
||||
|
||||
this.EXPORTED_SYMBOLS = ['ShumwayTelemetry'];
|
||||
|
||||
const Cu = Components.utils;
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
const BANNER_SIZES = [
|
||||
"88x31", "120x60", "120x90", "120x240", "120x600", "125x125", "160x600",
|
||||
"180x150", "234x60", "240x400", "250x250", "300x100", "300x250", "300x600",
|
||||
"300x1050", "336x280", "468x60", "550x480", "720x100", "728x90", "970x90",
|
||||
"970x250"];
|
||||
|
||||
function getBannerType(width, height) {
|
||||
return BANNER_SIZES.indexOf(width + 'x' + height) + 1;
|
||||
}
|
||||
|
||||
this.ShumwayTelemetry = {
|
||||
onFirstFrame: function (timeToDisplay) {
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_TIME_TO_VIEW_MS");
|
||||
histogram.add(timeToDisplay);
|
||||
},
|
||||
onParseInfo: function (parseInfo) {
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_PARSING_MS");
|
||||
histogram.add(parseInfo.parseTime);
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_SWF_SIZE_KB");
|
||||
histogram.add(parseInfo.size / 1024);
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_SWF_VERSION");
|
||||
histogram.add(parseInfo.swfVersion);
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_SWF_FRAME_RATE");
|
||||
histogram.add(parseInfo.frameRate);
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_SWF_AREA");
|
||||
histogram.add(parseInfo.width * parseInfo.height);
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_SWF_BANNER");
|
||||
histogram.add(getBannerType(parseInfo.width, parseInfo.height));
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_SWF_AVM2");
|
||||
histogram.add(parseInfo.isAvm2);
|
||||
},
|
||||
onError: function (errorType) {
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_ERROR");
|
||||
histogram.add(errorType);
|
||||
},
|
||||
onPageIndex: function (pageIndex) {
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_SWF_INDEX_ON_PAGE");
|
||||
histogram.add(pageIndex);
|
||||
},
|
||||
onFeature: function (featureType) {
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_FEATURE_USED");
|
||||
histogram.add(featureType);
|
||||
},
|
||||
onLoadResource: function (resultType) {
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_LOAD_RESOURCE_RESULT");
|
||||
histogram.add(resultType);
|
||||
},
|
||||
onFallback: function (userAction) {
|
||||
var histogram = Services.telemetry.getHistogramById("SHUMWAY_FALLBACK");
|
||||
histogram.add(userAction);
|
||||
}
|
||||
};
|
@ -1,130 +0,0 @@
|
||||
/* Copyright 2012 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ["ShumwayUtils"];
|
||||
|
||||
const PREF_PREFIX = 'shumway.';
|
||||
const PREF_DISABLED = PREF_PREFIX + 'disabled';
|
||||
const PREF_WHITELIST = PREF_PREFIX + 'swf.whitelist';
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cm = Components.manager;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
function getBoolPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(pref);
|
||||
} catch (ex) {
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
function log(str) {
|
||||
dump(str + '\n');
|
||||
}
|
||||
|
||||
var ShumwayUtils = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
_registered: false,
|
||||
|
||||
init: function init() {
|
||||
this.migratePreferences();
|
||||
if (this.enabled)
|
||||
this._ensureRegistered();
|
||||
else
|
||||
this._ensureUnregistered();
|
||||
|
||||
Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster)
|
||||
.addMessageListener('Shumway:Chrome:isEnabled', this);
|
||||
|
||||
// Listen for when shumway is completely disabled.
|
||||
Services.prefs.addObserver(PREF_DISABLED, this, false);
|
||||
},
|
||||
|
||||
migratePreferences: function migratePreferences() {
|
||||
// At one point we had shumway.disabled set to true by default,
|
||||
// and we are trying to replace it with shumway.swf.whitelist:
|
||||
// checking if the user already changed it before to reset
|
||||
// the whitelist to '*'.
|
||||
if (Services.prefs.prefHasUserValue(PREF_DISABLED) &&
|
||||
!Services.prefs.prefHasUserValue(PREF_WHITELIST) &&
|
||||
!getBoolPref(PREF_DISABLED, false)) {
|
||||
// The user is already using Shumway -- enabling all web sites.
|
||||
Services.prefs.setCharPref(PREF_WHITELIST, '*');
|
||||
}
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe: function observe(aSubject, aTopic, aData) {
|
||||
if (this.enabled)
|
||||
this._ensureRegistered();
|
||||
else
|
||||
this._ensureUnregistered();
|
||||
},
|
||||
|
||||
receiveMessage: function(message) {
|
||||
switch (message.name) {
|
||||
case 'Shumway:Chrome:isEnabled':
|
||||
return this.enabled;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* shumway is only enabled if the global switch enabling is true.
|
||||
* @return {boolean} Wether or not it's enabled.
|
||||
*/
|
||||
get enabled() {
|
||||
return !getBoolPref(PREF_DISABLED, true);
|
||||
},
|
||||
|
||||
_ensureRegistered: function _ensureRegistered() {
|
||||
if (this._registered)
|
||||
return;
|
||||
|
||||
// Load the component and register it.
|
||||
Cu.import('resource://shumway/ShumwayBootstrapUtils.jsm');
|
||||
ShumwayBootstrapUtils.register();
|
||||
|
||||
this._registered = true;
|
||||
|
||||
log('Shumway is registered');
|
||||
|
||||
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
|
||||
.getService(Ci.nsIFrameScriptLoader);
|
||||
globalMM.broadcastAsyncMessage('Shumway:Child:refreshSettings');
|
||||
},
|
||||
|
||||
_ensureUnregistered: function _ensureUnregistered() {
|
||||
if (!this._registered)
|
||||
return;
|
||||
|
||||
// Remove the contract/component.
|
||||
ShumwayBootstrapUtils.unregister();
|
||||
Cu.unload('resource://shumway/ShumwayBootstrapUtils.jsm');
|
||||
|
||||
this._registered = false;
|
||||
|
||||
log('Shumway is unregistered');
|
||||
|
||||
let globalMM = Cc['@mozilla.org/globalmessagemanager;1']
|
||||
.getService(Ci.nsIFrameScriptLoader);
|
||||
globalMM.broadcastAsyncMessage('Shumway:Child:refreshSettings');
|
||||
}
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
precision mediump float;
|
||||
|
||||
varying vec4 vColor;
|
||||
uniform mat4 uColorMatrix;
|
||||
uniform vec4 uColorVector;
|
||||
uniform sampler2D uSampler[8];
|
||||
varying vec2 vCoordinate;
|
||||
varying float vKind;
|
||||
varying float vSampler;
|
||||
|
||||
void main() {
|
||||
vec4 color;
|
||||
int kind = int(floor(vKind + 0.5));
|
||||
if (kind == 0) {
|
||||
color = vColor;
|
||||
} else if (kind == 1 || kind == 2) {
|
||||
int sampler = int(floor(vSampler + 0.5));
|
||||
if (sampler == 0) {
|
||||
color = vColor * texture2D(uSampler[0], vCoordinate);
|
||||
} else if (sampler == 1) {
|
||||
color = vColor * texture2D(uSampler[1], vCoordinate);
|
||||
} else if (sampler == 2) {
|
||||
color = vColor * texture2D(uSampler[2], vCoordinate);
|
||||
} else if (sampler == 3) {
|
||||
color = vColor * texture2D(uSampler[3], vCoordinate);
|
||||
} else if (sampler == 4) {
|
||||
color = vColor * texture2D(uSampler[4], vCoordinate);
|
||||
} else if (sampler == 5) {
|
||||
color = vColor * texture2D(uSampler[5], vCoordinate);
|
||||
} else if (sampler == 6) {
|
||||
color = vColor * texture2D(uSampler[6], vCoordinate);
|
||||
} else if (sampler == 7) {
|
||||
color = vColor * texture2D(uSampler[7], vCoordinate);
|
||||
}
|
||||
if (kind == 2) {
|
||||
color = color * uColorMatrix + uColorVector;
|
||||
}
|
||||
} else {
|
||||
color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
// color.rgb *= color.a;
|
||||
if (color.a < 0.01) {
|
||||
discard;
|
||||
}
|
||||
gl_FragColor = color;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
uniform vec2 uResolution;
|
||||
uniform mat3 uTransformMatrix;
|
||||
uniform mat4 uTransformMatrix3D;
|
||||
|
||||
attribute vec4 aPosition;
|
||||
attribute vec4 aColor;
|
||||
attribute vec2 aCoordinate;
|
||||
attribute float aKind;
|
||||
attribute float aSampler;
|
||||
|
||||
varying vec4 vColor;
|
||||
varying vec2 vCoordinate;
|
||||
varying float vKind;
|
||||
varying float vSampler;
|
||||
|
||||
void main() {
|
||||
gl_Position = uTransformMatrix3D * aPosition;
|
||||
vColor = aColor;
|
||||
vCoordinate = aCoordinate;
|
||||
vKind = aKind;
|
||||
vSampler = aSampler;
|
||||
}
|
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +0,0 @@
|
||||
0.11.422
|
||||
137ba70
|
Binary file not shown.
@ -1,36 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head lang="en">
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
#easelContainer {
|
||||
position:fixed !important;
|
||||
left:0;top:0;bottom:0;right:0;
|
||||
overflow: hidden;
|
||||
line-height: 0;
|
||||
}
|
||||
</style>
|
||||
<script src='resource://shumway/shumway.gfx.js'></script>
|
||||
</head>
|
||||
<body contextmenu="shumwayMenu">
|
||||
<div id="easelContainer"></div>
|
||||
<menu type="context" id="shumwayMenu">
|
||||
<menuitem label="Show URL" id="showURLMenu"></menuitem>
|
||||
<menuitem label="Open in Inspector" id="inspectorMenu"></menuitem>
|
||||
<menuitem label="Report Problems" id="reportMenu"></menuitem>
|
||||
<menuitem label="Reload in Adobe Flash Player" id="fallbackMenu" hidden></menuitem>
|
||||
<menuitem label="Debug this SWF" id="debugMenu"></menuitem>
|
||||
<menuitem label="About Shumway %version%..." id="aboutMenu"></menuitem>
|
||||
</menu>
|
||||
<script src="viewerGfx.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,110 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2013 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<base href=""/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
body.started #playerIframe {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#gfxIframe {
|
||||
position:fixed !important;
|
||||
left:0; top:0;
|
||||
width: 100%; height: 100%;
|
||||
overflow: hidden;
|
||||
border: 0 none;
|
||||
}
|
||||
|
||||
#overlay {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#overlay.enabled {
|
||||
display: block;
|
||||
position:fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#report, #fallback {
|
||||
float: right;
|
||||
width: 70px; height: 16px;
|
||||
padding: 8px 4px 4px;
|
||||
color: white;
|
||||
background-color: rgba(218, 56, 7, 0.63);
|
||||
font: bold 10px sans-serif;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
#report {
|
||||
display: none;
|
||||
width: 100px;
|
||||
}
|
||||
#overlay:hover #report {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fallback .icon {
|
||||
display: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#fallback:hover .icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#report:hover, #fallback:hover {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#playerIframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 100px), screen and (max-height: 40px) {
|
||||
body.started #overlay {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<iframe id="playerIframe" width="9" height="9" src="" sandbox="allow-scripts"></iframe>
|
||||
<iframe id="gfxIframe" src="" sandbox="allow-scripts"></iframe>
|
||||
<section>
|
||||
<div id="overlay">
|
||||
<a id="fallback" href="#">Shumway <span class="icon">×</span></a>
|
||||
<a id="report" href="#">Report Problems</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script src='resource://shumway/web/viewer.js'></script>
|
||||
</body>
|
||||
</html>
|
@ -1,234 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var movieUrl, movieParams;
|
||||
|
||||
function runViewer() {
|
||||
var flashParams = ShumwayCom.getPluginParams();
|
||||
|
||||
movieUrl = flashParams.url;
|
||||
if (!movieUrl) {
|
||||
console.log("no movie url provided -- stopping here");
|
||||
return;
|
||||
}
|
||||
|
||||
movieParams = flashParams.movieParams;
|
||||
var objectParams = flashParams.objectParams;
|
||||
var baseUrl = flashParams.baseUrl;
|
||||
var isOverlay = flashParams.isOverlay;
|
||||
var isDebuggerEnabled = flashParams.isDebuggerEnabled;
|
||||
var initStartTime = flashParams.initStartTime;
|
||||
|
||||
if (movieParams.fmt_list && movieParams.url_encoded_fmt_stream_map) {
|
||||
// HACK removing FLVs from the fmt_list
|
||||
movieParams.fmt_list = movieParams.fmt_list.split(',').filter(function (s) {
|
||||
var fid = s.split('/')[0];
|
||||
return fid !== '5' && fid !== '34' && fid !== '35'; // more?
|
||||
}).join(',');
|
||||
}
|
||||
|
||||
var backgroundColor;
|
||||
if (objectParams) {
|
||||
var m;
|
||||
if (objectParams.bgcolor && (m = /#([0-9A-F]{6})/i.exec(objectParams.bgcolor))) {
|
||||
var hexColor = parseInt(m[1], 16);
|
||||
backgroundColor = hexColor << 8 | 0xff;
|
||||
}
|
||||
if (objectParams.wmode === 'transparent') {
|
||||
backgroundColor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
playerReady.then(function () {
|
||||
var settings = ShumwayCom.getSettings();
|
||||
var playerSettings = settings.playerSettings;
|
||||
|
||||
ShumwayCom.setupPlayerComBridge(document.getElementById('playerIframe'));
|
||||
parseSwf(movieUrl, baseUrl, movieParams, objectParams, settings, initStartTime, backgroundColor);
|
||||
|
||||
if (isOverlay) {
|
||||
if (isDebuggerEnabled) {
|
||||
document.getElementById('overlay').className = 'enabled';
|
||||
var fallbackDiv = document.getElementById('fallback');
|
||||
fallbackDiv.addEventListener('click', function (e) {
|
||||
fallback();
|
||||
e.preventDefault();
|
||||
});
|
||||
var reportDiv = document.getElementById('report');
|
||||
reportDiv.addEventListener('click', function (e) {
|
||||
reportIssue();
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ShumwayCom.setupGfxComBridge(document.getElementById('gfxIframe'));
|
||||
gfxWindow.postMessage({
|
||||
type: 'prepareUI',
|
||||
params: {
|
||||
isOverlay: isOverlay,
|
||||
isDebuggerEnabled: isDebuggerEnabled,
|
||||
isHudOn: playerSettings.hud,
|
||||
backgroundColor: backgroundColor
|
||||
}
|
||||
}, '*')
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener("message", function handlerMessage(e) {
|
||||
var args = e.data;
|
||||
if (typeof args !== 'object' || args === null) {
|
||||
return;
|
||||
}
|
||||
if (gfxWindow && e.source === gfxWindow) {
|
||||
switch (args.callback) {
|
||||
case 'displayParameters':
|
||||
// The display parameters data will be send to the player window.
|
||||
// TODO do we need sanitize it?
|
||||
displayParametersResolved(args.params);
|
||||
break;
|
||||
case 'showURL':
|
||||
showURL();
|
||||
break;
|
||||
case 'showInInspector':
|
||||
showInInspector();
|
||||
break;
|
||||
case 'reportIssue':
|
||||
reportIssue();
|
||||
break;
|
||||
case 'showAbout':
|
||||
showAbout();
|
||||
break;
|
||||
case 'enableDebug':
|
||||
enableDebug();
|
||||
break;
|
||||
case 'fallback':
|
||||
fallback();
|
||||
break;
|
||||
default:
|
||||
console.error('Unexpected message from gfx frame: ' + args.callback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (playerWindow && e.source === playerWindow) {
|
||||
switch (args.callback) {
|
||||
case 'started':
|
||||
document.body.classList.add('started');
|
||||
break;
|
||||
default:
|
||||
console.error('Unexpected message from player frame: ' + args.callback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
|
||||
function fallback() {
|
||||
ShumwayCom.fallback();
|
||||
}
|
||||
|
||||
function showURL() {
|
||||
window.prompt("Copy to clipboard", movieUrl);
|
||||
}
|
||||
|
||||
function showInInspector() {
|
||||
var base = "http://www.areweflashyet.com/shumway/examples/inspector/inspector.html?rfile=";
|
||||
var params = '';
|
||||
for (var k in movieParams) {
|
||||
params += '&' + k + '=' + encodeURIComponent(movieParams[k]);
|
||||
}
|
||||
window.open(base + encodeURIComponent(movieUrl) + params);
|
||||
}
|
||||
|
||||
function reportIssue() {
|
||||
//var duplicatesMap = Object.create(null);
|
||||
//var prunedExceptions = [];
|
||||
//avm2.exceptions.forEach(function(e) {
|
||||
// var ident = e.source + e.message + e.stack;
|
||||
// var entry = duplicatesMap[ident];
|
||||
// if (!entry) {
|
||||
// entry = duplicatesMap[ident] = {
|
||||
// source: e.source,
|
||||
// message: e.message,
|
||||
// stack: e.stack,
|
||||
// count: 0
|
||||
// };
|
||||
// prunedExceptions.push(entry);
|
||||
// }
|
||||
// entry.count++;
|
||||
//});
|
||||
//ShumwayCom.reportIssue(JSON.stringify(prunedExceptions));
|
||||
ShumwayCom.reportIssue();
|
||||
}
|
||||
|
||||
function showAbout() {
|
||||
window.open('http://areweflashyet.com/');
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
ShumwayCom.enableDebug();
|
||||
}
|
||||
|
||||
var playerWindow, gfxWindow;
|
||||
|
||||
function parseSwf(url, baseUrl, movieParams, objectParams, settings,
|
||||
initStartTime, backgroundColor) {
|
||||
var compilerSettings = settings.compilerSettings;
|
||||
var playerSettings = settings.playerSettings;
|
||||
|
||||
displayParametersReady.then(function (displayParameters) {
|
||||
var data = {
|
||||
type: 'runSwf',
|
||||
flashParams: {
|
||||
compilerSettings: compilerSettings,
|
||||
movieParams: movieParams,
|
||||
objectParams: objectParams,
|
||||
displayParameters: displayParameters,
|
||||
turboMode: playerSettings.turboMode,
|
||||
env: playerSettings.env,
|
||||
bgcolor: backgroundColor,
|
||||
url: url,
|
||||
baseUrl: baseUrl || url,
|
||||
initStartTime: initStartTime
|
||||
}
|
||||
};
|
||||
playerWindow.postMessage(data, '*');
|
||||
});
|
||||
}
|
||||
|
||||
// We need to wait for gfx window to report display parameters before we
|
||||
// start SWF playback in the player window.
|
||||
var displayParametersResolved;
|
||||
var displayParametersReady = new Promise(function (resolve) {
|
||||
displayParametersResolved = resolve;
|
||||
});
|
||||
|
||||
var playerReady = new Promise(function (resolve) {
|
||||
function iframeLoaded() {
|
||||
if (--iframesToLoad > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfxWindow = document.getElementById('gfxIframe').contentWindow;
|
||||
playerWindow = document.getElementById('playerIframe').contentWindow;
|
||||
resolve();
|
||||
}
|
||||
|
||||
var iframesToLoad = 2;
|
||||
document.getElementById('gfxIframe').addEventListener('load', iframeLoaded);
|
||||
document.getElementById('gfxIframe').src = 'resource://shumway/web/viewer.gfx.html';
|
||||
document.getElementById('playerIframe').addEventListener('load', iframeLoaded);
|
||||
document.getElementById('playerIframe').src = 'resource://shumway/web/viewer.player.html';
|
||||
});
|
@ -1,32 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright 2013 Mozilla Foundation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<base href=""/>
|
||||
|
||||
// Loading the relooper from the asm.js cache takes 3x as long as compiling it, so no async.
|
||||
<script src="../libs/relooper.js"></script>
|
||||
<script src="../shumway.player.js"></script>
|
||||
<script src="viewerPlayer.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Shumway Player
|
||||
</body>
|
||||
</html>
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
var SHUMWAY_ROOT = "resource://shumway/";
|
||||
|
||||
var easel;
|
||||
function createEasel(backgroundColor) {
|
||||
var Stage = Shumway.GFX.Stage;
|
||||
var Easel = Shumway.GFX.Easel;
|
||||
var Canvas2DRenderer = Shumway.GFX.Canvas2DRenderer;
|
||||
|
||||
Shumway.GFX.WebGL.SHADER_ROOT = SHUMWAY_ROOT + "gfx/gl/shaders/";
|
||||
easel = new Easel(document.getElementById("easelContainer"), false, backgroundColor);
|
||||
|
||||
if (ShumwayCom.environment === 'test') {
|
||||
ShumwayCom.setScreenShotCallback(function () {
|
||||
// flush rendering buffers
|
||||
easel.render();
|
||||
return easel.screenShot(null, true, false).dataURL;
|
||||
});
|
||||
}
|
||||
|
||||
easel.startRendering();
|
||||
return easel;
|
||||
}
|
||||
|
||||
var easelHost;
|
||||
function createEaselHost() {
|
||||
var peer = new Shumway.Remoting.ShumwayComTransportPeer();
|
||||
easelHost = new Shumway.GFX.Window.WindowEaselHost(easel, peer);
|
||||
return easelHost;
|
||||
}
|
||||
|
||||
function setHudVisible(visible) {
|
||||
Shumway.GFX.hud.value = !!visible;
|
||||
}
|
||||
|
||||
function fallback() {
|
||||
parent.postMessage({callback: 'fallback'}, '*');
|
||||
}
|
||||
|
||||
function showURL() {
|
||||
parent.postMessage({callback: 'showURL'}, '*' );
|
||||
}
|
||||
|
||||
function showInInspector() {
|
||||
parent.postMessage({callback: 'showInInspector'}, '*');
|
||||
}
|
||||
|
||||
function reportIssue() {
|
||||
parent.postMessage({callback: 'reportIssue'}, '*');
|
||||
}
|
||||
|
||||
function showAbout() {
|
||||
parent.postMessage({callback: 'showAbout'}, '*');
|
||||
}
|
||||
|
||||
function enableDebug() {
|
||||
parent.postMessage({callback: 'enableDebug'}, '*');
|
||||
}
|
||||
|
||||
function prepareUI(params) {
|
||||
if (params.isOverlay) {
|
||||
var fallbackMenu = document.getElementById('fallbackMenu');
|
||||
fallbackMenu.removeAttribute('hidden');
|
||||
fallbackMenu.addEventListener('click', fallback);
|
||||
}
|
||||
document.getElementById('showURLMenu').addEventListener('click', showURL);
|
||||
document.getElementById('inspectorMenu').addEventListener('click', showInInspector);
|
||||
document.getElementById('reportMenu').addEventListener('click', reportIssue);
|
||||
document.getElementById('aboutMenu').addEventListener('click', showAbout);
|
||||
|
||||
var version = Shumway.version || '';
|
||||
document.getElementById('aboutMenu').label =
|
||||
document.getElementById('aboutMenu').label.replace('%version%', version);
|
||||
|
||||
if (params.isDebuggerEnabled) {
|
||||
document.getElementById('debugMenu').addEventListener('click', enableDebug);
|
||||
} else {
|
||||
document.getElementById('debugMenu').remove();
|
||||
}
|
||||
|
||||
setHudVisible(params.isHudOn);
|
||||
|
||||
createEasel(params.backgroundColor);
|
||||
createEaselHost();
|
||||
|
||||
var displayParameters = easel.getDisplayParameters();
|
||||
window.parent.postMessage({
|
||||
callback: 'displayParameters',
|
||||
params: displayParameters
|
||||
}, '*');
|
||||
}
|
||||
|
||||
window.addEventListener('message', function onWindowMessage(e) {
|
||||
var data = e.data;
|
||||
if (typeof data !== 'object' || data === null) {
|
||||
console.error('Unexpected message for gfx frame.');
|
||||
return;
|
||||
}
|
||||
switch (data.type) {
|
||||
case "prepareUI":
|
||||
prepareUI(data.params);
|
||||
break;
|
||||
default:
|
||||
console.error('Unexpected message for gfx frame: ' + args.callback);
|
||||
break;
|
||||
}
|
||||
}, true);
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
window.print = function(msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
function runSwfPlayer(flashParams, settings) {
|
||||
console.info('Time from init start to SWF player start: ' + (Date.now() - flashParams.initStartTime));
|
||||
if (settings) {
|
||||
Shumway.Settings.setSettings(settings);
|
||||
}
|
||||
setupServices();
|
||||
|
||||
var asyncLoading = true;
|
||||
var baseUrl = flashParams.baseUrl;
|
||||
var objectParams = flashParams.objectParams;
|
||||
var movieUrl = flashParams.url;
|
||||
|
||||
if (ShumwayCom.environment === 'test') {
|
||||
Shumway.frameRateOption.value = 60;
|
||||
Shumway.dontSkipFramesOption.value = true;
|
||||
|
||||
window.print = function(msg) {
|
||||
ShumwayCom.print(msg.toString());
|
||||
};
|
||||
|
||||
Shumway.Random.reset();
|
||||
Shumway.installTimeWarper();
|
||||
} else {
|
||||
Shumway.frameRateOption.value = flashParams.turboMode ? 60 : -1;
|
||||
}
|
||||
|
||||
Shumway.createSecurityDomain(Shumway.AVM2LoadLibrariesFlags.Builtin | Shumway.AVM2LoadLibrariesFlags.Playerglobal).then(function (securityDomain) {
|
||||
function runSWF(file, buffer, baseUrl) {
|
||||
var peer = new Shumway.Remoting.ShumwayComTransportPeer();
|
||||
var gfxService = new Shumway.Player.Window.WindowGFXService(securityDomain, peer);
|
||||
var player = new Shumway.Player.Player(securityDomain, gfxService, flashParams.env);
|
||||
player.defaultStageColor = flashParams.bgcolor;
|
||||
player.movieParams = flashParams.movieParams;
|
||||
player.stageAlign = (objectParams && (objectParams.salign || objectParams.align)) || '';
|
||||
player.stageScale = (objectParams && objectParams.scale) || 'showall';
|
||||
player.displayParameters = flashParams.displayParameters;
|
||||
player.initStartTime = flashParams.initStartTime;
|
||||
|
||||
player.pageUrl = baseUrl;
|
||||
console.info('Time from init start to SWF loading start: ' + (Date.now() - flashParams.initStartTime));
|
||||
player.load(file, buffer);
|
||||
playerStarted();
|
||||
}
|
||||
|
||||
Shumway.FileLoadingService.instance.init(baseUrl);
|
||||
if (asyncLoading) {
|
||||
runSWF(movieUrl, undefined, baseUrl);
|
||||
} else {
|
||||
new Shumway.BinaryFileReader(movieUrl).readAll(null, function(buffer, error) {
|
||||
if (!buffer) {
|
||||
throw "Unable to open the file " + movieUrl + ": " + error;
|
||||
}
|
||||
runSWF(movieUrl, buffer, baseUrl);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupServices() {
|
||||
Shumway.Telemetry.instance = new Shumway.Player.ShumwayComTelemetryService();
|
||||
Shumway.ExternalInterfaceService.instance = new Shumway.Player.ShumwayComExternalInterface();
|
||||
Shumway.ClipboardService.instance = new Shumway.Player.ShumwayComClipboardService();
|
||||
Shumway.FileLoadingService.instance = new Shumway.Player.ShumwayComFileLoadingService();
|
||||
Shumway.SystemResourcesLoadingService.instance = new Shumway.Player.ShumwayComResourcesLoadingService(true);
|
||||
Shumway.LocalConnectionService.instance = new Shumway.Player.ShumwayComLocalConnectionService();
|
||||
}
|
||||
|
||||
function playerStarted() {
|
||||
document.body.style.backgroundColor = 'green';
|
||||
window.parent.postMessage({
|
||||
callback: 'started'
|
||||
}, '*');
|
||||
}
|
||||
|
||||
window.addEventListener('message', function onWindowMessage(e) {
|
||||
var data = e.data;
|
||||
if (typeof data !== 'object' || data === null) {
|
||||
console.error('Unexpected message for player frame.');
|
||||
return;
|
||||
}
|
||||
switch (data.type) {
|
||||
case "runSwf":
|
||||
if (data.settings) {
|
||||
Shumway.Settings.setSettings(data.settings);
|
||||
}
|
||||
setupServices();
|
||||
runSwfPlayer(data.flashParams, data.settings);
|
||||
break;
|
||||
default:
|
||||
console.error('Unexpected message for player frame: ' + args.callback);
|
||||
break;
|
||||
}
|
||||
}, true);
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
importScripts(['../shumway.parser.js']);
|
||||
|
||||
var loader = new Shumway.SWF.ResourceLoader(this, true);
|
@ -1,5 +0,0 @@
|
||||
shumway.jar:
|
||||
% content shumway %chrome/
|
||||
% resource shumway %content/
|
||||
chrome/ (chrome/*)
|
||||
content/ (content/*)
|
@ -1,7 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
@ -654,10 +654,6 @@
|
||||
@RESPATH@/browser/chrome/browser.manifest
|
||||
@RESPATH@/browser/chrome/pdfjs.manifest
|
||||
@RESPATH@/browser/chrome/pdfjs/*
|
||||
#ifdef NIGHTLY_BUILD
|
||||
@RESPATH@/browser/chrome/shumway.manifest
|
||||
@RESPATH@/browser/chrome/shumway/*
|
||||
#endif
|
||||
@RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/chrome.manifest
|
||||
@RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/icon.png
|
||||
@RESPATH@/browser/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/install.rdf
|
||||
|
Loading…
Reference in New Issue
Block a user