mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to inbound, a=merge
MozReview-Commit-ID: 3PWdAnh0hk5
This commit is contained in:
commit
092655aa0a
@ -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.
|
||||
@ -152,10 +151,6 @@ mobile/android/locales/
|
||||
# Pretty sure we're disabling this one anyway
|
||||
mobile/android/modules/ContactService.jsm
|
||||
|
||||
# es7 proposed: array comprehensions
|
||||
# https://github.com/eslint/espree/issues/125
|
||||
mobile/android/modules/WebappManager.jsm
|
||||
|
||||
# Non-standard `(catch ex if ...)`
|
||||
mobile/android/components/Snippets.js
|
||||
|
||||
|
@ -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.)
|
||||
|
@ -6648,6 +6648,18 @@ var gIdentityHandler = {
|
||||
this._identityPopup.hidePopup();
|
||||
},
|
||||
|
||||
removeCertException() {
|
||||
if (!this._uriHasHost) {
|
||||
Cu.reportError("Trying to revoke a cert exception on a URI without a host?");
|
||||
return;
|
||||
}
|
||||
let host = this._uri.host;
|
||||
let port = this._uri.port > 0 ? this._uri.port : 443;
|
||||
this._overrideService.clearValidityOverride(host, port);
|
||||
BrowserReloadSkipCache();
|
||||
this._identityPopup.hidePopup();
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper to parse out the important parts of _sslStatus (of the SSL cert in
|
||||
* particular) for use in constructing identity UI strings
|
||||
|
@ -153,22 +153,28 @@ Sanitizer.prototype = {
|
||||
};
|
||||
|
||||
// Array of objects in form { name, promise }.
|
||||
// Name is the itemName and promise may be a promise, if the sanitization
|
||||
// is asynchronous, or the function return value, if synchronous.
|
||||
let promises = [];
|
||||
// `name` is the item's name and `promise` may be a promise, if the
|
||||
// sanitization is asynchronous, or the function return value, otherwise.
|
||||
let handles = [];
|
||||
for (let itemName of itemsToClear) {
|
||||
let item = this.items[itemName];
|
||||
// Workaround for bug 449811.
|
||||
let name = itemName;
|
||||
let item = this.items[name];
|
||||
try {
|
||||
// Note we need to catch errors here, otherwise Promise.all would stop
|
||||
// at the first rejection.
|
||||
promises.push(item.clear(range)
|
||||
.then(() => progress[itemName] = "cleared",
|
||||
ex => annotateError(itemName, ex)));
|
||||
// Catch errors here, so later we can just loop through these.
|
||||
handles.push({ name,
|
||||
promise: item.clear(range)
|
||||
.then(() => progress[name] = "cleared",
|
||||
ex => annotateError(name, ex))
|
||||
});
|
||||
} catch (ex) {
|
||||
annotateError(itemName, ex);
|
||||
annotateError(name, ex);
|
||||
}
|
||||
}
|
||||
yield Promise.all(promises);
|
||||
for (let handle of handles) {
|
||||
progress[handle.name] = "blocking";
|
||||
yield handle.promise;
|
||||
}
|
||||
|
||||
// Sanitization is complete.
|
||||
TelemetryStopwatch.finish("FX_SANITIZE_TOTAL", refObj);
|
||||
|
@ -117,6 +117,12 @@
|
||||
<description id="identity-popup-content-verifier"
|
||||
when-connection="secure secure-ev secure-cert-user-overridden"/>
|
||||
|
||||
<!-- Remove Certificate Exception -->
|
||||
<button when-connection="secure-cert-user-overridden"
|
||||
label="&identity.removeCertException.label;"
|
||||
accesskey="&identity.removeCertException.accesskey;"
|
||||
oncommand="gIdentityHandler.removeCertException()"/>
|
||||
|
||||
<!-- Connection is Not Secure -->
|
||||
<description when-connection="not-secure"
|
||||
and-when-loginforms="secure">&identity.description.insecure;</description>
|
||||
|
@ -2,36 +2,208 @@
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://devtools/shared/event-emitter.js");
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
|
||||
var {
|
||||
PlatformInfo,
|
||||
EventManager,
|
||||
PlatformInfo,
|
||||
} = ExtensionUtils;
|
||||
|
||||
// WeakMap[Extension -> Map[name => Command]]
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
// WeakMap[Extension -> CommandList]
|
||||
var commandsMap = new WeakMap();
|
||||
|
||||
function Command(description, shortcut) {
|
||||
this.description = description;
|
||||
this.shortcut = shortcut;
|
||||
function CommandList(commandsObj, extensionID) {
|
||||
this.commands = this.loadCommandsFromManifest(commandsObj);
|
||||
this.keysetID = `ext-keyset-id-${makeWidgetId(extensionID)}`;
|
||||
this.windowOpenListener = null;
|
||||
this.register();
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
||||
CommandList.prototype = {
|
||||
/**
|
||||
* Registers the commands to all open windows and to any which
|
||||
* are later created.
|
||||
*/
|
||||
register() {
|
||||
for (let window of WindowListManager.browserWindows()) {
|
||||
this.registerKeysToDocument(window.document);
|
||||
}
|
||||
|
||||
this.windowOpenListener = (window) => {
|
||||
this.registerKeysToDocument(window.document);
|
||||
};
|
||||
|
||||
WindowListManager.addOpenListener(this.windowOpenListener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Unregisters the commands from all open windows and stops commands
|
||||
* from being registered to windows which are later created.
|
||||
*/
|
||||
unregister() {
|
||||
for (let window of WindowListManager.browserWindows()) {
|
||||
let keyset = window.document.getElementById(this.keysetID);
|
||||
if (keyset) {
|
||||
keyset.remove();
|
||||
}
|
||||
}
|
||||
|
||||
WindowListManager.removeOpenListener(this.windowOpenListener);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a Map from commands for each command in the manifest.commands object.
|
||||
* @param {Object} commandsObj The manifest.commands JSON object.
|
||||
*/
|
||||
loadCommandsFromManifest(commandsObj) {
|
||||
let commands = new Map();
|
||||
// For Windows, chrome.runtime expects 'win' while chrome.commands
|
||||
// expects 'windows'. We can special case this for now.
|
||||
let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
|
||||
for (let name of Object.keys(commandsObj)) {
|
||||
let command = commandsObj[name];
|
||||
commands.set(name, {
|
||||
description: command.description,
|
||||
shortcut: command.suggested_key[os] || command.suggested_key.default,
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
},
|
||||
|
||||
/**
|
||||
* Registers the commands to a document.
|
||||
* @param {Document} doc The XUL document to insert the Keyset.
|
||||
*/
|
||||
registerKeysToDocument(doc) {
|
||||
let keyset = doc.createElementNS(XUL_NS, "keyset");
|
||||
keyset.id = this.keysetID;
|
||||
this.commands.forEach((command, name) => {
|
||||
let keyElement = this.buildKey(doc, name, command.shortcut);
|
||||
keyset.appendChild(keyElement);
|
||||
});
|
||||
doc.documentElement.appendChild(keyset);
|
||||
},
|
||||
|
||||
/**
|
||||
* Builds a XUL Key element and attaches an onCommand listener which
|
||||
* emits a command event with the provided name when fired.
|
||||
*
|
||||
* @param {Document} doc The XUL document.
|
||||
* @param {String} name The name of the command.
|
||||
* @param {String} shortcut The shortcut provided in the manifest.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/key
|
||||
*
|
||||
* @returns {Document} The newly created Key element.
|
||||
*/
|
||||
buildKey(doc, name, shortcut) {
|
||||
let keyElement = this.buildKeyFromShortcut(doc, shortcut);
|
||||
|
||||
// We need to have the attribute "oncommand" for the "command" listener to fire,
|
||||
// and it is currently ignored when set to the empty string.
|
||||
keyElement.setAttribute("oncommand", "//");
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
// We remove all references to the key elements when the extension is shutdown,
|
||||
// therefore the listeners for these elements will be garbage collected.
|
||||
keyElement.addEventListener("command", (event) => {
|
||||
this.emit("command", name);
|
||||
});
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
|
||||
return keyElement;
|
||||
},
|
||||
|
||||
/**
|
||||
* Builds a XUL Key element from the provided shortcut.
|
||||
*
|
||||
* @param {Document} doc The XUL document.
|
||||
* @param {String} name The name of the command.
|
||||
* @param {String} shortcut The shortcut provided in the manifest.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/key
|
||||
* @returns {Document} The newly created Key element.
|
||||
*/
|
||||
buildKeyFromShortcut(doc, shortcut) {
|
||||
let keyElement = doc.createElementNS(XUL_NS, "key");
|
||||
|
||||
let parts = shortcut.split("+");
|
||||
|
||||
// The key is always the last element.
|
||||
let chromeKey = parts.pop();
|
||||
|
||||
// The modifiers are the remaining elements.
|
||||
keyElement.setAttribute("modifiers", this.getModifiersAttribute(parts));
|
||||
|
||||
if (/^[A-Z0-9]$/.test(chromeKey)) {
|
||||
// We use the key attribute for all single digits and characters.
|
||||
keyElement.setAttribute("key", chromeKey);
|
||||
} else {
|
||||
keyElement.setAttribute("keycode", this.getKeycodeAttribute(chromeKey));
|
||||
}
|
||||
|
||||
return keyElement;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the corresponding XUL keycode from the given chrome key.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* input | output
|
||||
* ---------------------------------------
|
||||
* "PageUP" | "VK_PAGE_UP"
|
||||
* "Delete" | "VK_DELETE"
|
||||
*
|
||||
* @param {String} key The chrome key (e.g. "PageUp", "Space", ...)
|
||||
* @return The constructed value for the Key's 'keycode' attribute.
|
||||
*/
|
||||
getKeycodeAttribute(chromeKey) {
|
||||
return `VK${chromeKey.replace(/([A-Z])/g, "_$&").toUpperCase()}`;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines the corresponding XUL modifiers from the chrome modifiers.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* input | output
|
||||
* ---------------------------------------
|
||||
* ["Ctrl", "Shift"] | "accel shift"
|
||||
* ["MacCtrl"] | "control"
|
||||
*
|
||||
* @param {Array} chromeModifiers The array of chrome modifiers.
|
||||
* @return The constructed value for the Key's 'modifiers' attribute.
|
||||
*/
|
||||
getModifiersAttribute(chromeModifiers) {
|
||||
let modifiersMap = {
|
||||
"Alt" : "alt",
|
||||
"Command" : "accel",
|
||||
"Ctrl" : "accel",
|
||||
"MacCtrl" : "control",
|
||||
"Shift" : "shift",
|
||||
};
|
||||
return Array.from(chromeModifiers, modifier => {
|
||||
return modifiersMap[modifier];
|
||||
}).join(" ");
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
extensions.on("manifest_commands", (type, directive, extension, manifest) => {
|
||||
let commands = new Map();
|
||||
for (let name of Object.keys(manifest.commands)) {
|
||||
let os = PlatformInfo.os == "win" ? "windows" : PlatformInfo.os;
|
||||
let manifestCommand = manifest.commands[name];
|
||||
let description = manifestCommand.description;
|
||||
let shortcut = manifestCommand.suggested_key[os] || manifestCommand.suggested_key.default;
|
||||
let command = new Command(description, shortcut);
|
||||
commands.set(name, command);
|
||||
}
|
||||
commandsMap.set(extension, commands);
|
||||
commandsMap.set(extension, new CommandList(manifest.commands, extension.id));
|
||||
});
|
||||
|
||||
extensions.on("shutdown", (type, extension) => {
|
||||
commandsMap.delete(extension);
|
||||
let commandsList = commandsMap.get(extension);
|
||||
if (commandsList) {
|
||||
commandsList.unregister();
|
||||
commandsMap.delete(extension);
|
||||
}
|
||||
});
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
|
||||
@ -39,15 +211,24 @@ extensions.registerSchemaAPI("commands", null, (extension, context) => {
|
||||
return {
|
||||
commands: {
|
||||
getAll() {
|
||||
let commands = Array.from(commandsMap.get(extension), ([name, command]) => {
|
||||
let commands = commandsMap.get(extension).commands;
|
||||
return Promise.resolve(Array.from(commands, ([name, command]) => {
|
||||
return ({
|
||||
name,
|
||||
description: command.description,
|
||||
shortcut: command.shortcut,
|
||||
});
|
||||
});
|
||||
return Promise.resolve(commands);
|
||||
}));
|
||||
},
|
||||
onCommand: new EventManager(context, "commands.onCommand", fire => {
|
||||
let listener = (event, name) => {
|
||||
fire(name);
|
||||
};
|
||||
commandsMap.get(extension).on("command", listener);
|
||||
return () => {
|
||||
commandsMap.get(extension).off("command", listener);
|
||||
};
|
||||
}).api(),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
@ -828,12 +828,26 @@ extensions.registerSchemaAPI("tabs", null, (extension, context) => {
|
||||
|
||||
let gBrowser = tab.ownerDocument.defaultView.gBrowser;
|
||||
let newTab = gBrowser.duplicateTab(tab);
|
||||
gBrowser.moveTabTo(newTab, tab._tPos + 1);
|
||||
gBrowser.selectTabAtIndex(newTab._tPos);
|
||||
|
||||
return new Promise(resolve => {
|
||||
// We need to use SSTabRestoring because any attributes set before
|
||||
// are ignored. SSTabRestored is too late and results in a jump in
|
||||
// the UI. See http://bit.ly/session-store-api for more information.
|
||||
newTab.addEventListener("SSTabRestoring", function listener() {
|
||||
// As the tab is restoring, move it to the correct position.
|
||||
newTab.removeEventListener("SSTabRestoring", listener);
|
||||
// Pinned tabs that are duplicated are inserted
|
||||
// after the existing pinned tab and pinned.
|
||||
if (tab.pinned) {
|
||||
gBrowser.pinTab(newTab);
|
||||
}
|
||||
gBrowser.moveTabTo(newTab, tab._tPos + 1);
|
||||
});
|
||||
|
||||
newTab.addEventListener("SSTabRestored", function listener() {
|
||||
// Once it has been restored, select it and return the promise.
|
||||
newTab.removeEventListener("SSTabRestored", listener);
|
||||
gBrowser.selectedTab = newTab;
|
||||
return resolve(TabManager.convert(extension, newTab));
|
||||
});
|
||||
});
|
||||
|
@ -107,7 +107,6 @@
|
||||
"events": [
|
||||
{
|
||||
"name": "onCommand",
|
||||
"unsupported": true,
|
||||
"description": "Fired when a registered command is activated using a keyboard shortcut.",
|
||||
"type": "function",
|
||||
"parameters": [
|
||||
|
@ -11,7 +11,6 @@ support-files =
|
||||
file_iframe_document.sjs
|
||||
|
||||
[browser_ext_simple.js]
|
||||
[browser_ext_commands.js]
|
||||
[browser_ext_currentWindow.js]
|
||||
[browser_ext_browserAction_simple.js]
|
||||
[browser_ext_browserAction_pageAction_icon.js]
|
||||
@ -22,6 +21,8 @@ support-files =
|
||||
[browser_ext_browserAction_popup.js]
|
||||
[browser_ext_popup_api_injection.js]
|
||||
[browser_ext_contextMenus.js]
|
||||
[browser_ext_commands_getAll.js]
|
||||
[browser_ext_commands_onCommand.js]
|
||||
[browser_ext_getViews.js]
|
||||
[browser_ext_lastError.js]
|
||||
[browser_ext_runtime_setUninstallURL.js]
|
||||
|
@ -0,0 +1,74 @@
|
||||
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
add_task(function* () {
|
||||
// Create a window before the extension is loaded.
|
||||
let win1 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots");
|
||||
yield BrowserTestUtils.browserLoaded(win1.gBrowser.selectedBrowser);
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"name": "Commands Extension",
|
||||
"commands": {
|
||||
"toggle-feature-using-alt-shift-3": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+3",
|
||||
},
|
||||
},
|
||||
"toggle-feature-using-alt-shift-comma": {
|
||||
"suggested_key": {
|
||||
"default": "Alt+Shift+Comma",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.commands.onCommand.addListener((message) => {
|
||||
browser.test.sendMessage("oncommand", message);
|
||||
});
|
||||
browser.test.sendMessage("ready");
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitMessage("ready");
|
||||
|
||||
// Create another window after the extension is loaded.
|
||||
let win2 = yield BrowserTestUtils.openNewBrowserWindow();
|
||||
yield BrowserTestUtils.loadURI(win2.gBrowser.selectedBrowser, "about:config");
|
||||
yield BrowserTestUtils.browserLoaded(win2.gBrowser.selectedBrowser);
|
||||
|
||||
// Confirm the keysets have been added to both windows.
|
||||
let keysetID = `ext-keyset-id-${makeWidgetId(extension.id)}`;
|
||||
let keyset = win1.document.getElementById(keysetID);
|
||||
is(keyset.childNodes.length, 2, "Expected keyset to exist and have 2 children");
|
||||
|
||||
keyset = win2.document.getElementById(keysetID);
|
||||
is(keyset.childNodes.length, 2, "Expected keyset to exist and have 2 children");
|
||||
|
||||
// Confirm that the commands are registered to both windows.
|
||||
yield focusWindow(win1);
|
||||
EventUtils.synthesizeKey("3", {altKey: true, shiftKey: true});
|
||||
let message = yield extension.awaitMessage("oncommand");
|
||||
is(message, "toggle-feature-using-alt-shift-3", "Expected onCommand listener to fire with correct message");
|
||||
|
||||
yield focusWindow(win2);
|
||||
EventUtils.synthesizeKey("VK_COMMA", {altKey: true, shiftKey: true});
|
||||
message = yield extension.awaitMessage("oncommand");
|
||||
is(message, "toggle-feature-using-alt-shift-comma", "Expected onCommand listener to fire with correct message");
|
||||
|
||||
yield extension.unload();
|
||||
|
||||
// Confirm that the keysets have been removed from both windows after the extension is unloaded.
|
||||
keyset = win1.document.getElementById(keysetID);
|
||||
is(keyset, null, "Expected keyset to be removed from the window");
|
||||
|
||||
keyset = win2.document.getElementById(keysetID);
|
||||
is(keyset, null, "Expected keyset to be removed from the window");
|
||||
|
||||
yield BrowserTestUtils.closeWindow(win1);
|
||||
yield BrowserTestUtils.closeWindow(win2);
|
||||
});
|
@ -35,10 +35,42 @@ add_task(function* testDuplicateTab() {
|
||||
yield extension.awaitFinish("tabs.duplicate");
|
||||
yield extension.unload();
|
||||
|
||||
while (window.gBrowser.tabs.length > 1) {
|
||||
let tab = window.gBrowser.tabs[0];
|
||||
if (tab.linkedBrowser.currentURI.spec === "http://example.net/") {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
while (gBrowser.tabs[0].linkedBrowser.currentURI.spec === "http://example.net/") {
|
||||
yield BrowserTestUtils.removeTab(gBrowser.tabs[0]);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* testDuplicatePinnedTab() {
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.net/");
|
||||
gBrowser.pinTab(tab);
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
"permissions": ["tabs"],
|
||||
},
|
||||
|
||||
background: function() {
|
||||
browser.tabs.query({
|
||||
lastFocusedWindow: true,
|
||||
}, function(tabs) {
|
||||
// Duplicate the pinned tab, example.net.
|
||||
browser.tabs.duplicate(tabs[0].id, (tab) => {
|
||||
browser.test.assertEq("http://example.net/", tab.url);
|
||||
// Should be the second tab, next to the one duplicated.
|
||||
browser.test.assertEq(1, tab.index);
|
||||
// Should be pinned.
|
||||
browser.test.assertTrue(tab.pinned);
|
||||
browser.test.notifyPass("tabs.duplicate.pinned");
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
yield extension.awaitFinish("tabs.duplicate.pinned");
|
||||
yield extension.unload();
|
||||
|
||||
while (gBrowser.tabs[0].linkedBrowser.currentURI.spec === "http://example.net/") {
|
||||
yield BrowserTestUtils.removeTab(gBrowser.tabs[0]);
|
||||
}
|
||||
});
|
||||
|
@ -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";
|
||||
|
@ -33,7 +33,6 @@ support-files =
|
||||
skip-if = e10s # Bug ?????? - test fails - "Number of dragged items should be the same. - Got 0, expected 1"
|
||||
[browser_forgetthissite_single.js]
|
||||
[browser_history_sidebar_search.js]
|
||||
skip-if = e10s && (os == 'linux' || os == 'mac') # Bug 1116457
|
||||
[browser_library_batch_delete.js]
|
||||
[browser_library_commands.js]
|
||||
[browser_library_downloads.js]
|
||||
|
@ -1,89 +1,64 @@
|
||||
/* 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/. */
|
||||
add_task(function* test () {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
|
||||
/**
|
||||
* Bug 392497 - search in history sidebar loses sort
|
||||
*/
|
||||
// Visited pages listed by descending visit date.
|
||||
let pages = [
|
||||
"http://sidebar.mozilla.org/a",
|
||||
"http://sidebar.mozilla.org/b",
|
||||
"http://sidebar.mozilla.org/c",
|
||||
"http://www.mozilla.org/d",
|
||||
];
|
||||
|
||||
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
var bh = hs.QueryInterface(Ci.nsIBrowserHistory);
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
function uri(spec) {
|
||||
return ios.newURI(spec, null, null);
|
||||
}
|
||||
// Number of pages that will be filtered out by the search.
|
||||
const FILTERED_COUNT = 1;
|
||||
|
||||
var sidebar = document.getElementById("sidebar");
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
|
||||
// Visited pages listed by descending visit date.
|
||||
var pages = [
|
||||
"http://sidebar.mozilla.org/a",
|
||||
"http://sidebar.mozilla.org/b",
|
||||
"http://sidebar.mozilla.org/c",
|
||||
"http://www.mozilla.org/d",
|
||||
];
|
||||
// Number of pages that will be filtered out by the search.
|
||||
const FILTERED_COUNT = 1;
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Cleanup.
|
||||
PlacesTestUtils.clearHistory().then(continue_test);
|
||||
}
|
||||
|
||||
function continue_test() {
|
||||
// Add some visited page.
|
||||
var time = Date.now();
|
||||
var pagesLength = pages.length;
|
||||
var places = [];
|
||||
for (var i = 0; i < pagesLength; i++) {
|
||||
places.push({uri: uri(pages[i]), visitDate: (time - i) * 1000,
|
||||
transition: hs.TRANSITION_TYPED});
|
||||
let time = Date.now();
|
||||
let places = [];
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
places.push({ uri: NetUtil.newURI(pages[i]),
|
||||
visitDate: (time - i) * 1000,
|
||||
transition: PlacesUtils.history.TRANSITION_TYPED });
|
||||
}
|
||||
PlacesTestUtils.addVisits(places).then(() => {
|
||||
SidebarUI.show("viewHistorySidebar");
|
||||
yield PlacesTestUtils.addVisits(places);
|
||||
|
||||
yield withSidebarTree("history", function* () {
|
||||
info("Set 'by last visited' view");
|
||||
sidebar.contentDocument.getElementById("bylastvisited").doCommand();
|
||||
let tree = sidebar.contentDocument.getElementById("historyTree");
|
||||
check_tree_order(tree, pages);
|
||||
|
||||
// Set a search value.
|
||||
let searchBox = sidebar.contentDocument.getElementById("search-box");
|
||||
ok(searchBox, "search box is in context");
|
||||
searchBox.value = "sidebar.mozilla";
|
||||
searchBox.doCommand();
|
||||
check_tree_order(tree, pages, -FILTERED_COUNT);
|
||||
|
||||
info("Reset the search");
|
||||
searchBox.value = "";
|
||||
searchBox.doCommand();
|
||||
check_tree_order(tree, pages);
|
||||
});
|
||||
|
||||
sidebar.addEventListener("load", function() {
|
||||
sidebar.removeEventListener("load", arguments.callee, true);
|
||||
executeSoon(function() {
|
||||
// Set "by last visited" in the sidebar (sort by visit date descendind).
|
||||
sidebar.contentDocument.getElementById("bylastvisited").doCommand();
|
||||
check_sidebar_tree_order(pages.length);
|
||||
var searchBox = sidebar.contentDocument.getElementById("search-box");
|
||||
ok(searchBox, "search box is in context");
|
||||
searchBox.value = "sidebar.mozilla";
|
||||
searchBox.doCommand();
|
||||
check_sidebar_tree_order(pages.length - FILTERED_COUNT);
|
||||
searchBox.value = "";
|
||||
searchBox.doCommand();
|
||||
check_sidebar_tree_order(pages.length);
|
||||
yield PlacesTestUtils.clearHistory();
|
||||
});
|
||||
|
||||
// Cleanup.
|
||||
SidebarUI.hide();
|
||||
PlacesTestUtils.clearHistory().then(finish);
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
function check_sidebar_tree_order(aExpectedRows) {
|
||||
var tree = sidebar.contentDocument.getElementById("historyTree");
|
||||
var treeView = tree.view;
|
||||
var rc = treeView.rowCount;
|
||||
var columns = tree.columns;
|
||||
function check_tree_order(tree, pages, aNumberOfRowsDelta = 0) {
|
||||
let treeView = tree.view;
|
||||
let columns = tree.columns;
|
||||
is(columns.count, 1, "There should be only 1 column in the sidebar");
|
||||
var found = 0;
|
||||
for (var r = 0; r < rc; r++) {
|
||||
var node = treeView.nodeForTreeIndex(r);
|
||||
// We could inherit visits from previous tests, skip them since they are
|
||||
// not interesting for us.
|
||||
|
||||
let found = 0;
|
||||
for (let i = 0; i < treeView.rowCount; i++) {
|
||||
let node = treeView.nodeForTreeIndex(i);
|
||||
// We could inherit delayed visits from previous tests, skip them.
|
||||
if (!pages.includes(node.uri))
|
||||
continue;
|
||||
is(node.uri, pages[r], "Node is in correct position based on its visit date");
|
||||
is(node.uri, pages[i], "Node is in correct position based on its visit date");
|
||||
found++;
|
||||
}
|
||||
ok(found, aExpectedRows, "Found all expected results");
|
||||
ok(found, pages.length + aNumberOfRowsDelta, "Found all expected results");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -777,6 +777,9 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
||||
<!ENTITY identity.disableMixedContentBlocking.accesskey "D">
|
||||
<!ENTITY identity.learnMore "Learn More">
|
||||
|
||||
<!ENTITY identity.removeCertException.label "Remove Exception">
|
||||
<!ENTITY identity.removeCertException.accesskey "R">
|
||||
|
||||
<!ENTITY identity.moreInfoLinkText2 "More Information">
|
||||
|
||||
<!ENTITY identity.permissions "Permissions">
|
||||
|
@ -51,6 +51,7 @@ button {
|
||||
|
||||
.target {
|
||||
margin-top: 5px;
|
||||
min-height: 34px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
@ -38,6 +38,13 @@ module.exports = createClass({
|
||||
dom.div({ className: "target-details" },
|
||||
dom.div({ className: "target-name" }, target.name)
|
||||
),
|
||||
(isRunning && isServiceWorker ?
|
||||
dom.button({
|
||||
className: "push-button",
|
||||
onClick: this.push
|
||||
}, Strings.GetStringFromName("push")) :
|
||||
null
|
||||
),
|
||||
(isRunning ?
|
||||
dom.button({
|
||||
className: "debug-button",
|
||||
@ -72,6 +79,16 @@ module.exports = createClass({
|
||||
}
|
||||
},
|
||||
|
||||
push() {
|
||||
let { client, target } = this.props;
|
||||
if (target.workerActor) {
|
||||
client.request({
|
||||
to: target.workerActor,
|
||||
type: "push"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
openWorkerToolbox(workerActor) {
|
||||
let { client } = this.props;
|
||||
client.attachWorker(workerActor, (response, workerClient) => {
|
||||
|
@ -7,9 +7,12 @@ support-files =
|
||||
addons/unpacked/install.rdf
|
||||
service-workers/empty-sw.html
|
||||
service-workers/empty-sw.js
|
||||
service-workers/push-sw.html
|
||||
service-workers/push-sw.js
|
||||
|
||||
[browser_addons_debugging_initial_state.js]
|
||||
[browser_addons_install.js]
|
||||
[browser_addons_toggle_debug.js]
|
||||
[browser_service_workers.js]
|
||||
[browser_service_workers_push.js]
|
||||
[browser_service_workers_timeout.js]
|
||||
|
@ -0,0 +1,98 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* eslint-disable mozilla/no-cpows-in-tests */
|
||||
/* global sendAsyncMessage */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that clicking on the Push button next to a Service Worker works as
|
||||
// intended in about:debugging.
|
||||
// It should trigger a "push" notification in the worker.
|
||||
|
||||
// Service workers can't be loaded from chrome://, but http:// is ok with
|
||||
// dom.serviceWorkers.testing.enabled turned on.
|
||||
const HTTP_ROOT = CHROME_ROOT.replace(
|
||||
"chrome://mochitests/content/", "http://mochi.test:8888/");
|
||||
const SERVICE_WORKER = HTTP_ROOT + "service-workers/push-sw.js";
|
||||
const TAB_URL = HTTP_ROOT + "service-workers/push-sw.html";
|
||||
|
||||
add_task(function* () {
|
||||
info("Turn on workers via mochitest http.");
|
||||
yield new Promise(done => {
|
||||
let options = { "set": [
|
||||
// Accept workers from mochitest's http.
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
]};
|
||||
SpecialPowers.pushPrefEnv(options, done);
|
||||
});
|
||||
|
||||
let { tab, document } = yield openAboutDebugging("workers");
|
||||
|
||||
// Listen for mutations in the service-workers list.
|
||||
let serviceWorkersElement = document.getElementById("service-workers");
|
||||
let onMutation = waitForMutation(serviceWorkersElement, { childList: true });
|
||||
|
||||
// Open a tab that registers a push service worker.
|
||||
let swTab = yield addTab(TAB_URL);
|
||||
|
||||
info("Make the test page notify us when the service worker sends a message.");
|
||||
let frameScript = function() {
|
||||
let win = content.wrappedJSObject;
|
||||
win.navigator.serviceWorker.addEventListener("message", function(event) {
|
||||
sendAsyncMessage(event.data);
|
||||
}, false);
|
||||
};
|
||||
let mm = swTab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
// Expect the service worker to claim the test window when activating.
|
||||
let onClaimed = new Promise(done => {
|
||||
mm.addMessageListener("sw-claimed", function listener() {
|
||||
mm.removeMessageListener("sw-claimed", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Wait for the service-workers list to update.
|
||||
yield onMutation;
|
||||
|
||||
// Check that the service worker appears in the UI.
|
||||
assertHasTarget(true, document, "service-workers", SERVICE_WORKER);
|
||||
|
||||
info("Ensure that the registration resolved before trying to interact with " +
|
||||
"the service worker.");
|
||||
yield waitForServiceWorkerRegistered(swTab);
|
||||
ok(true, "Service worker registration resolved");
|
||||
|
||||
// Retrieve the Push button for the worker.
|
||||
let names = [...document.querySelectorAll("#service-workers .target-name")];
|
||||
let name = names.filter(element => element.textContent === SERVICE_WORKER)[0];
|
||||
ok(name, "Found the service worker in the list");
|
||||
let targetElement = name.parentNode.parentNode;
|
||||
let pushBtn = targetElement.querySelector(".push-button");
|
||||
ok(pushBtn, "Found its push button");
|
||||
|
||||
info("Wait for the service worker to claim the test window before " +
|
||||
"proceeding.");
|
||||
yield onClaimed;
|
||||
|
||||
info("Click on the Push button and wait for the service worker to receive " +
|
||||
"a push notification");
|
||||
let onPushNotification = new Promise(done => {
|
||||
mm.addMessageListener("sw-pushed", function listener() {
|
||||
mm.removeMessageListener("sw-pushed", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
pushBtn.click();
|
||||
yield onPushNotification;
|
||||
ok(true, "Service worker received a push notification");
|
||||
|
||||
// Finally, unregister the service worker itself.
|
||||
yield unregisterServiceWorker(swTab);
|
||||
ok(true, "Service worker registration unregistered");
|
||||
|
||||
yield removeTab(swTab);
|
||||
yield closeAboutDebugging(tab);
|
||||
});
|
@ -1,9 +1,6 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* eslint-disable mozilla/no-cpows-in-tests */
|
||||
/* global sendAsyncMessage */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Service workers can't be loaded from chrome://,
|
||||
@ -15,13 +12,6 @@ const TAB_URL = HTTP_ROOT + "service-workers/empty-sw.html";
|
||||
|
||||
const SW_TIMEOUT = 1000;
|
||||
|
||||
function assertHasWorker(expected, document, type, name) {
|
||||
let names = [...document.querySelectorAll("#" + type + " .target-name")];
|
||||
names = names.map(element => element.textContent);
|
||||
is(names.includes(name), expected,
|
||||
"The " + type + " url appears in the list: " + names);
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
yield new Promise(done => {
|
||||
let options = {"set": [
|
||||
@ -42,25 +32,10 @@ add_task(function* () {
|
||||
let serviceWorkersElement = document.getElementById("service-workers");
|
||||
yield waitForMutation(serviceWorkersElement, { childList: true });
|
||||
|
||||
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
|
||||
assertHasTarget(true, document, "service-workers", SERVICE_WORKER);
|
||||
|
||||
// Ensure that the registration resolved before trying to connect to the sw
|
||||
let frameScript = function() {
|
||||
// Retrieve the `sw` promise created in the html page
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function() {
|
||||
sendAsyncMessage("sw-registered");
|
||||
});
|
||||
};
|
||||
let mm = swTab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
yield new Promise(done => {
|
||||
mm.addMessageListener("sw-registered", function listener() {
|
||||
mm.removeMessageListener("sw-registered", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
yield waitForServiceWorkerRegistered(swTab);
|
||||
ok(true, "Service worker registration resolved");
|
||||
|
||||
// Retrieve the DEBUG button for the worker
|
||||
@ -88,7 +63,7 @@ add_task(function* () {
|
||||
setTimeout(done, SW_TIMEOUT * 2);
|
||||
});
|
||||
|
||||
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
|
||||
assertHasTarget(true, document, "service-workers", SERVICE_WORKER);
|
||||
ok(targetElement.querySelector(".debug-button"),
|
||||
"The debug button is still there");
|
||||
|
||||
@ -102,35 +77,14 @@ add_task(function* () {
|
||||
ok(!targetElement.querySelector(".debug-button"),
|
||||
"The debug button was removed when the worker was killed");
|
||||
|
||||
// Finally, unregister the service worker itself
|
||||
// Use message manager to work with e10s
|
||||
frameScript = function() {
|
||||
// Retrieve the `sw` promise created in the html page
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function(registration) {
|
||||
registration.unregister().then(function() {
|
||||
sendAsyncMessage("sw-unregistered");
|
||||
},
|
||||
function(e) {
|
||||
dump("SW not unregistered; " + e + "\n");
|
||||
});
|
||||
});
|
||||
};
|
||||
mm = swTab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
yield new Promise(done => {
|
||||
mm.addMessageListener("sw-unregistered", function listener() {
|
||||
mm.removeMessageListener("sw-unregistered", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
// Finally, unregister the service worker itself.
|
||||
yield unregisterServiceWorker(swTab);
|
||||
ok(true, "Service worker registration unregistered");
|
||||
|
||||
// Now ensure that the worker registration is correctly removed.
|
||||
// The list should update once the registration is destroyed.
|
||||
yield waitForMutation(serviceWorkersElement, { childList: true });
|
||||
assertHasWorker(false, document, "service-workers", SERVICE_WORKER);
|
||||
assertHasTarget(false, document, "service-workers", SERVICE_WORKER);
|
||||
|
||||
yield removeTab(swTab);
|
||||
yield closeAboutDebugging(tab);
|
||||
|
@ -2,15 +2,18 @@
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* eslint-env browser */
|
||||
/* eslint-disable mozilla/no-cpows-in-tests */
|
||||
/* exported openAboutDebugging, closeAboutDebugging, installAddon,
|
||||
uninstallAddon, waitForMutation */
|
||||
uninstallAddon, waitForMutation, assertHasTarget,
|
||||
waitForServiceWorkerRegistered, unregisterServiceWorker */
|
||||
/* global sendAsyncMessage */
|
||||
|
||||
"use strict";
|
||||
|
||||
var {utils: Cu, classes: Cc, interfaces: Ci} = Components;
|
||||
var { utils: Cu, classes: Cc, interfaces: Ci } = Components;
|
||||
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {AddonManager} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||
const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||
const Services = require("Services");
|
||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
DevToolsUtils.testing = true;
|
||||
@ -146,3 +149,73 @@ function waitForMutation(target, mutationOptions) {
|
||||
observer.observe(target, mutationOptions);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an about:debugging TargetList element contains a Target element
|
||||
* corresponding to the specified name.
|
||||
* @param {Boolean} expected
|
||||
* @param {Document} document
|
||||
* @param {String} type
|
||||
* @param {String} name
|
||||
*/
|
||||
function assertHasTarget(expected, document, type, name) {
|
||||
let names = [...document.querySelectorAll("#" + type + " .target-name")];
|
||||
names = names.map(element => element.textContent);
|
||||
is(names.includes(name), expected,
|
||||
"The " + type + " url appears in the list: " + names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that will resolve after the service worker in the page
|
||||
* has successfully registered itself.
|
||||
* @param {Tab} tab
|
||||
*/
|
||||
function waitForServiceWorkerRegistered(tab) {
|
||||
// Make the test page notify us when the service worker is registered.
|
||||
let frameScript = function() {
|
||||
// Retrieve the `sw` promise created in the html page.
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function(registration) {
|
||||
sendAsyncMessage("sw-registered");
|
||||
});
|
||||
};
|
||||
let mm = tab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
return new Promise(done => {
|
||||
mm.addMessageListener("sw-registered", function listener() {
|
||||
mm.removeMessageListener("sw-registered", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the service worker within the test page to unregister, and returns a
|
||||
* promise that will resolve when it has successfully unregistered itself.
|
||||
* @param {Tab} tab
|
||||
*/
|
||||
function unregisterServiceWorker(tab) {
|
||||
// Use message manager to work with e10s.
|
||||
let frameScript = function() {
|
||||
// Retrieve the `sw` promise created in the html page.
|
||||
let { sw } = content.wrappedJSObject;
|
||||
sw.then(function(registration) {
|
||||
registration.unregister().then(function() {
|
||||
sendAsyncMessage("sw-unregistered");
|
||||
},
|
||||
function(e) {
|
||||
dump("SW not unregistered; " + e + "\n");
|
||||
});
|
||||
});
|
||||
};
|
||||
let mm = tab.linkedBrowser.messageManager;
|
||||
mm.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true);
|
||||
|
||||
return new Promise(done => {
|
||||
mm.addMessageListener("sw-unregistered", function listener() {
|
||||
mm.removeMessageListener("sw-unregistered", listener);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Service worker push test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
var sw = navigator.serviceWorker.register("push-sw.js");
|
||||
sw.then(
|
||||
function(registration) {
|
||||
dump("SW registered\n");
|
||||
},
|
||||
function(error) {
|
||||
dump("SW not registered: " + error + "\n");
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,33 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* eslint-env worker */
|
||||
/* global clients */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Send a message to all controlled windows.
|
||||
function postMessage(message) {
|
||||
return clients.matchAll().then(function(clientlist) {
|
||||
clientlist.forEach(function(client) {
|
||||
client.postMessage(message);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Don't wait for the next page load to become the active service worker.
|
||||
self.addEventListener("install", function(event) {
|
||||
event.waitUntil(self.skipWaiting());
|
||||
});
|
||||
|
||||
// Claim control over the currently open test page when activating.
|
||||
self.addEventListener("activate", function(event) {
|
||||
event.waitUntil(self.clients.claim().then(function() {
|
||||
return postMessage("sw-claimed");
|
||||
}));
|
||||
});
|
||||
|
||||
// Forward all "push" events to the controlled window.
|
||||
self.addEventListener("push", function(event) {
|
||||
event.waitUntil(postMessage("sw-pushed"));
|
||||
});
|
@ -13,6 +13,7 @@ support-files =
|
||||
doc_markup_events-overflow.html
|
||||
doc_markup_flashing.html
|
||||
doc_markup_html_mixed_case.html
|
||||
doc_markup_image_and_canvas.html
|
||||
doc_markup_links.html
|
||||
doc_markup_mutation.html
|
||||
doc_markup_navigation.html
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -3,6 +3,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
debug = Debug
|
||||
push = Push
|
||||
|
||||
addons = Add-ons
|
||||
addonDebugging.label = Enable add-on debugging
|
||||
|
8
devtools/client/locales/en-US/storage.dtd
Normal file
8
devtools/client/locales/en-US/storage.dtd
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- 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/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : This file contains the Storage Inspector strings. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : Placeholder for the searchbox that allows you to filter the table items. -->
|
||||
<!ENTITY searchBox.placeholder "Filter items">
|
@ -4,6 +4,9 @@
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"DTD/xhtml1-strict.dtd">
|
||||
%htmlDTD;
|
||||
<!ENTITY % globalDTD
|
||||
SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
]>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
@ -16,7 +19,7 @@
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/components-frame.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools/skin/components-h-split-box.css" type="text/css"/>
|
||||
</head>
|
||||
<body class="theme-body">
|
||||
<body class="theme-body" dir="&locale.dir;">
|
||||
<div id="app"></div>
|
||||
|
||||
<script type="application/javascript;version=1.8"
|
||||
|
@ -29,7 +29,7 @@
|
||||
<script type="application/javascript" src="views/recordings.js"/>
|
||||
|
||||
<popupset id="performance-options-popupset">
|
||||
<menupopup id="performance-filter-menupopup"/>
|
||||
<menupopup id="performance-filter-menupopup" position="before_start"/>
|
||||
<menupopup id="performance-options-menupopup" position="before_end">
|
||||
<menuitem id="option-show-platform-data"
|
||||
type="checkbox"
|
||||
|
@ -455,6 +455,25 @@ var TestActor = exports.TestActor = protocol.ActorClass({
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Get an attribute on a DOM Node.
|
||||
* @param {String} selector The node selector
|
||||
* @param {String} attribute The attribute name
|
||||
* @return {String} value The attribute value
|
||||
*/
|
||||
getAttribute: protocol.method(function (selector, attribute) {
|
||||
let node = this._querySelector(selector);
|
||||
return node.getAttribute(attribute);
|
||||
}, {
|
||||
request: {
|
||||
selector: Arg(0, "string"),
|
||||
property: Arg(1, "string")
|
||||
},
|
||||
response: {
|
||||
value: RetVal("string")
|
||||
}
|
||||
}),
|
||||
|
||||
/**
|
||||
* Set an attribute on a DOM Node.
|
||||
* @param {String} selector The node selector
|
||||
|
@ -24,6 +24,7 @@ const EVENTS = {
|
||||
ROW_CONTEXT_MENU: "row-context-menu",
|
||||
ROW_SELECTED: "row-selected",
|
||||
ROW_UPDATED: "row-updated",
|
||||
TABLE_FILTERED: "table-filtered",
|
||||
SCROLL_END: "scroll-end"
|
||||
};
|
||||
Object.defineProperty(this, "EVENTS", {
|
||||
@ -353,6 +354,7 @@ TableWidget.prototype = {
|
||||
if (key != this.sortedOn) {
|
||||
column.insertAt(item, index);
|
||||
}
|
||||
column.updateZebra();
|
||||
}
|
||||
this.items.set(item[this.uniqueId], item);
|
||||
this.tbody.removeAttribute("empty");
|
||||
@ -440,6 +442,41 @@ TableWidget.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Filters the table based on a specific value
|
||||
*
|
||||
* @param {String} value: The filter value
|
||||
* @param {Array} ignoreProps: Props to ignore while filtering
|
||||
*/
|
||||
filterItems(value, ignoreProps = []) {
|
||||
if (this.filteredValue == value) {
|
||||
return;
|
||||
}
|
||||
if (!value) {
|
||||
this.emit(EVENTS.TABLE_FILTERED, []);
|
||||
return;
|
||||
}
|
||||
this.filteredValue = value;
|
||||
// Shouldn't be case-sensitive
|
||||
value = value.toLowerCase();
|
||||
|
||||
let itemsToHide = [...this.items.keys()];
|
||||
// Loop through all items and hide unmatched items
|
||||
for (let [id, val] of this.items) {
|
||||
for (let prop in val) {
|
||||
if (ignoreProps.includes(prop)) {
|
||||
continue;
|
||||
}
|
||||
let propValue = val[prop].toString().toLowerCase();
|
||||
if (propValue.includes(value)) {
|
||||
itemsToHide.splice(itemsToHide.indexOf(id), 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.emit(EVENTS.TABLE_FILTERED, itemsToHide);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calls the afterScroll function when the user has stopped scrolling
|
||||
*/
|
||||
@ -521,6 +558,9 @@ function Column(table, id, header) {
|
||||
this.onRowUpdated = this.onRowUpdated.bind(this);
|
||||
this.table.on(EVENTS.ROW_UPDATED, this.onRowUpdated);
|
||||
|
||||
this.onTableFiltered = this.onTableFiltered.bind(this);
|
||||
this.table.on(EVENTS.TABLE_FILTERED, this.onTableFiltered);
|
||||
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.onMousedown = this.onMousedown.bind(this);
|
||||
this.onKeydown = this.onKeydown.bind(this);
|
||||
@ -597,6 +637,21 @@ Column.prototype = {
|
||||
} else {
|
||||
this.sorted = 2;
|
||||
}
|
||||
this.updateZebra();
|
||||
},
|
||||
|
||||
onTableFiltered: function(event, itemsToHide) {
|
||||
this._updateItems();
|
||||
if (!this.cells) {
|
||||
return;
|
||||
}
|
||||
for (let cell of this.cells) {
|
||||
cell.hidden = false;
|
||||
}
|
||||
for (let id of itemsToHide) {
|
||||
this.cells[this.items[id]].hidden = true;
|
||||
}
|
||||
this.updateZebra();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -612,12 +667,14 @@ Column.prototype = {
|
||||
if (this.highlightUpdated && this.items[id] != null) {
|
||||
this.cells[this.items[id]].flash();
|
||||
}
|
||||
this.updateZebra();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.table.off(EVENTS.COLUMN_SORTED, this.onColumnSorted);
|
||||
this.table.off(EVENTS.HEADER_CONTEXT_MENU, this.toggleColumn);
|
||||
this.table.off(EVENTS.ROW_UPDATED, this.onRowUpdated);
|
||||
this.table.off(EVENTS.TABLE_FILTERED, this.onTableFiltered);
|
||||
this.splitter.remove();
|
||||
this.column.parentNode.remove();
|
||||
this.cells = null;
|
||||
@ -718,6 +775,7 @@ Column.prototype = {
|
||||
}
|
||||
this.items[item[this.uniqueId]] = index;
|
||||
this.cells.splice(index, 0, new Cell(this, item, this.cells[index]));
|
||||
this.updateZebra();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -846,9 +904,21 @@ Column.prototype = {
|
||||
this.cells[this.items[this.selectedRow]].toggleClass("theme-selected");
|
||||
}
|
||||
this._itemsDirty = false;
|
||||
this.updateZebra();
|
||||
return items;
|
||||
},
|
||||
|
||||
updateZebra() {
|
||||
this._updateItems();
|
||||
let i = 0;
|
||||
for (let cell of this.cells) {
|
||||
if (!cell.hidden) {
|
||||
i++;
|
||||
}
|
||||
cell.toggleClass("even", !(i % 2));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Click event handler for the column. Used to detect click on header for
|
||||
* for sorting.
|
||||
@ -911,6 +981,12 @@ Column.prototype = {
|
||||
if (this.header == prevRow) {
|
||||
prevRow = this.column.lastChild;
|
||||
}
|
||||
while (prevRow.hasAttribute("hidden")) {
|
||||
prevRow = prevRow.previousSibling;
|
||||
if (this.header == prevRow) {
|
||||
prevRow = this.column.lastChild;
|
||||
}
|
||||
}
|
||||
this.table.emit(EVENTS.ROW_SELECTED, prevRow.getAttribute("data-id"));
|
||||
break;
|
||||
|
||||
@ -918,6 +994,10 @@ Column.prototype = {
|
||||
event.preventDefault();
|
||||
let nextRow = event.originalTarget.nextSibling ||
|
||||
this.header.nextSibling;
|
||||
while (nextRow.hasAttribute("hidden")) {
|
||||
nextRow = nextRow.nextSibling ||
|
||||
this.header.nextSibling;
|
||||
}
|
||||
this.table.emit(EVENTS.ROW_SELECTED, nextRow.getAttribute("data-id"));
|
||||
break;
|
||||
}
|
||||
@ -964,6 +1044,18 @@ Cell.prototype = {
|
||||
return this._id;
|
||||
},
|
||||
|
||||
get hidden() {
|
||||
return this.label.hasAttribute("hidden");
|
||||
},
|
||||
|
||||
set hidden(value) {
|
||||
if (value) {
|
||||
this.label.setAttribute("hidden", "hidden");
|
||||
} else {
|
||||
this.label.removeAttribute("hidden");
|
||||
}
|
||||
},
|
||||
|
||||
set value(value) {
|
||||
this._value = value;
|
||||
if (value == null) {
|
||||
@ -993,8 +1085,8 @@ Cell.prototype = {
|
||||
return this._value;
|
||||
},
|
||||
|
||||
toggleClass: function(className) {
|
||||
this.label.classList.toggle(className);
|
||||
toggleClass: function(className, condition) {
|
||||
this.label.classList.toggle(className, condition);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1005,6 +1097,11 @@ Cell.prototype = {
|
||||
this.label.classList.remove("flash-out");
|
||||
// Cause a reflow so that the animation retriggers on adding back the class
|
||||
let a = this.label.parentNode.offsetWidth; // eslint-disable-line
|
||||
let onAnimEnd = () => {
|
||||
this.label.classList.remove("flash-out");
|
||||
this.label.removeEventListener("animationend", onAnimEnd);
|
||||
};
|
||||
this.label.addEventListener("animationend", onAnimEnd);
|
||||
this.label.classList.add("flash-out");
|
||||
},
|
||||
|
||||
|
@ -7,6 +7,11 @@
|
||||
<?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://devtools/skin/storage.css" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % storageDTD SYSTEM "chrome://devtools/locale/storage.dtd">
|
||||
%storageDTD;
|
||||
]>
|
||||
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
@ -20,7 +25,15 @@
|
||||
<box flex="1" class="devtools-responsive-container theme-body">
|
||||
<vbox id="storage-tree"/>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<vbox id="storage-table" class="theme-sidebar" flex="1"/>
|
||||
<vbox flex="1">
|
||||
<hbox id="storage-toolbar" class="devtools-toolbar">
|
||||
<textbox id="storage-searchbox"
|
||||
class="devtools-searchinput"
|
||||
type="search"
|
||||
placeholder="&searchBox.placeholder;"/>
|
||||
</hbox>
|
||||
<vbox id="storage-table" class="theme-sidebar" flex="1"/>
|
||||
</vbox>
|
||||
<splitter class="devtools-side-splitter"/>
|
||||
<vbox id="storage-sidebar" class="devtools-sidebar-tabs" hidden="true">
|
||||
<vbox flex="1"/>
|
||||
|
@ -5,6 +5,7 @@ support-files =
|
||||
storage-complex-values.html
|
||||
storage-listings.html
|
||||
storage-overflow.html
|
||||
storage-search.html
|
||||
storage-secured-iframe.html
|
||||
storage-unsecured-iframe.html
|
||||
storage-updates.html
|
||||
@ -13,6 +14,7 @@ support-files =
|
||||
[browser_storage_basic.js]
|
||||
[browser_storage_dynamic_updates.js]
|
||||
[browser_storage_overflow.js]
|
||||
[browser_storage_search.js]
|
||||
[browser_storage_sidebar.js]
|
||||
skip-if = (os == 'win' && os_version == '6.1' && e10s && !debug) # bug 1229272
|
||||
[browser_storage_values.js]
|
||||
|
87
devtools/client/storage/test/browser_storage_search.js
Normal file
87
devtools/client/storage/test/browser_storage_search.js
Normal file
@ -0,0 +1,87 @@
|
||||
// Tests the filter search box in the storage inspector
|
||||
"use strict";
|
||||
|
||||
add_task(function*() {
|
||||
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-search.html");
|
||||
|
||||
let $$ = sel => gPanelWindow.document.querySelectorAll(sel);
|
||||
gUI.tree.expandAll();
|
||||
yield selectTreeItem(["localStorage", "http://test1.example.org"]);
|
||||
|
||||
// Results: 0=hidden, 1=visible
|
||||
let testcases = [
|
||||
// Test that search isn't case-sensitive
|
||||
{
|
||||
value: "FoO",
|
||||
results: [0, 0, 1, 1, 0, 1, 0]
|
||||
},
|
||||
{
|
||||
value: "OR",
|
||||
results: [0, 1, 0, 0, 0, 1, 0]
|
||||
},
|
||||
{
|
||||
value: "aNImAl",
|
||||
results: [0, 1, 0, 0, 0, 0, 0]
|
||||
},
|
||||
// Test numbers
|
||||
{
|
||||
value: "01",
|
||||
results: [1, 0, 0, 0, 0, 0, 1]
|
||||
},
|
||||
{
|
||||
value: "2016",
|
||||
results: [0, 0, 0, 0, 0, 0, 1]
|
||||
},
|
||||
{
|
||||
value: "56789",
|
||||
results: [1, 0, 0, 0, 0, 0, 0]
|
||||
},
|
||||
// Test filtering by value
|
||||
{
|
||||
value: "horse",
|
||||
results: [0, 1, 0, 0, 0, 0, 0]
|
||||
},
|
||||
{
|
||||
value: "$$$",
|
||||
results: [0, 0, 0, 0, 1, 0, 0]
|
||||
},
|
||||
{
|
||||
value: "bar",
|
||||
results: [0, 0, 1, 1, 0, 0, 0]
|
||||
},
|
||||
// Test input with whitespace
|
||||
{
|
||||
value: "energy b",
|
||||
results: [0, 0, 0, 1, 0, 0, 0]
|
||||
},
|
||||
// Test no input at all
|
||||
{
|
||||
value: "",
|
||||
results: [1, 1, 1, 1, 1, 1, 1]
|
||||
},
|
||||
// Test input that matches nothing
|
||||
{
|
||||
value: "input that matches nothing",
|
||||
results: [0, 0, 0, 0, 0, 0, 0]
|
||||
}
|
||||
];
|
||||
|
||||
let names = $$("#name .table-widget-cell");
|
||||
let rows = $$("#value .table-widget-cell");
|
||||
for (let testcase of testcases) {
|
||||
info(`Testing input: ${testcase.value}`);
|
||||
|
||||
gUI.searchBox.value = testcase.value;
|
||||
gUI.filterItems();
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
info(`Testing row ${i}`);
|
||||
info(`key: ${names[i].value}, value: ${rows[i].value}`);
|
||||
let state = testcase.results[i] ? "visible" : "hidden";
|
||||
is(rows[i].hasAttribute("hidden"), !testcase.results[i],
|
||||
`Row ${i} should be ${state}`);
|
||||
}
|
||||
}
|
||||
|
||||
yield finishTests();
|
||||
});
|
26
devtools/client/storage/test/storage-search.html
Normal file
26
devtools/client/storage/test/storage-search.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1224115 - Storage Inspector table filtering
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Storage inspector table filtering test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript;version=1.8">
|
||||
"use strict";
|
||||
window.clear = () => {
|
||||
localStorage.clear();
|
||||
};
|
||||
|
||||
localStorage.setItem("01234", "56789");
|
||||
localStorage.setItem("ANIMAL", "hOrSe");
|
||||
localStorage.setItem("FOO", "bArBaz");
|
||||
localStorage.setItem("food", "energy bar");
|
||||
localStorage.setItem("money", "##$$$**");
|
||||
localStorage.setItem("sport", "football");
|
||||
localStorage.setItem("year", "2016");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -81,6 +81,10 @@ var StorageUI = this.StorageUI = function StorageUI(front, target, panelWin) {
|
||||
this.view = new VariablesView(this.sidebar.firstChild,
|
||||
GENERIC_VARIABLES_VIEW_SETTINGS);
|
||||
|
||||
this.searchBox = this._panelDoc.getElementById("storage-searchbox");
|
||||
this.filterItems = this.filterItems.bind(this);
|
||||
this.searchBox.addEventListener("input", this.filterItems);
|
||||
|
||||
this.front.listStores().then(storageTypes => {
|
||||
this.populateStorageTree(storageTypes);
|
||||
}).then(null, console.error);
|
||||
@ -113,6 +117,8 @@ StorageUI.prototype = {
|
||||
this.front.off("stores-update", this.onUpdate);
|
||||
this.front.off("stores-cleared", this.onCleared);
|
||||
this._panelDoc.removeEventListener("keypress", this.handleKeypress);
|
||||
this.searchBox.removeEventListener("input", this.filterItems);
|
||||
this.searchBox = null;
|
||||
this._telemetry.toolClosed("storage");
|
||||
},
|
||||
|
||||
@ -546,6 +552,7 @@ StorageUI.prototype = {
|
||||
onHostSelect: function(event, item) {
|
||||
this.table.clear();
|
||||
this.hideSidebar();
|
||||
this.searchBox.value = "";
|
||||
|
||||
let [type, host] = item;
|
||||
let names = null;
|
||||
@ -644,6 +651,15 @@ StorageUI.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles filtering the table
|
||||
*/
|
||||
filterItems() {
|
||||
let value = this.searchBox.value;
|
||||
this.table.filterItems(value, ["valueActor"]);
|
||||
this._panelDoc.documentElement.classList.toggle("filtering", !!value);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles endless scrolling for the table
|
||||
*/
|
||||
|
@ -49,8 +49,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
#inspector-pane-toggle,
|
||||
#inspector-pane-toggle[pane-collapsed] {
|
||||
#inspector-pane-toggle > .toolbarbutton-icon {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
@ -1146,8 +1146,12 @@
|
||||
color: inherit;
|
||||
text-align: center;
|
||||
font-weight: inherit !important;
|
||||
border-bottom-width: 0 !important;
|
||||
border-image: linear-gradient(transparent 15%, var(--theme-splitter-color) 15%, var(--theme-splitter-color) 85%, transparent 85%) 1 1;
|
||||
border-image: linear-gradient(transparent 15%,
|
||||
var(--theme-splitter-color) 15%,
|
||||
var(--theme-splitter-color) 85%,
|
||||
transparent 85%,
|
||||
transparent calc(100% - 1px),
|
||||
var(--theme-splitter-color) calc(100% - 1px)) 1 1;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
@ -1159,7 +1163,7 @@
|
||||
background-color: var(--theme-selection-background);
|
||||
color: var(--theme-selection-color);
|
||||
border-image: linear-gradient(var(--theme-splitter-color), var(--theme-splitter-color)) 1 1;
|
||||
box-shadow: -0.5px 0 0 0.5px var(--theme-splitter-color);
|
||||
box-shadow: -0.5px -0.5px 0 0.5px var(--theme-splitter-color);
|
||||
background-position: right 6px center;
|
||||
}
|
||||
|
||||
@ -1185,17 +1189,12 @@
|
||||
color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
.table-widget-column-header + .table-widget-cell {
|
||||
border-top: 1px solid var(--theme-splitter-color);
|
||||
.table-widget-cell[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.table-widget-cell:last-child {
|
||||
border-bottom: 1px solid var(--table-splitter-color);
|
||||
}
|
||||
|
||||
:root:not(.filtering) .table-widget-cell:nth-child(odd):not(.theme-selected),
|
||||
.table-widget-cell:not(.theme-selected)[odd] {
|
||||
background: var(--table-zebra-background);
|
||||
.table-widget-cell.even:not(.theme-selected) {
|
||||
background-color: var(--table-zebra-background);
|
||||
}
|
||||
|
||||
:root:not(.no-animate) .table-widget-cell.flash-out {
|
||||
|
@ -5,6 +5,8 @@ var { DebuggerServer } = require("devtools/server/main");
|
||||
const protocol = require("devtools/server/protocol");
|
||||
const { Arg, method, RetVal } = protocol;
|
||||
|
||||
loader.lazyRequireGetter(this, "ChromeUtils");
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
@ -140,6 +142,20 @@ let WorkerActor = protocol.ActorClass({
|
||||
response: RetVal("json")
|
||||
}),
|
||||
|
||||
push: method(function () {
|
||||
if (this._dbg.type !== Ci.nsIWorkerDebugger.TYPE_SERVICE) {
|
||||
return { error: "wrongType" };
|
||||
}
|
||||
let registration = this._getServiceWorkerRegistrationInfo();
|
||||
let originAttributes = ChromeUtils.originAttributesToSuffix(
|
||||
this._dbg.principal.originAttributes);
|
||||
swm.sendPushEvent(originAttributes, registration.scope);
|
||||
return { type: "pushed" };
|
||||
}, {
|
||||
request: {},
|
||||
response: RetVal("json")
|
||||
}),
|
||||
|
||||
onClose: function () {
|
||||
if (this._attached) {
|
||||
this._detach();
|
||||
|
@ -32,6 +32,7 @@ var loaderModules = {
|
||||
"Services": Object.create(Services),
|
||||
"toolkit/loader": Loader,
|
||||
PromiseDebugging,
|
||||
ChromeUtils,
|
||||
ThreadSafeChromeUtils,
|
||||
HeapSnapshot,
|
||||
};
|
||||
|
@ -1450,7 +1450,8 @@ WorkerClient.prototype = {
|
||||
|
||||
return this.request({
|
||||
to: connectReponse.threadActor,
|
||||
type: "attach"
|
||||
type: "attach",
|
||||
options: aOptions
|
||||
}).then(attachResponse => {
|
||||
if (attachResponse.error) {
|
||||
aOnResponse(attachResponse, null);
|
||||
|
@ -366,6 +366,7 @@ var loader = {
|
||||
|
||||
var {
|
||||
Debugger,
|
||||
URL,
|
||||
createSandbox,
|
||||
dump,
|
||||
rpc,
|
||||
@ -428,6 +429,7 @@ var {
|
||||
|
||||
return {
|
||||
Debugger,
|
||||
URL: this.URL,
|
||||
createSandbox,
|
||||
dump: this.dump,
|
||||
rpc,
|
||||
@ -465,6 +467,7 @@ var {
|
||||
|
||||
return {
|
||||
Debugger: this.Debugger,
|
||||
URL: this.URL,
|
||||
createSandbox: this.createSandbox,
|
||||
dump: this.dump,
|
||||
rpc: this.rpc,
|
||||
@ -494,7 +497,7 @@ this.worker = new WorkerDebuggerLoader({
|
||||
"Debugger": Debugger,
|
||||
"PromiseDebugging": PromiseDebugging,
|
||||
"Services": Object.create(null),
|
||||
"URL": null,
|
||||
"URL": URL,
|
||||
"chrome": chrome,
|
||||
"xpcInspector": xpcInspector
|
||||
},
|
||||
|
@ -69,10 +69,6 @@ extern const wchar_t* kFlashFullscreenClass;
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif // defined(XP_MACOSX)
|
||||
|
||||
// This is the pref used to determine whether to use Shumway on a Flash object
|
||||
// (when Shumway is enabled).
|
||||
static const char kShumwayWhitelistPref[] = "shumway.swf.whitelist";
|
||||
|
||||
using namespace mozilla::plugins;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::gl;
|
||||
@ -137,7 +133,6 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
||||
, mUseSurrogate(true)
|
||||
, mNPP(npp)
|
||||
, mNPNIface(npniface)
|
||||
, mIsWhitelistedForShumway(false)
|
||||
, mWindowType(NPWindowTypeWindow)
|
||||
, mDrawingModel(kDefaultDrawingModel)
|
||||
, mLastRecordedDrawingModel(-1)
|
||||
|
@ -316,18 +316,6 @@ public:
|
||||
aOutput = mSrcAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function tells us whether this plugin instance would have been
|
||||
* whitelisted for Shumway if Shumway had been enabled. This is being used
|
||||
* for the purpose of gathering telemetry on Flash hangs that could
|
||||
* potentially be avoided by using Shumway instead.
|
||||
*/
|
||||
bool
|
||||
IsWhitelistedForShumway() const
|
||||
{
|
||||
return mIsWhitelistedForShumway;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
AnswerPluginFocusChange(const bool& gotFocus) override;
|
||||
|
||||
@ -402,7 +390,6 @@ private:
|
||||
NPP mNPP;
|
||||
const NPNetscapeFuncs* mNPNIface;
|
||||
nsCString mSrcAttribute;
|
||||
bool mIsWhitelistedForShumway;
|
||||
NPWindowType mWindowType;
|
||||
int16_t mDrawingModel;
|
||||
IntSize mWindowSize;
|
||||
|
@ -1135,24 +1135,6 @@ PluginModuleChromeParent::AnnotateHang(mozilla::HangMonitor::HangAnnotations& aA
|
||||
aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginName"), mPluginName);
|
||||
aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginVersion"),
|
||||
mPluginVersion);
|
||||
if (mIsFlashPlugin) {
|
||||
bool isWhitelistedForShumway = false;
|
||||
{ // Scope for lock
|
||||
mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
|
||||
if (!mProtocolCallStack.IsEmpty()) {
|
||||
mozilla::ipc::IProtocol* topProtocol =
|
||||
mProtocolCallStack.LastElement();
|
||||
PluginInstanceParent* instance =
|
||||
GetManagingInstance(topProtocol);
|
||||
if (instance) {
|
||||
isWhitelistedForShumway =
|
||||
instance->IsWhitelistedForShumway();
|
||||
}
|
||||
}
|
||||
}
|
||||
aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginIsWhitelistedForShumway"),
|
||||
isWhitelistedForShumway);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,8 +142,8 @@ HTTP(..) == bug533251.html bug533251-ref.html
|
||||
HTTP(..) == font-familiy-whitespace-1.html font-familiy-whitespace-1-ref.html
|
||||
HTTP(..) != font-familiy-whitespace-1.html font-familiy-whitespace-1-notref.html
|
||||
|
||||
skip-if(B2G||Mulet) HTTP(..) == ivs-1.html ivs-1-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet) HTTP(..) == cjkcisvs-1.html cjkcisvs-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
skip-if(B2G||Mulet||Android) HTTP(..) == ivs-1.html ivs-1-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop # Android bug 1250229
|
||||
skip-if(B2G||Mulet||Android) HTTP(..) == cjkcisvs-1.html cjkcisvs-1-ref.html # Initial mulet triage: parity with B2G/B2G Desktop # Android bug 1250229
|
||||
|
||||
skip-if(B2G||Mulet) HTTP(..) == missing-names.html missing-names-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop
|
||||
|
||||
|
@ -169,7 +169,7 @@ fuzzy-if(gtkWidget||B2G,255,6) fuzzy-if(cocoaWidget,65,69) == 1193519-sideways-l
|
||||
|
||||
== 1243125-1-floats-overflowing.html 1243125-1-floats-overflowing-ref.html
|
||||
|
||||
HTTP(..) == 1248248-1-orientation-break-glyphrun.html 1248248-1-orientation-break-glyphrun-ref.html
|
||||
skip-if(Android) HTTP(..) == 1248248-1-orientation-break-glyphrun.html 1248248-1-orientation-break-glyphrun-ref.html # Android bug 1250229
|
||||
|
||||
# Suite of tests from Gérard Talbot in bug 1079151
|
||||
# Frequent Windows 7 load failed: timed out waiting for test to complete (waiting for onload scripts to complete), bug 1167155 and friends
|
||||
|
@ -27,7 +27,6 @@ globals:
|
||||
TelemetryStopwatch: false
|
||||
UITelemetry: false
|
||||
UserAgentOverrides: 0
|
||||
WebappManager: false
|
||||
XPCOMUtils: false
|
||||
ctypes: false
|
||||
dump: false
|
||||
|
@ -865,30 +865,6 @@ pref("browser.snippets.enabled", true);
|
||||
pref("browser.snippets.syncPromo.enabled", true);
|
||||
pref("browser.snippets.firstrunHomepage.enabled", true);
|
||||
|
||||
// The URL of the APK factory from which we obtain APKs for webapps.
|
||||
pref("browser.webapps.apkFactoryUrl", "https://controller.apk.firefox.com/application.apk");
|
||||
|
||||
// How frequently to check for webapp updates, in seconds (86400 is daily).
|
||||
pref("browser.webapps.updateInterval", 86400);
|
||||
|
||||
// Whether or not to check for updates. Enabled by default, but the runtime
|
||||
// disables it for webapp profiles on firstrun, so only the main Fennec process
|
||||
// checks for updates (to avoid duplicate update notifications).
|
||||
//
|
||||
// In the future, we might want to make each webapp process check for updates
|
||||
// for its own webapp, in which case we'll need to have a third state for this
|
||||
// preference. Thus it's an integer rather than a boolean.
|
||||
//
|
||||
// Possible values:
|
||||
// 0: don't check for updates
|
||||
// 1: do check for updates
|
||||
pref("browser.webapps.checkForUpdates", 1);
|
||||
|
||||
// The URL of the service that checks for updates.
|
||||
// To test updates, set this to http://apk-update-checker.paas.allizom.org,
|
||||
// which is a test server that always reports all apps as having updates.
|
||||
pref("browser.webapps.updateCheckUrl", "https://controller.apk.firefox.com/app_updates");
|
||||
|
||||
// The mode of home provider syncing.
|
||||
// 0: Sync always
|
||||
// 1: Sync only when on wifi
|
||||
|
@ -184,44 +184,12 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="org.mozilla.gecko.webapp.Dispatcher"
|
||||
android:noHistory="true" >
|
||||
<intent-filter>
|
||||
<!-- catch links from synthetic apks -->
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="application/webapp" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<receiver android:name="org.mozilla.gecko.webapp.UninstallListener" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_REMOVED" />
|
||||
<data android:scheme="package" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.mozilla.gecko.webapp.TaskKiller">
|
||||
<intent-filter>
|
||||
<action android:name="org.mozilla.webapp.TASK_REMOVED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.mozilla.gecko.restrictions.RestrictionProvider">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Declare a predefined number of Webapp<num> activities. These are
|
||||
used so that each web app can launch in its own process. Keep
|
||||
this number in sync with the total number of web apps handled in
|
||||
WebappAllocator. -->
|
||||
|
||||
#define FRAGMENT WebappManifestFragment.xml.frag.in
|
||||
#include WebappFragmentRepeater.inc
|
||||
|
||||
<!-- Masquerade as the Resolver so that we can be opened from the Marketplace. -->
|
||||
<activity-alias
|
||||
android:name="com.android.internal.app.ResolverActivity"
|
||||
@ -254,6 +222,15 @@
|
||||
<receiver android:name="org.mozilla.gecko.AlarmReceiver" >
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="org.mozilla.gecko.notifications.WhatsNewReceiver"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_REPLACED" />
|
||||
<data android:scheme="package" android:path="org.mozilla.gecko" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
#include ../services/manifests/FxAccountAndroidManifest_activities.xml.in
|
||||
#ifdef MOZ_ANDROID_SEARCH_ACTIVITY
|
||||
#include ../search/manifests/SearchAndroidManifest_activities.xml.in
|
||||
|
@ -1,301 +0,0 @@
|
||||
#define APPNUM 0
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 1
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 2
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 3
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 4
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 5
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 6
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 7
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 8
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 9
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 10
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 11
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 12
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 13
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 14
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 15
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 16
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 17
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 18
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 19
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 20
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 21
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 22
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 23
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 24
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 25
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 26
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 27
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 28
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 29
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 30
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 31
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 32
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 33
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 34
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 35
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 36
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 37
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 38
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 39
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 40
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 41
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 42
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 43
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 44
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 45
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 46
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 47
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 48
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 49
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 50
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 51
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 52
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 53
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 54
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 55
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 56
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 57
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 58
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 59
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 60
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 61
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 62
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 63
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 64
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 65
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 66
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 67
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 68
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 69
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 70
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 71
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 72
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 73
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 74
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 75
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 76
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 77
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 78
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 79
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 80
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 81
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 82
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 83
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 84
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 85
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 86
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 87
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 88
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 89
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 90
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 91
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 92
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 93
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 94
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 95
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 96
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 97
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 98
|
||||
#include @FRAGMENT@
|
||||
|
||||
#define APPNUM 99
|
||||
#include @FRAGMENT@
|
||||
#undef APPNUM
|
||||
#undef FRAGMENT
|
@ -1,9 +0,0 @@
|
||||
<activity android:name="org.mozilla.gecko.webapp.Webapps$Webapp@APPNUM@"
|
||||
android:label="@string/webapp_generic_name"
|
||||
android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize"
|
||||
android:windowSoftInputMode="stateUnspecified|adjustResize"
|
||||
android:process=":@ANDROID_PACKAGE_NAME@.Webapp@APPNUM@"
|
||||
android:theme="@style/Gecko.App"
|
||||
android:launchMode="singleTop"
|
||||
android:exported="true"
|
||||
/>
|
@ -679,6 +679,7 @@ public class BrowserApp extends GeckoApp
|
||||
mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting);
|
||||
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this,
|
||||
"Gecko:DelayedStartup",
|
||||
"Menu:Open",
|
||||
"Menu:Update",
|
||||
"LightweightTheme:Update",
|
||||
@ -1390,6 +1391,7 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener) this,
|
||||
"Gecko:DelayedStartup",
|
||||
"Menu:Open",
|
||||
"Menu:Update",
|
||||
"LightweightTheme:Update",
|
||||
|
@ -43,8 +43,6 @@ import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
import org.mozilla.gecko.util.PrefUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.webapp.EventListener;
|
||||
import org.mozilla.gecko.webapp.UninstallListener;
|
||||
import org.mozilla.gecko.widget.ButtonToast;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
@ -144,7 +142,6 @@ public abstract class GeckoApp
|
||||
NORMAL, /* normal application start */
|
||||
URL, /* launched with a passed URL */
|
||||
PREFETCH, /* launched with a passed URL that we prefetch */
|
||||
WEBAPP, /* launched as a webapp runtime */
|
||||
GUEST, /* launched in guest browsing */
|
||||
RESTRICTED, /* launched with restricted profile */
|
||||
SHORTCUT /* launched from a homescreen shortcut */
|
||||
@ -214,8 +211,6 @@ public abstract class GeckoApp
|
||||
private volatile HealthRecorder mHealthRecorder;
|
||||
private volatile Locale mLastLocale;
|
||||
|
||||
private EventListener mWebappEventListener;
|
||||
|
||||
private Intent mRestartIntent;
|
||||
|
||||
abstract public int getLayout();
|
||||
@ -691,9 +686,7 @@ public abstract class GeckoApp
|
||||
@Override
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
try {
|
||||
if (event.equals("Gecko:DelayedStartup")) {
|
||||
ThreadUtils.postToBackgroundThread(new UninstallListener.DelayedStartupTask(this));
|
||||
} else if (event.equals("Gecko:Ready")) {
|
||||
if (event.equals("Gecko:Ready")) {
|
||||
mGeckoReadyStartupTimer.stop();
|
||||
geckoConnected();
|
||||
|
||||
@ -711,10 +704,6 @@ public abstract class GeckoApp
|
||||
doShutdown();
|
||||
return;
|
||||
|
||||
} else if ("NativeApp:IsDebuggable".equals(event)) {
|
||||
JSONObject ret = new JSONObject();
|
||||
ret.put("isDebuggable", getIsDebuggable());
|
||||
EventDispatcher.sendResponse(message, ret);
|
||||
} else if (event.equals("Accessibility:Event")) {
|
||||
GeckoAccessibility.sendAccessibilityEvent(message);
|
||||
}
|
||||
@ -1268,10 +1257,8 @@ public abstract class GeckoApp
|
||||
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this,
|
||||
"Gecko:Ready",
|
||||
"Gecko:DelayedStartup",
|
||||
"Gecko:Exited",
|
||||
"Accessibility:Event",
|
||||
"NativeApp:IsDebuggable");
|
||||
"Accessibility:Event");
|
||||
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener)this,
|
||||
"Accessibility:Ready",
|
||||
@ -1299,11 +1286,6 @@ public abstract class GeckoApp
|
||||
EventDispatcher.getInstance().registerBackgroundThreadListener((BundleEventListener) this,
|
||||
"History:GetPrePathLastVisitedTimeMilliseconds");
|
||||
|
||||
if (mWebappEventListener == null) {
|
||||
mWebappEventListener = new EventListener();
|
||||
mWebappEventListener.registerEvents();
|
||||
}
|
||||
|
||||
GeckoThread.launch();
|
||||
|
||||
Bundle stateBundle = ContextUtils.getBundleExtra(getIntent(), EXTRA_STATE_BUNDLE);
|
||||
@ -2103,10 +2085,8 @@ public abstract class GeckoApp
|
||||
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this,
|
||||
"Gecko:Ready",
|
||||
"Gecko:DelayedStartup",
|
||||
"Gecko:Exited",
|
||||
"Accessibility:Event",
|
||||
"NativeApp:IsDebuggable");
|
||||
"Accessibility:Event");
|
||||
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((NativeEventListener)this,
|
||||
"Accessibility:Ready",
|
||||
@ -2133,11 +2113,6 @@ public abstract class GeckoApp
|
||||
EventDispatcher.getInstance().unregisterBackgroundThreadListener((BundleEventListener) this,
|
||||
"History:GetPrePathLastVisitedTimeMilliseconds");
|
||||
|
||||
if (mWebappEventListener != null) {
|
||||
mWebappEventListener.unregisterEvents();
|
||||
mWebappEventListener = null;
|
||||
}
|
||||
|
||||
deleteTempFiles();
|
||||
|
||||
if (mDoorHangerPopup != null)
|
||||
@ -2673,23 +2648,6 @@ public abstract class GeckoApp
|
||||
return versionCode;
|
||||
}
|
||||
|
||||
protected boolean getIsDebuggable() {
|
||||
// Return false so Fennec doesn't appear to be debuggable. WebappImpl
|
||||
// then overrides this and returns the value of android:debuggable for
|
||||
// the webapp APK, so webapps get the behavior supported by this method
|
||||
// (i.e. automatic configuration and enabling of the remote debugger).
|
||||
return false;
|
||||
|
||||
// If we ever want to expose this for Fennec, here's how we would do it:
|
||||
// int flags = 0;
|
||||
// try {
|
||||
// flags = getPackageManager().getPackageInfo(getPackageName(), 0).applicationInfo.flags;
|
||||
// } catch (NameNotFoundException e) {
|
||||
// Log.wtf(LOGTAG, getPackageName() + " not found", e);
|
||||
// }
|
||||
// return (flags & android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
}
|
||||
|
||||
// FHR reason code for a session end prior to a restart for a
|
||||
// locale change.
|
||||
private static final String SESSION_END_LOCALE_CHANGED = "L";
|
||||
|
@ -2835,9 +2835,4 @@ public class GeckoAppShell
|
||||
final Display disp = wm.getDefaultDisplay();
|
||||
return new Rect(0, 0, disp.getWidth(), disp.getHeight());
|
||||
}
|
||||
|
||||
@JNITarget
|
||||
static boolean isWebAppProcess() {
|
||||
return GeckoProfile.get(getApplicationContext()).isWebAppProfile();
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +145,6 @@ public class GeckoApplication extends Application
|
||||
|
||||
// Make sure that all browser-ish applications default to the real LocalBrowserDB.
|
||||
// GeckoView consumers use their own Application class, so this doesn't affect them.
|
||||
// WebappImpl overrides this on creation.
|
||||
//
|
||||
// We need to do this before any access to the profile; it controls
|
||||
// which database class is used.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user