зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to b2g-inbound
This commit is contained in:
Коммит
7e5877b7aa
|
@ -163,26 +163,26 @@ public:
|
|||
const int32_t& aY) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvReplaceText(const uint64_t& aID,
|
||||
const nsString& aText);
|
||||
const nsString& aText) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvInsertText(const uint64_t& aID,
|
||||
const nsString& aText,
|
||||
const int32_t& aPosition);
|
||||
const int32_t& aPosition) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvCopyText(const uint64_t& aID,
|
||||
const int32_t& aStartPos,
|
||||
const int32_t& aEndPos);
|
||||
const int32_t& aEndPos) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvCutText(const uint64_t& aID,
|
||||
const int32_t& aStartPos,
|
||||
const int32_t& aEndPos);
|
||||
const int32_t& aEndPos) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvDeleteText(const uint64_t& aID,
|
||||
const int32_t& aStartPos,
|
||||
const int32_t& aEndPos);
|
||||
const int32_t& aEndPos) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvPasteText(const uint64_t& aID,
|
||||
const int32_t& aPosition);
|
||||
const int32_t& aPosition) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
bool PersistentPropertiesToArray(nsIPersistentProperties* aProps,
|
||||
|
|
|
@ -18,7 +18,7 @@ sinclude $(topsrcdir)/config/rules.mk
|
|||
|
||||
# This can switch to just zipping the files when native jetpacks land
|
||||
$(TESTADDONS)/%.xpi: FORCE $(call mkdir_deps,$(CURDIR)/$(TESTADDONS)) $(ADDONSRC)/%
|
||||
$(PYTHON) $(srcdir)/source/bin/cfx xpi --pkgdir=$(lastword $^) --output-file=$@
|
||||
$(PYTHON) $(srcdir)/source/bin/cfx xpi --no-strip-xpi --pkgdir=$(lastword $^) --output-file=$@
|
||||
|
||||
#libs:: $(ADDONS)
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=0
|
||||
. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=0
|
||||
. $topsrcdir/build/macosx/mozconfig.common
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
|
|
@ -2,6 +2,8 @@ MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
|||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_INSTALLER=0
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=0
|
||||
. "$topsrcdir/browser/config/mozconfigs/win32/nightly"
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
|
|
@ -1461,6 +1461,8 @@ pref("devtools.profiler.ui.show-platform-data", false);
|
|||
pref("devtools.profiler.ui.show-idle-blocks", true);
|
||||
|
||||
// The default Performance UI settings
|
||||
pref("devtools.performance.memory.sample-probability", "0.05");
|
||||
pref("devtools.performance.memory.max-log-length", 2147483647); // Math.pow(2,31) - 1
|
||||
pref("devtools.performance.timeline.hidden-markers", "[]");
|
||||
pref("devtools.performance.ui.invert-call-tree", true);
|
||||
pref("devtools.performance.ui.invert-flame-graph", false);
|
||||
|
|
|
@ -30,7 +30,7 @@ function createScheduler(options) {
|
|||
// avoid typos in the test and other footguns in the options.
|
||||
let allowedOptions = ["expectedDelay", "expectNewTimer", "syncFunction"];
|
||||
for (let key of Object.keys(options)) {
|
||||
if (!allowedOptions.includes(key)) {
|
||||
if (allowedOptions.indexOf(key) == -1) {
|
||||
throw new Error("Invalid option " + key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,7 +329,7 @@ PerformanceFront.prototype = {
|
|||
return 0;
|
||||
}
|
||||
yield this._request("memory", "attach");
|
||||
let memoryStartTime = yield this._request("memory", "startRecordingAllocations");
|
||||
let memoryStartTime = yield this._request("memory", "startRecordingAllocations", options);
|
||||
yield this._pullAllocationSites();
|
||||
return memoryStartTime;
|
||||
}),
|
||||
|
|
|
@ -182,7 +182,9 @@ let PerformanceController = {
|
|||
// ToolbarView, so that they may be accessible via the "gear" menu.
|
||||
// Every other pref should be registered here.
|
||||
this._nonBooleanPrefs = new ViewHelpers.Prefs("devtools.performance", {
|
||||
"hidden-markers": ["Json", "timeline.hidden-markers"]
|
||||
"hidden-markers": ["Json", "timeline.hidden-markers"],
|
||||
"memory-sample-probability": ["Float", "memory.sample-probability"],
|
||||
"memory-max-log-length": ["Int", "memory.max-log-length"]
|
||||
});
|
||||
|
||||
this._nonBooleanPrefs.registerObserver();
|
||||
|
@ -262,11 +264,13 @@ let PerformanceController = {
|
|||
let withMemory = this.getOption("enable-memory");
|
||||
let withTicks = this.getOption("enable-framerate");
|
||||
let withAllocations = this.getOption("enable-memory");
|
||||
let probability = this.getPref("memory-sample-probability");
|
||||
let maxLogLength = this.getPref("memory-max-log-length");
|
||||
|
||||
let recording = this._createRecording({ withMemory, withTicks, withAllocations });
|
||||
let recording = this._createRecording({ withMemory, withTicks, withAllocations, probability, maxLogLength });
|
||||
|
||||
this.emit(EVENTS.RECORDING_WILL_START, recording);
|
||||
yield recording.startRecording({ withTicks, withMemory, withAllocations });
|
||||
yield recording.startRecording({ withMemory, withTicks, withAllocations, probability, maxLogLength });
|
||||
this.emit(EVENTS.RECORDING_STARTED, recording);
|
||||
|
||||
this.setCurrentRecording(recording);
|
||||
|
|
|
@ -54,6 +54,7 @@ support-files =
|
|||
[browser_perf-options-enable-memory-01.js]
|
||||
[browser_perf-options-enable-memory-02.js]
|
||||
[browser_perf-options-enable-framerate.js]
|
||||
[browser_perf-options-allocations.js]
|
||||
[browser_perf-overview-render-01.js]
|
||||
[browser_perf-overview-render-02.js]
|
||||
[browser_perf-overview-render-03.js]
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
/**
|
||||
* Tests that setting the `devtools.performance.memory.` prefs propagate to the memory actor.
|
||||
*/
|
||||
function spawnTest () {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, PerformanceController, $, gFront } = panel.panelWin;
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||
|
||||
let originalProbability = Services.prefs.getCharPref("devtools.performance.memory.sample-probability");
|
||||
let originalLogLength = Services.prefs.getIntPref("devtools.performance.memory.max-log-length");
|
||||
|
||||
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", "0.213");
|
||||
Services.prefs.setIntPref("devtools.performance.memory.max-log-length", 777777);
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
let { probability, maxLogLength } = yield gFront._request("memory", "getAllocationsSettings");
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
is(probability, 0.213, "allocations probability option is set on memory actor");
|
||||
is(maxLogLength, 777777, "allocations max log length option is set on memory actor");
|
||||
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
||||
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", originalProbability);
|
||||
Services.prefs.setIntPref("devtools.performance.memory.max-log-length", originalLogLength);
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
|
@ -58,7 +58,8 @@ skip-if = e10s # Layouthelpers test should not run in a content page.
|
|||
[browser_options-view-01.js]
|
||||
[browser_outputparser.js]
|
||||
skip-if = e10s # Test intermittently fails with e10s. Bug 1124162.
|
||||
[browser_prefs.js]
|
||||
[browser_prefs-01.js]
|
||||
[browser_prefs-02.js]
|
||||
[browser_require_basic.js]
|
||||
[browser_spectrum.js]
|
||||
[browser_theme.js]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests that ViewHelpers.Prefs work properly with custom types of Float and Json.
|
||||
|
||||
let {ViewHelpers} = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
|
||||
|
||||
function test() {
|
||||
let originalJson = Services.prefs.getCharPref("devtools.performance.timeline.hidden-markers");
|
||||
let originalFloat = Services.prefs.getCharPref("devtools.performance.memory.sample-probability");
|
||||
|
||||
let Prefs = new ViewHelpers.Prefs("devtools.performance", {
|
||||
"float": ["Float", "memory.sample-probability"],
|
||||
"json": ["Json", "timeline.hidden-markers"]
|
||||
});
|
||||
|
||||
Prefs.registerObserver();
|
||||
|
||||
// Float
|
||||
Services.prefs.setCharPref("devtools.performance.timeline.hidden-markers", "{\"a\":1}");
|
||||
is(Prefs.json.a, 1, "The JSON pref value is correctly casted on get.");
|
||||
|
||||
Prefs.json = { b: 2 };
|
||||
is(Prefs.json.a, undefined, "The JSON pref value is correctly casted on set (1).");
|
||||
is(Prefs.json.b, 2, "The JSON pref value is correctly casted on set (2).");
|
||||
|
||||
// Float
|
||||
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", "3.14");
|
||||
is(Prefs.float, 3.14, "The float pref value is correctly casted on get.");
|
||||
|
||||
Prefs.float = 6.28;
|
||||
is(Prefs.float, 6.28, "The float pref value is correctly casted on set.");
|
||||
|
||||
Prefs.unregisterObserver();
|
||||
|
||||
Services.prefs.setCharPref("devtools.performance.timeline.hidden-markers", originalJson);
|
||||
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", originalFloat);
|
||||
finish();
|
||||
}
|
|
@ -187,6 +187,7 @@ MarkerDetails.prototype = {
|
|||
|
||||
if (displayName) {
|
||||
let functionLabel = this._document.createElement("label");
|
||||
functionLabel.className = "devtools-monospace";
|
||||
functionLabel.setAttribute("value", displayName);
|
||||
hbox.appendChild(functionLabel);
|
||||
}
|
||||
|
|
|
@ -390,7 +390,8 @@ ViewHelpers.L10N.prototype = {
|
|||
* let prefs = new ViewHelpers.Prefs("root.path.to.branch", {
|
||||
* myIntPref: ["Int", "leaf.path.to.my-int-pref"],
|
||||
* myCharPref: ["Char", "leaf.path.to.my-char-pref"],
|
||||
* myJsonPref: ["Json", "leaf.path.to.my-json-pref"]
|
||||
* myJsonPref: ["Json", "leaf.path.to.my-json-pref"],
|
||||
* myFloatPref: ["Float", "leaf.path.to.my-float-pref"]
|
||||
* ...
|
||||
* });
|
||||
*
|
||||
|
@ -477,8 +478,8 @@ ViewHelpers.Prefs.prototype = {
|
|||
|
||||
/**
|
||||
* Maps a property name to a pref, defining lazy getters and setters.
|
||||
* Supported types are "Bool", "Char", "Int" and "Json" (which is basically
|
||||
* just sugar for "Char" using the standard JSON serializer).
|
||||
* Supported types are "Bool", "Char", "Int", "Float" (sugar around "Char" type and casting),
|
||||
* and "Json" (which is basically just sugar for "Char" using the standard JSON serializer).
|
||||
*
|
||||
* @param string aAccessorName
|
||||
* @param string aType
|
||||
|
@ -494,6 +495,10 @@ ViewHelpers.Prefs.prototype = {
|
|||
this._map(aAccessorName, "Char", aPrefsRoot, aPrefName, { in: JSON.parse, out: JSON.stringify });
|
||||
return;
|
||||
}
|
||||
if (aType == "Float") {
|
||||
this._map(aAccessorName, "Char", aPrefsRoot, aPrefName, { in: Number.parseFloat, out: (n) => n + ""});
|
||||
return;
|
||||
}
|
||||
|
||||
Object.defineProperty(this, aAccessorName, {
|
||||
get: () => aSerializer.in(this._get(aType, aPrefsRoot, aPrefName)),
|
||||
|
|
|
@ -28,3 +28,6 @@ webide.jar:
|
|||
content/wifi-auth.xhtml (wifi-auth.xhtml)
|
||||
content/logs.xhtml (logs.xhtml)
|
||||
content/logs.js (logs.js)
|
||||
content/project-listing.xhtml (project-listing.xhtml)
|
||||
content/project-listing.js (project-listing.js)
|
||||
content/project-panel.js (project-panel.js)
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* 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/. */
|
||||
|
||||
const Cu = Components.utils;
|
||||
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
||||
const {AppManager} = require("devtools/webide/app-manager");
|
||||
const ProjectList = require("devtools/webide/project-list");
|
||||
|
||||
let projectList = new ProjectList(window, window.parent);
|
||||
|
||||
window.addEventListener("load", function onLoad() {
|
||||
window.removeEventListener("load", onLoad);
|
||||
AppManager.on("app-manager-update", onAppManagerUpdate);
|
||||
document.getElementById("new-app").onclick = CreateNewApp;
|
||||
document.getElementById("hosted-app").onclick = ImportHostedApp;
|
||||
document.getElementById("packaged-app").onclick = ImportPackagedApp;
|
||||
projectList.update();
|
||||
}, true);
|
||||
|
||||
window.addEventListener("unload", function onUnload() {
|
||||
window.removeEventListener("unload", onUnload);
|
||||
projectList = null;
|
||||
AppManager.off("app-manager-update", onAppManagerUpdate);
|
||||
});
|
||||
|
||||
function onAppManagerUpdate(event, what) {
|
||||
switch (what) {
|
||||
case "list-tabs-response":
|
||||
case "runtime-apps-found":
|
||||
case "project-validated":
|
||||
case "project-removed":
|
||||
case "project":
|
||||
projectList.update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function CreateNewApp() {
|
||||
projectList.newApp();
|
||||
}
|
||||
|
||||
function ImportHostedApp() {
|
||||
projectList.importHostedApp();
|
||||
}
|
||||
|
||||
function ImportPackagedApp() {
|
||||
projectList.importPackagedApp();
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-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/. -->
|
||||
|
||||
<!DOCTYPE html [
|
||||
<!ENTITY % webideDTD SYSTEM "chrome://browser/locale/devtools/webide.dtd" >
|
||||
%webideDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf8"/>
|
||||
<link rel="stylesheet" href="chrome://webide/skin/project-listing.css" type="text/css"/>
|
||||
<script type="application/javascript;version=1.8" src="chrome://webide/content/project-listing.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="project-panel">
|
||||
<div id="project-panel-box">
|
||||
<button class="panel-item project-panel-item-newapp" id="new-app">&projectMenu_newApp_label;</button>
|
||||
<button class="panel-item project-panel-item-openpackaged" id="packaged-app">&projectMenu_importPackagedApp_label;</button>
|
||||
<button class="panel-item project-panel-item-openhosted" id="hosted-app">&projectMenu_importHostedApp_label;</button>
|
||||
<label class="panel-header">&projectPanel_myProjects;</label>
|
||||
<div id="project-panel-projects"></div>
|
||||
<label class="panel-header" id="panel-header-runtimeapps" hidden="true">&projectPanel_runtimeApps;</label>
|
||||
<div id="project-panel-runtimeapps"/>
|
||||
<label class="panel-header" id="panel-header-tabs" hidden="true">&projectPanel_tabs;</label>
|
||||
<div id="project-panel-tabs"/>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
/* 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/. */
|
||||
|
||||
let ProjectPanel = {
|
||||
// TODO: Expand function to save toggle state.
|
||||
toggle: function(sidebarsEnabled, triggerPopup) {
|
||||
let deferred = promise.defer();
|
||||
let doc = document;
|
||||
|
||||
if (sidebarsEnabled) {
|
||||
doc.querySelector("#project-listing-panel").setAttribute("sidebar-displayed", true);
|
||||
doc.querySelector("#project-listing-splitter").setAttribute("sidebar-displayed", true);
|
||||
deferred.resolve();
|
||||
} else if (triggerPopup) {
|
||||
let panelNode = doc.querySelector("#project-panel");
|
||||
let panelVboxNode = doc.querySelector("#project-panel > #project-panel-box");
|
||||
let anchorNode = doc.querySelector("#project-panel-button > .panel-button-anchor");
|
||||
|
||||
window.setTimeout(() => {
|
||||
// Open the popup only when the projects are added.
|
||||
// Not doing it in the next tick can cause mis-calculations
|
||||
// of the size of the panel.
|
||||
function onPopupShown() {
|
||||
panelNode.removeEventListener("popupshown", onPopupShown);
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
panelNode.addEventListener("popupshown", onPopupShown);
|
||||
panelNode.openPopup(anchorNode);
|
||||
panelVboxNode.scrollTop = 0;
|
||||
}, 0);
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
|
@ -24,6 +24,7 @@ const utils = require("devtools/webide/utils");
|
|||
const Telemetry = require("devtools/shared/telemetry");
|
||||
const {RuntimeScanners, WiFiScanner} = require("devtools/webide/runtimes");
|
||||
const {showDoorhanger} = require("devtools/shared/doorhanger");
|
||||
const ProjectList = require("devtools/webide/project-list");
|
||||
|
||||
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
|
||||
|
||||
|
@ -51,6 +52,8 @@ window.addEventListener("unload", function onUnload() {
|
|||
UI.uninit();
|
||||
});
|
||||
|
||||
let projectList;
|
||||
|
||||
let UI = {
|
||||
init: function() {
|
||||
this._telemetry = new Telemetry();
|
||||
|
@ -64,6 +67,9 @@ let UI = {
|
|||
this.appManagerUpdate = this.appManagerUpdate.bind(this);
|
||||
AppManager.on("app-manager-update", this.appManagerUpdate);
|
||||
|
||||
projectList = new ProjectList(window, window);
|
||||
ProjectPanel.toggle(projectList.sidebarsEnabled);
|
||||
|
||||
this.updateCommands();
|
||||
this.updateRuntimeList();
|
||||
|
||||
|
@ -72,6 +78,7 @@ let UI = {
|
|||
|
||||
AppProjects.load().then(() => {
|
||||
this.autoSelectProject();
|
||||
projectList.update();
|
||||
}, e => {
|
||||
console.error(e);
|
||||
this.reportError("error_appProjectsLoadFailed");
|
||||
|
@ -115,6 +122,7 @@ let UI = {
|
|||
window.removeEventListener("focus", this.onfocus, true);
|
||||
AppManager.off("app-manager-update", this.appManagerUpdate);
|
||||
AppManager.uninit();
|
||||
projectList = null;
|
||||
window.removeEventListener("message", this.onMessage);
|
||||
this.updateConnectionTelemetry();
|
||||
this._telemetry.toolClosed("webide");
|
||||
|
@ -171,6 +179,7 @@ let UI = {
|
|||
UI.openProject();
|
||||
UI.autoStartProject();
|
||||
UI.saveLastSelectedProject();
|
||||
projectList.update();
|
||||
});
|
||||
return;
|
||||
case "project-is-not-running":
|
||||
|
@ -190,12 +199,17 @@ let UI = {
|
|||
this.updateCommands();
|
||||
this.updateProjectButton();
|
||||
this.updateProjectEditorHeader();
|
||||
projectList.update();
|
||||
break;
|
||||
case "project-removed":
|
||||
projectList.update();
|
||||
break;
|
||||
case "install-progress":
|
||||
this.updateProgress(Math.round(100 * details.bytesSent / details.totalBytes));
|
||||
break;
|
||||
case "runtime-apps-found":
|
||||
this.autoSelectProject();
|
||||
projectList.update();
|
||||
break;
|
||||
case "pre-package":
|
||||
this.prePackageLog(details);
|
||||
|
@ -225,6 +239,7 @@ let UI = {
|
|||
}
|
||||
},
|
||||
|
||||
// TODO: remove hidePanel when project layout is complete - Bug 1079347
|
||||
hidePanels: function() {
|
||||
let panels = document.querySelectorAll("panel");
|
||||
for (let p of panels) {
|
||||
|
@ -527,14 +542,16 @@ let UI = {
|
|||
|
||||
let project = AppManager.selectedProject;
|
||||
|
||||
if (!project) {
|
||||
buttonNode.classList.add("no-project");
|
||||
labelNode.setAttribute("value", Strings.GetStringFromName("projectButton_label"));
|
||||
imageNode.removeAttribute("src");
|
||||
} else {
|
||||
buttonNode.classList.remove("no-project");
|
||||
labelNode.setAttribute("value", project.name);
|
||||
imageNode.setAttribute("src", project.icon);
|
||||
if (!projectList.sidebarsEnabled) {
|
||||
if (!project) {
|
||||
buttonNode.classList.add("no-project");
|
||||
labelNode.setAttribute("value", Strings.GetStringFromName("projectButton_label"));
|
||||
imageNode.removeAttribute("src");
|
||||
} else {
|
||||
buttonNode.classList.remove("no-project");
|
||||
labelNode.setAttribute("value", project.name);
|
||||
imageNode.setAttribute("src", project.icon);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1039,217 +1056,19 @@ let Cmds = {
|
|||
* }
|
||||
*/
|
||||
newApp: function(testOptions) {
|
||||
return UI.busyUntil(Task.spawn(function* () {
|
||||
|
||||
// Open newapp.xul, which will feed ret.location
|
||||
let ret = {location: null, testOptions: testOptions};
|
||||
window.openDialog("chrome://webide/content/newapp.xul", "newapp", "chrome,modal", ret);
|
||||
if (!ret.location)
|
||||
return;
|
||||
|
||||
// Retrieve added project
|
||||
let project = AppProjects.get(ret.location);
|
||||
|
||||
// Select project
|
||||
AppManager.selectedProject = project;
|
||||
|
||||
}), "creating new app");
|
||||
projectList.newApp(testOptions);
|
||||
},
|
||||
|
||||
importPackagedApp: function(location) {
|
||||
return UI.busyUntil(Task.spawn(function* () {
|
||||
|
||||
let directory = utils.getPackagedDirectory(window, location);
|
||||
|
||||
if (!directory) {
|
||||
// User cancelled directory selection
|
||||
return;
|
||||
}
|
||||
|
||||
yield UI.importAndSelectApp(directory);
|
||||
}), "importing packaged app");
|
||||
projectList.importPackagedApp(location);
|
||||
},
|
||||
|
||||
importHostedApp: function(location) {
|
||||
return UI.busyUntil(Task.spawn(function* () {
|
||||
|
||||
let url = utils.getHostedURL(window, location);
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield UI.importAndSelectApp(url);
|
||||
}), "importing hosted app");
|
||||
projectList.importHostedApp(location);
|
||||
},
|
||||
|
||||
showProjectPanel: function() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
let panelNode = document.querySelector("#project-panel");
|
||||
let panelVboxNode = document.querySelector("#project-panel > vbox");
|
||||
let anchorNode = document.querySelector("#project-panel-button > .panel-button-anchor");
|
||||
let projectsNode = document.querySelector("#project-panel-projects");
|
||||
|
||||
while (projectsNode.hasChildNodes()) {
|
||||
projectsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
AppProjects.load().then(() => {
|
||||
let projects = AppProjects.store.object.projects;
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i];
|
||||
let panelItemNode = document.createElement("toolbarbutton");
|
||||
panelItemNode.className = "panel-item";
|
||||
projectsNode.appendChild(panelItemNode);
|
||||
panelItemNode.setAttribute("label", project.name || AppManager.DEFAULT_PROJECT_NAME);
|
||||
panelItemNode.setAttribute("image", project.icon || AppManager.DEFAULT_PROJECT_ICON);
|
||||
if (!project.name || !project.icon) {
|
||||
// The result of the validation process (storing names, icons, …) is not stored in
|
||||
// the IndexedDB database when App Manager v1 is used.
|
||||
// We need to run the validation again and update the name and icon of the app.
|
||||
AppManager.validateAndUpdateProject(project).then(() => {
|
||||
panelItemNode.setAttribute("label", project.name);
|
||||
panelItemNode.setAttribute("image", project.icon);
|
||||
});
|
||||
}
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
UI.hidePanels();
|
||||
AppManager.selectedProject = project;
|
||||
}, true);
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
// Open the popup only when the projects are added.
|
||||
// Not doing it in the next tick can cause mis-calculations
|
||||
// of the size of the panel.
|
||||
function onPopupShown() {
|
||||
panelNode.removeEventListener("popupshown", onPopupShown);
|
||||
deferred.resolve();
|
||||
}
|
||||
panelNode.addEventListener("popupshown", onPopupShown);
|
||||
panelNode.openPopup(anchorNode);
|
||||
panelVboxNode.scrollTop = 0;
|
||||
}, 0);
|
||||
}, deferred.reject);
|
||||
|
||||
|
||||
let runtimeappsHeaderNode = document.querySelector("#panel-header-runtimeapps");
|
||||
let sortedApps = [];
|
||||
for (let [manifestURL, app] of AppManager.apps) {
|
||||
sortedApps.push(app);
|
||||
}
|
||||
sortedApps = sortedApps.sort((a, b) => {
|
||||
return a.manifest.name > b.manifest.name;
|
||||
});
|
||||
let mainProcess = AppManager.isMainProcessDebuggable();
|
||||
if (AppManager.connected && (sortedApps.length > 0 || mainProcess)) {
|
||||
runtimeappsHeaderNode.removeAttribute("hidden");
|
||||
} else {
|
||||
runtimeappsHeaderNode.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
let runtimeAppsNode = document.querySelector("#project-panel-runtimeapps");
|
||||
while (runtimeAppsNode.hasChildNodes()) {
|
||||
runtimeAppsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
if (mainProcess) {
|
||||
let panelItemNode = document.createElement("toolbarbutton");
|
||||
panelItemNode.className = "panel-item";
|
||||
panelItemNode.setAttribute("label", Strings.GetStringFromName("mainProcess_label"));
|
||||
panelItemNode.setAttribute("image", AppManager.DEFAULT_PROJECT_ICON);
|
||||
runtimeAppsNode.appendChild(panelItemNode);
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
UI.hidePanels();
|
||||
AppManager.selectedProject = {
|
||||
type: "mainProcess",
|
||||
name: Strings.GetStringFromName("mainProcess_label"),
|
||||
icon: AppManager.DEFAULT_PROJECT_ICON
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
|
||||
for (let i = 0; i < sortedApps.length; i++) {
|
||||
let app = sortedApps[i];
|
||||
let panelItemNode = document.createElement("toolbarbutton");
|
||||
panelItemNode.className = "panel-item";
|
||||
panelItemNode.setAttribute("label", app.manifest.name);
|
||||
panelItemNode.setAttribute("image", app.iconURL);
|
||||
runtimeAppsNode.appendChild(panelItemNode);
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
UI.hidePanels();
|
||||
AppManager.selectedProject = {
|
||||
type: "runtimeApp",
|
||||
app: app.manifest,
|
||||
icon: app.iconURL,
|
||||
name: app.manifest.name
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
|
||||
// Build the tab list right now, so it's fast...
|
||||
this._buildProjectPanelTabs();
|
||||
|
||||
// But re-list them and rebuild, in case any tabs navigated since the last
|
||||
// time they were listed.
|
||||
if (AppManager.connected) {
|
||||
AppManager.listTabs().then(() => {
|
||||
this._buildProjectPanelTabs();
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
_buildProjectPanelTabs: function() {
|
||||
let tabs = AppManager.tabStore.tabs;
|
||||
let tabsHeaderNode = document.querySelector("#panel-header-tabs");
|
||||
if (AppManager.connected && tabs.length > 0) {
|
||||
tabsHeaderNode.removeAttribute("hidden");
|
||||
} else {
|
||||
tabsHeaderNode.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
let tabsNode = document.querySelector("#project-panel-tabs");
|
||||
while (tabsNode.hasChildNodes()) {
|
||||
tabsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
let tab = tabs[i];
|
||||
let url;
|
||||
try {
|
||||
url = new URL(tab.url);
|
||||
} catch (e) {
|
||||
// Don't try to handle invalid URLs, especially from Valence.
|
||||
continue;
|
||||
}
|
||||
// Wanted to use nsIFaviconService here, but it only works for visited
|
||||
// tabs, so that's no help for any remote tabs. Maybe some favicon wizard
|
||||
// knows how to get high-res favicons easily, or we could offer actor
|
||||
// support for this (bug 1061654).
|
||||
tab.favicon = url.origin + "/favicon.ico";
|
||||
tab.name = tab.title || Strings.GetStringFromName("project_tab_loading");
|
||||
if (url.protocol.startsWith("http")) {
|
||||
tab.name = url.hostname + ": " + tab.name;
|
||||
}
|
||||
let panelItemNode = document.createElement("toolbarbutton");
|
||||
panelItemNode.className = "panel-item";
|
||||
panelItemNode.setAttribute("label", tab.name);
|
||||
panelItemNode.setAttribute("image", tab.favicon);
|
||||
tabsNode.appendChild(panelItemNode);
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
UI.hidePanels();
|
||||
AppManager.selectedProject = {
|
||||
type: "tab",
|
||||
app: tab,
|
||||
icon: tab.favicon,
|
||||
location: tab.url,
|
||||
name: tab.name
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
ProjectPanel.toggle(projectList.sidebarsEnabled, true);
|
||||
},
|
||||
|
||||
showRuntimePanel: function() {
|
||||
|
@ -1346,7 +1165,7 @@ let Cmds = {
|
|||
},
|
||||
|
||||
removeProject: function() {
|
||||
return AppManager.removeSelectedProject();
|
||||
AppManager.removeSelectedProject();
|
||||
},
|
||||
|
||||
toggleEditors: function() {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
|
||||
<?xml-stylesheet href="chrome://webide/skin/webide.css"?>
|
||||
|
||||
<window id="webide" onclose="return UI.canCloseProject();"
|
||||
|
@ -26,6 +27,7 @@
|
|||
persist="screenX screenY width height sizemode">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"></script>
|
||||
<script type="application/javascript" src="project-panel.js"></script>
|
||||
<script type="application/javascript" src="webide.js"></script>
|
||||
|
||||
<commandset id="mainCommandSet">
|
||||
|
@ -150,7 +152,7 @@
|
|||
|
||||
<!-- App panel -->
|
||||
<panel id="project-panel" type="arrow" position="bottomcenter topleft" consumeoutsideclicks="true" animate="false">
|
||||
<vbox flex="1">
|
||||
<vbox flex="1" id="project-panel-box">
|
||||
<toolbarbutton class="panel-item project-panel-item-newapp" command="cmd_newApp"/>
|
||||
<toolbarbutton class="panel-item project-panel-item-openpackaged" command="cmd_importPackagedApp"/>
|
||||
<toolbarbutton class="panel-item project-panel-item-openhosted" command="cmd_importHostedApp"/>
|
||||
|
@ -191,18 +193,26 @@
|
|||
</popupset>
|
||||
|
||||
<notificationbox flex="1" id="notificationbox">
|
||||
<deck flex="1" id="deck" selectedIndex="-1">
|
||||
<iframe id="deck-panel-details" flex="1" src="details.xhtml"/>
|
||||
<iframe id="deck-panel-projecteditor" flex="1"/>
|
||||
<iframe id="deck-panel-addons" flex="1" src="addons.xhtml"/>
|
||||
<iframe id="deck-panel-prefs" flex="1" src="prefs.xhtml"/>
|
||||
<iframe id="deck-panel-permissionstable" flex="1" lazysrc="permissionstable.xhtml"/>
|
||||
<iframe id="deck-panel-runtimedetails" flex="1" lazysrc="runtimedetails.xhtml"/>
|
||||
<iframe id="deck-panel-monitor" flex="1" lazysrc="monitor.xhtml"/>
|
||||
<iframe id="deck-panel-devicepreferences" flex="1" lazysrc="devicepreferences.xhtml"/>
|
||||
<iframe id="deck-panel-devicesettings" flex="1" lazysrc="devicesettings.xhtml"/>
|
||||
<iframe id="deck-panel-logs" flex="1" src="logs.xhtml"/>
|
||||
</deck>
|
||||
<hbox flex="1">
|
||||
<vbox id="project-listing-panel" class="project-listing" flex="1">
|
||||
<div id="project-listing-wrapper">
|
||||
<iframe id="project-listing-panel-details" flex="1" src="project-listing.xhtml"/>
|
||||
</div>
|
||||
</vbox>
|
||||
<splitter class="devtools-side-splitter" id="project-listing-splitter"/>
|
||||
<deck flex="1" id="deck" selectedIndex="-1">
|
||||
<iframe id="deck-panel-details" flex="1" src="details.xhtml"/>
|
||||
<iframe id="deck-panel-projecteditor" flex="1"/>
|
||||
<iframe id="deck-panel-addons" flex="1" src="addons.xhtml"/>
|
||||
<iframe id="deck-panel-prefs" flex="1" src="prefs.xhtml"/>
|
||||
<iframe id="deck-panel-permissionstable" flex="1" lazysrc="permissionstable.xhtml"/>
|
||||
<iframe id="deck-panel-runtimedetails" flex="1" lazysrc="runtimedetails.xhtml"/>
|
||||
<iframe id="deck-panel-monitor" flex="1" lazysrc="monitor.xhtml"/>
|
||||
<iframe id="deck-panel-devicepreferences" flex="1" lazysrc="devicepreferences.xhtml"/>
|
||||
<iframe id="deck-panel-devicesettings" flex="1" lazysrc="devicesettings.xhtml"/>
|
||||
<iframe id="deck-panel-logs" flex="1" src="logs.xhtml"/>
|
||||
</deck>
|
||||
</hbox>
|
||||
<splitter hidden="true" class="devtools-horizontal-splitter" orient="vertical"/>
|
||||
<!-- toolbox iframe will be inserted here -->
|
||||
</notificationbox>
|
||||
|
|
|
@ -327,15 +327,17 @@ let AppManager = exports.AppManager = {
|
|||
return this._selectedProject;
|
||||
},
|
||||
|
||||
removeSelectedProject: function() {
|
||||
removeSelectedProject: Task.async(function*() {
|
||||
let location = this.selectedProject.location;
|
||||
AppManager.selectedProject = null;
|
||||
// If the user cancels the removeProject operation, don't remove the project
|
||||
if (AppManager.selectedProject != null) {
|
||||
return;
|
||||
}
|
||||
return AppProjects.remove(location);
|
||||
},
|
||||
|
||||
yield AppProjects.remove(location);
|
||||
AppManager.update("project-removed");
|
||||
}),
|
||||
|
||||
packageProject: Task.async(function*(project) {
|
||||
if (!project) {
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
/* 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/. */
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
|
||||
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
|
||||
const {AppProjects} = require("devtools/app-manager/app-projects");
|
||||
const {AppManager} = require("devtools/webide/app-manager");
|
||||
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
|
||||
const utils = require("devtools/webide/utils");
|
||||
|
||||
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
|
||||
|
||||
let ProjectList;
|
||||
|
||||
module.exports = ProjectList = function(window, parentWindow) {
|
||||
EventEmitter.decorate(this);
|
||||
this._doc = window.document;
|
||||
this._UI = parentWindow.UI;
|
||||
this._parentWindow = parentWindow;
|
||||
this._panelNodeEl = "toolbarbutton";
|
||||
this._sidebarsEnabled = Services.prefs.getBoolPref("devtools.webide.sidebars");
|
||||
|
||||
if (this._sidebarsEnabled) {
|
||||
this._panelNodeEl = "div";
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
ProjectList.prototype = {
|
||||
get doc() {
|
||||
return this._doc;
|
||||
},
|
||||
|
||||
get sidebarsEnabled() {
|
||||
return this._sidebarsEnabled;
|
||||
},
|
||||
|
||||
/**
|
||||
* testOptions: { chrome mochitest support
|
||||
* folder: nsIFile, where to store the app
|
||||
* index: Number, index of the app in the template list
|
||||
* name: String name of the app
|
||||
* }
|
||||
*/
|
||||
newApp: function(testOptions) {
|
||||
let parentWindow = this._parentWindow;
|
||||
return this._UI.busyUntil(Task.spawn(function*() {
|
||||
// Open newapp.xul, which will feed ret.location
|
||||
let ret = {location: null, testOptions: testOptions};
|
||||
parentWindow.openDialog("chrome://webide/content/newapp.xul", "newapp", "chrome,modal", ret);
|
||||
if (!ret.location)
|
||||
return;
|
||||
|
||||
// Retrieve added project
|
||||
let project = AppProjects.get(ret.location);
|
||||
|
||||
// Select project
|
||||
AppManager.selectedProject = project;
|
||||
}), "creating new app");
|
||||
},
|
||||
|
||||
importPackagedApp: function(location) {
|
||||
let parentWindow = this._parentWindow;
|
||||
let UI = this._UI;
|
||||
return UI.busyUntil(Task.spawn(function*() {
|
||||
let directory = utils.getPackagedDirectory(parentWindow, location);
|
||||
|
||||
if (!directory) {
|
||||
// User cancelled directory selection
|
||||
return;
|
||||
}
|
||||
|
||||
yield UI.importAndSelectApp(directory);
|
||||
}), "importing packaged app");
|
||||
},
|
||||
|
||||
importHostedApp: function(location) {
|
||||
let parentWindow = this._parentWindow;
|
||||
let UI = this._UI;
|
||||
return UI.busyUntil(Task.spawn(function*() {
|
||||
let url = utils.getHostedURL(parentWindow, location);
|
||||
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield UI.importAndSelectApp(url);
|
||||
}), "importing hosted app");
|
||||
},
|
||||
|
||||
/**
|
||||
* opts: {
|
||||
* panel: Object, currenl project panel node
|
||||
* name: String, name of the project
|
||||
* icon: String path of the project icon
|
||||
* }
|
||||
*/
|
||||
_renderProjectItem: function(opts) {
|
||||
if (this._sidebarsEnabled) {
|
||||
let span = this._doc.createElement("span");
|
||||
span.textContent = opts.name;
|
||||
let icon = this._doc.createElement("img");
|
||||
icon.className = "project-image";
|
||||
icon.setAttribute("src", opts.icon);
|
||||
opts.panel.appendChild(icon);
|
||||
opts.panel.appendChild(span);
|
||||
} else {
|
||||
opts.panel.setAttribute("label", opts.name);
|
||||
opts.panel.setAttribute("image", opts.icon);
|
||||
}
|
||||
},
|
||||
|
||||
_buildProjectPanelTabs: function() {
|
||||
let tabs = AppManager.tabStore.tabs;
|
||||
let tabsHeaderNode = this._doc.querySelector("#panel-header-tabs");
|
||||
|
||||
if (AppManager.connected && tabs.length > 0) {
|
||||
tabsHeaderNode.removeAttribute("hidden");
|
||||
} else {
|
||||
tabsHeaderNode.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
let tabsNode = this._doc.querySelector("#project-panel-tabs");
|
||||
|
||||
while (tabsNode.hasChildNodes()) {
|
||||
tabsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
let tab = tabs[i];
|
||||
let URL = this._parentWindow.URL;
|
||||
let url;
|
||||
try {
|
||||
url = new URL(tab.url);
|
||||
} catch (e) {
|
||||
// Don't try to handle invalid URLs, especially from Valence.
|
||||
continue;
|
||||
}
|
||||
// Wanted to use nsIFaviconService here, but it only works for visited
|
||||
// tabs, so that's no help for any remote tabs. Maybe some favicon wizard
|
||||
// knows how to get high-res favicons easily, or we could offer actor
|
||||
// support for this (bug 1061654).
|
||||
tab.favicon = url.origin + "/favicon.ico";
|
||||
tab.name = tab.title || Strings.GetStringFromName("project_tab_loading");
|
||||
if (url.protocol.startsWith("http")) {
|
||||
tab.name = url.hostname + ": " + tab.name;
|
||||
}
|
||||
let panelItemNode = this._doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
tabsNode.appendChild(panelItemNode);
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: tab.name,
|
||||
icon: tab.favicon
|
||||
});
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
if (!this._sidebarsEnabled) {
|
||||
this._UI.hidePanels();
|
||||
}
|
||||
AppManager.selectedProject = {
|
||||
type: "tab",
|
||||
app: tab,
|
||||
icon: tab.favicon,
|
||||
location: tab.url,
|
||||
name: tab.name
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
},
|
||||
|
||||
update: function() {
|
||||
let deferred = promise.defer();
|
||||
let doc = this._doc;
|
||||
let panelVboxNode = doc.querySelector("#project-panel > #project-panel-box");
|
||||
let anchorNode = doc.querySelector("#project-panel-button > .panel-button-anchor");
|
||||
let projectsNode = doc.querySelector("#project-panel-projects");
|
||||
|
||||
while (projectsNode.hasChildNodes()) {
|
||||
projectsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
AppProjects.load().then(() => {
|
||||
let projects = AppProjects.store.object.projects;
|
||||
for (let i = 0; i < projects.length; i++) {
|
||||
let project = projects[i];
|
||||
let panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
projectsNode.appendChild(panelItemNode);
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name || AppManager.DEFAULT_PROJECT_NAME,
|
||||
icon: project.icon|| AppManager.DEFAULT_PROJECT_ICON
|
||||
});
|
||||
if (!project.name || !project.icon) {
|
||||
// The result of the validation process (storing names, icons, …) is not stored in
|
||||
// the IndexedDB database when App Manager v1 is used.
|
||||
// We need to run the validation again and update the name and icon of the app.
|
||||
AppManager.validateAndUpdateProject(project).then(() => {
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: project.name,
|
||||
icon: project.icon
|
||||
});
|
||||
});
|
||||
}
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
if (!this._sidebarsEnabled) {
|
||||
this._UI.hidePanels();
|
||||
}
|
||||
AppManager.selectedProject = project;
|
||||
}, true);
|
||||
}
|
||||
|
||||
deferred.resolve();
|
||||
}, deferred.reject);
|
||||
|
||||
let runtimeappsHeaderNode = doc.querySelector("#panel-header-runtimeapps");
|
||||
let sortedApps = [];
|
||||
for (let [manifestURL, app] of AppManager.apps) {
|
||||
sortedApps.push(app);
|
||||
}
|
||||
sortedApps = sortedApps.sort((a, b) => {
|
||||
return a.manifest.name > b.manifest.name;
|
||||
});
|
||||
let mainProcess = AppManager.isMainProcessDebuggable();
|
||||
if (AppManager.connected && (sortedApps.length > 0 || mainProcess)) {
|
||||
runtimeappsHeaderNode.removeAttribute("hidden");
|
||||
} else {
|
||||
runtimeappsHeaderNode.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
let runtimeAppsNode = doc.querySelector("#project-panel-runtimeapps");
|
||||
while (runtimeAppsNode.hasChildNodes()) {
|
||||
runtimeAppsNode.firstChild.remove();
|
||||
}
|
||||
|
||||
if (mainProcess) {
|
||||
let panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: Strings.GetStringFromName("mainProcess_label"),
|
||||
icon: AppManager.DEFAULT_PROJECT_ICON
|
||||
});
|
||||
runtimeAppsNode.appendChild(panelItemNode);
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
if (!this._sidebarsEnabled) {
|
||||
this._UI.hidePanels();
|
||||
}
|
||||
AppManager.selectedProject = {
|
||||
type: "mainProcess",
|
||||
name: Strings.GetStringFromName("mainProcess_label"),
|
||||
icon: AppManager.DEFAULT_PROJECT_ICON
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
|
||||
for (let i = 0; i < sortedApps.length; i++) {
|
||||
let app = sortedApps[i];
|
||||
let panelItemNode = doc.createElement(this._panelNodeEl);
|
||||
panelItemNode.className = "panel-item";
|
||||
this._renderProjectItem({
|
||||
panel: panelItemNode,
|
||||
name: app.manifest.name,
|
||||
icon: app.iconURL
|
||||
});
|
||||
runtimeAppsNode.appendChild(panelItemNode);
|
||||
panelItemNode.addEventListener("click", () => {
|
||||
if (!this._sidebarsEnabled) {
|
||||
this._UI.hidePanels();
|
||||
}
|
||||
AppManager.selectedProject = {
|
||||
type: "runtimeApp",
|
||||
app: app.manifest,
|
||||
icon: app.iconURL,
|
||||
name: app.manifest.name
|
||||
};
|
||||
}, true);
|
||||
}
|
||||
|
||||
// Build the tab list right now, so it's fast...
|
||||
this._buildProjectPanelTabs();
|
||||
|
||||
// But re-list them and rebuild, in case any tabs navigated since the last
|
||||
// time they were listed.
|
||||
if (AppManager.connected) {
|
||||
AppManager.listTabs().then(() => {
|
||||
this._buildProjectPanelTabs();
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
|
@ -10,14 +10,21 @@ DIRS += [
|
|||
'themes',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'test/browser.ini',
|
||||
'test/sidebars/browser.ini'
|
||||
]
|
||||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'test/chrome.ini',
|
||||
'test/sidebars/chrome.ini'
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.devtools.webide += [
|
||||
'modules/addons.js',
|
||||
'modules/app-manager.js',
|
||||
'modules/build.js',
|
||||
'modules/config-view.js',
|
||||
'modules/project-list.js',
|
||||
'modules/remote-resources.js',
|
||||
'modules/runtimes.js',
|
||||
'modules/simulator-process.js',
|
||||
|
|
|
@ -50,7 +50,7 @@ function connectToLocal(win) {
|
|||
function selectTabProject(win) {
|
||||
return Task.spawn(function() {
|
||||
yield win.AppManager.listTabs();
|
||||
win.Cmds.showProjectPanel();
|
||||
win.projectList.update();
|
||||
yield nextTick();
|
||||
let tabsNode = win.document.querySelector("#project-panel-tabs");
|
||||
let tabNode = tabsNode.querySelectorAll(".panel-item")[1];
|
||||
|
|
|
@ -36,6 +36,7 @@ SimpleTest.registerCleanupFunction(() => {
|
|||
Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
|
||||
Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper");
|
||||
Services.prefs.clearUserPref("devtools.webide.autoinstallFxdtAdapters");
|
||||
Services.prefs.clearUserPref("devtools.webide.sidebars");
|
||||
});
|
||||
|
||||
function openWebIDE(autoInstallAddons) {
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[DEFAULT]
|
||||
subsuite = devtools
|
||||
support-files =
|
||||
../head.js
|
|
@ -0,0 +1,8 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
../app/index.html
|
||||
../app/manifest.webapp
|
||||
../head.js
|
||||
|
||||
[test_duplicate_import.html]
|
||||
[test_import.html]
|
|
@ -0,0 +1,75 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="../head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="application/javascript;version=1.8">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Task.spawn(function*() {
|
||||
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
|
||||
let win = yield openWebIDE();
|
||||
let winIframe = win.document.querySelector("#project-listing-panel-details").contentWindow;
|
||||
let packagedAppLocation = getTestFilePath("../app");
|
||||
let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
|
||||
|
||||
yield win.AppProjects.load();
|
||||
is(win.AppProjects.store.object.projects.length, 0, "IDB is empty");
|
||||
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ")");
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
yield nextTick();
|
||||
|
||||
info("to call importHostedApp(" + hostedAppManifest + ")");
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
yield nextTick();
|
||||
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ") again");
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
is(project.location, packagedAppLocation, "Correctly reselected existing packaged app.");
|
||||
yield nextTick();
|
||||
|
||||
info("to call importHostedApp(" + hostedAppManifest + ") again");
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
project = win.AppManager.selectedProject;
|
||||
is(project.location, hostedAppManifest, "Correctly reselected existing hosted app.");
|
||||
yield nextTick();
|
||||
|
||||
let panelNode = winIframe.document.querySelector("#project-panel");
|
||||
let items = panelNode.querySelectorAll(".panel-item");
|
||||
// 3 controls, + 2 projects
|
||||
is(items.length, 5, "5 projects in panel");
|
||||
is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct");
|
||||
is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct");
|
||||
|
||||
yield closeWebIDE(win);
|
||||
|
||||
yield removeAllProjects();
|
||||
|
||||
SimpleTest.finish();
|
||||
}).then(null, e => {
|
||||
ok(false, "Exception: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="../head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="application/javascript;version=1.8">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Task.spawn(function*() {
|
||||
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
|
||||
let win = yield openWebIDE();
|
||||
let winIframe = win.document.querySelector("#project-listing-panel-details").contentWindow;
|
||||
let packagedAppLocation = getTestFilePath("../app");
|
||||
|
||||
yield win.AppProjects.load();
|
||||
is(win.AppProjects.store.object.projects.length, 0, "IDB is empty");
|
||||
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ")");
|
||||
ok(!win.UI._busyPromise, "UI is not busy");
|
||||
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
is(project.location, packagedAppLocation, "Location is valid");
|
||||
is(project.name, "A name (in app directory)", "name field has been updated");
|
||||
is(project.manifest.launch_path, "/index.html", "manifest found. launch_path valid.");
|
||||
is(project.manifest.description, "desc", "manifest found. description valid");
|
||||
|
||||
yield nextTick();
|
||||
|
||||
let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
is(project.location, hostedAppManifest, "Location is valid");
|
||||
is(project.name, "hosted manifest name property", "name field has been updated");
|
||||
|
||||
yield nextTick();
|
||||
|
||||
hostedAppManifest = TEST_BASE + "/app";
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
ok(project.location.endsWith('manifest.webapp'), "The manifest was found and the project was updated");
|
||||
|
||||
let panelNode = winIframe.document.querySelector("#project-panel");
|
||||
let items = panelNode.querySelectorAll(".panel-item");
|
||||
// 3 controls, + 2 projects
|
||||
is(items.length, 6, "6 projects in panel");
|
||||
is(items[3].querySelector("span").textContent, "A name (in app directory)", "Panel text is correct");
|
||||
is(items[4].querySelector("span").textContent, "hosted manifest name property", "Panel text is correct");
|
||||
|
||||
yield closeWebIDE(win);
|
||||
|
||||
yield removeAllProjects();
|
||||
|
||||
SimpleTest.finish();
|
||||
}).then(null, e => {
|
||||
ok(false, "Exception: " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,145 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title></title>
|
||||
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/chrome-harness.js"></script>
|
||||
<script type="application/javascript;version=1.8" src="../head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setBoolPref("devtools.webide.sidebars", true);
|
||||
|
||||
let win;
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
Task.spawn(function*() {
|
||||
if (win) {
|
||||
yield closeWebIDE(win);
|
||||
}
|
||||
DebuggerServer.destroy();
|
||||
yield removeAllProjects();
|
||||
});
|
||||
});
|
||||
|
||||
Task.spawn(function*() {
|
||||
function isPlayActive() {
|
||||
return !win.document.querySelector("#cmd_play").hasAttribute("disabled");
|
||||
}
|
||||
|
||||
function isStopActive() {
|
||||
return !win.document.querySelector("#cmd_stop").hasAttribute("disabled");
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
win = yield openWebIDE();
|
||||
let winIframe = win.document.querySelector("#project-listing-panel-details").contentWindow;
|
||||
|
||||
win.AppManager.runtimeList.usb.push({
|
||||
connect: function(connection) {
|
||||
is(connection, win.AppManager.connection, "connection is valid");
|
||||
connection.host = null; // force connectPipe
|
||||
connection.connect();
|
||||
return promise.resolve();
|
||||
},
|
||||
|
||||
get name() {
|
||||
return "fakeRuntime";
|
||||
}
|
||||
});
|
||||
|
||||
win.AppManager.update("runtimelist");
|
||||
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
|
||||
let panelNode = winIframe.document.querySelector("#runtime-panel");
|
||||
let items = panelNode.querySelectorAll(".runtime-panel-item-usb");
|
||||
is(items.length, 1, "Found one runtime button");
|
||||
|
||||
let deferred = promise.defer();
|
||||
win.AppManager.connection.once(
|
||||
win.Connection.Events.CONNECTED,
|
||||
() => deferred.resolve());
|
||||
|
||||
items[0].click();
|
||||
|
||||
ok(win.document.querySelector("window").className, "busy", "UI is busy");
|
||||
yield win.UI._busyPromise;
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Connected");
|
||||
|
||||
yield waitForUpdate(win, "runtime-apps-found");
|
||||
|
||||
ok(isPlayActive(), "play button is enabled 1");
|
||||
ok(!isStopActive(), "stop button is disabled 1");
|
||||
let oldProject = win.AppManager.selectedProject;
|
||||
win.AppManager.selectedProject = null;
|
||||
|
||||
yield nextTick();
|
||||
|
||||
ok(!isPlayActive(), "play button is disabled 2");
|
||||
ok(!isStopActive(), "stop button is disabled 2");
|
||||
win.AppManager._selectedProject = oldProject;
|
||||
win.UI.updateCommands();
|
||||
|
||||
yield nextTick();
|
||||
|
||||
ok(isPlayActive(), "play button is enabled 3");
|
||||
ok(!isStopActive(), "stop button is disabled 3");
|
||||
|
||||
yield win.Cmds.disconnectRuntime();
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 0, "Disconnected");
|
||||
|
||||
ok(win.AppManager.selectedProject, "A project is still selected");
|
||||
ok(!isPlayActive(), "play button is disabled 4");
|
||||
ok(!isStopActive(), "stop button is disabled 4");
|
||||
|
||||
winIframe.document.querySelectorAll(".runtime-panel-item-other")[1].click();
|
||||
|
||||
yield waitForUpdate(win, "runtime-apps-found");
|
||||
|
||||
is(Object.keys(DebuggerServer._connections).length, 1, "Locally connected");
|
||||
|
||||
ok(win.AppManager.isMainProcessDebuggable(), "Main process available");
|
||||
|
||||
// Select main process
|
||||
yield win.Cmds.showProjectPanel();
|
||||
SimpleTest.executeSoon(() => {
|
||||
winIframe.document.querySelectorAll("#project-panel-runtimeapps .panel-item")[0].click();
|
||||
});
|
||||
|
||||
yield waitForUpdate(win, "project");
|
||||
|
||||
// Toolbox opens automatically for main process / runtime apps
|
||||
ok(win.UI.toolboxPromise, "Toolbox promise exists");
|
||||
yield win.UI.toolboxPromise;
|
||||
|
||||
ok(win.UI.toolboxIframe, "Toolbox iframe exists");
|
||||
|
||||
yield win.Cmds.disconnectRuntime();
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
let packagedAppLocation = getTestFilePath("build_app" + testSuffix + "1");
|
||||
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "details");
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
|
@ -76,7 +76,7 @@
|
|||
// # Now test a full featured package.json
|
||||
packagedAppLocation = getTestFilePath("build_app" + testSuffix + "2");
|
||||
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
|
@ -95,7 +95,7 @@
|
|||
is(loggedMessages[3], "succeed", "log messages are correct");
|
||||
|
||||
// Switch to the package dir in order to verify the generated webapp.manifest
|
||||
yield win.Cmds.importPackagedApp(packageDir);
|
||||
yield win.projectList.importPackagedApp(packageDir);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
|
|
|
@ -27,17 +27,17 @@
|
|||
is(win.AppProjects.store.object.projects.length, 0, "IDB is empty");
|
||||
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ")");
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
yield nextTick();
|
||||
|
||||
info("to call importHostedApp(" + hostedAppManifest + ")");
|
||||
yield win.Cmds.importHostedApp(hostedAppManifest);
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
yield nextTick();
|
||||
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ") again");
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
|
@ -45,7 +45,7 @@
|
|||
yield nextTick();
|
||||
|
||||
info("to call importHostedApp(" + hostedAppManifest + ") again");
|
||||
yield win.Cmds.importHostedApp(hostedAppManifest);
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
project = win.AppManager.selectedProject;
|
||||
is(project.location, hostedAppManifest, "Correctly reselected existing hosted app.");
|
||||
|
|
|
@ -18,60 +18,60 @@
|
|||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Task.spawn(function* () {
|
||||
let win = yield openWebIDE();
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
Task.spawn(function*() {
|
||||
let win = yield openWebIDE();
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
yield win.AppProjects.load();
|
||||
is(win.AppProjects.store.object.projects.length, 0, "IDB is empty");
|
||||
yield win.AppProjects.load();
|
||||
is(win.AppProjects.store.object.projects.length, 0, "IDB is empty");
|
||||
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ")");
|
||||
ok(!win.UI._busyPromise, "UI is not busy");
|
||||
info("to call importPackagedApp(" + packagedAppLocation + ")");
|
||||
ok(!win.UI._busyPromise, "UI is not busy");
|
||||
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
is(project.location, packagedAppLocation, "Location is valid");
|
||||
is(project.name, "A name (in app directory)", "name field has been updated");
|
||||
is(project.manifest.launch_path, "/index.html", "manifest found. launch_path valid.");
|
||||
is(project.manifest.description, "desc", "manifest found. description valid");
|
||||
let project = win.AppManager.selectedProject;
|
||||
is(project.location, packagedAppLocation, "Location is valid");
|
||||
is(project.name, "A name (in app directory)", "name field has been updated");
|
||||
is(project.manifest.launch_path, "/index.html", "manifest found. launch_path valid.");
|
||||
is(project.manifest.description, "desc", "manifest found. description valid");
|
||||
|
||||
yield nextTick();
|
||||
yield nextTick();
|
||||
|
||||
let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
|
||||
yield win.Cmds.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
let hostedAppManifest = TEST_BASE + "hosted_app.manifest";
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
is(project.location, hostedAppManifest, "Location is valid");
|
||||
is(project.name, "hosted manifest name property", "name field has been updated");
|
||||
project = win.AppManager.selectedProject;
|
||||
is(project.location, hostedAppManifest, "Location is valid");
|
||||
is(project.name, "hosted manifest name property", "name field has been updated");
|
||||
|
||||
yield nextTick();
|
||||
yield nextTick();
|
||||
|
||||
hostedAppManifest = TEST_BASE + "/app";
|
||||
yield win.Cmds.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
hostedAppManifest = TEST_BASE + "/app";
|
||||
yield win.projectList.importHostedApp(hostedAppManifest);
|
||||
yield waitForUpdate(win, "project-validated");
|
||||
|
||||
project = win.AppManager.selectedProject;
|
||||
ok(project.location.endsWith('manifest.webapp'), "The manifest was found and the project was updated");
|
||||
project = win.AppManager.selectedProject;
|
||||
ok(project.location.endsWith('manifest.webapp'), "The manifest was found and the project was updated");
|
||||
|
||||
info("opening panel");
|
||||
yield win.Cmds.showProjectPanel();
|
||||
info("panel open");
|
||||
info("opening panel");
|
||||
yield win.Cmds.showProjectPanel();
|
||||
info("panel open");
|
||||
|
||||
let panelNode = win.document.querySelector("#project-panel");
|
||||
let items = panelNode.querySelectorAll(".panel-item");
|
||||
// 3 controls, + 2 projects
|
||||
is(items.length, 6, "6 projects in panel");
|
||||
is(items[3].getAttribute("label"), "A name (in app directory)", "Panel label is correct");
|
||||
is(items[4].getAttribute("label"), "hosted manifest name property", "Panel label is correct");
|
||||
let panelNode = win.document.querySelector("#project-panel");
|
||||
let items = panelNode.querySelectorAll(".panel-item");
|
||||
// 3 controls, + 2 projects
|
||||
is(items.length, 6, "6 projects in panel");
|
||||
is(items[3].getAttribute("label"), "A name (in app directory)", "Panel label is correct");
|
||||
is(items[4].getAttribute("label"), "hosted manifest name property", "Panel label is correct");
|
||||
|
||||
yield closeWebIDE(win);
|
||||
yield closeWebIDE(win);
|
||||
|
||||
yield removeAllProjects();
|
||||
yield removeAllProjects();
|
||||
|
||||
SimpleTest.finish();
|
||||
SimpleTest.finish();
|
||||
}).then(null, e => {
|
||||
ok(false, "Exception: " + e);
|
||||
SimpleTest.finish();
|
||||
|
|
|
@ -25,13 +25,13 @@
|
|||
let AppManager = win.AppManager;
|
||||
|
||||
function isProjectMarkedAsValid() {
|
||||
let details = win.frames[0];
|
||||
let details = win.frames[1];
|
||||
return !details.document.body.classList.contains("error");
|
||||
}
|
||||
|
||||
let packagedAppLocation = getTestFilePath("app");
|
||||
|
||||
yield win.Cmds.importPackagedApp(packagedAppLocation);
|
||||
yield win.projectList.importPackagedApp(packagedAppLocation);
|
||||
yield waitForUpdate(win, "details");
|
||||
|
||||
let project = win.AppManager.selectedProject;
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
Task.spawn(function* () {
|
||||
let win = yield openWebIDE();
|
||||
let tmpDir = FileUtils.getDir("TmpD", []);
|
||||
yield win.Cmds.newApp({
|
||||
yield win.projectList.newApp({
|
||||
index: 0,
|
||||
name: "webideTmpApp",
|
||||
folder: tmpDir
|
||||
|
|
|
@ -18,3 +18,4 @@ webide.jar:
|
|||
skin/config-view.css (config-view.css)
|
||||
skin/wifi-auth.css (wifi-auth.css)
|
||||
skin/logs.css (logs.css)
|
||||
skin/project-listing.css (project-listing.css)
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/* 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/. */
|
||||
|
||||
html {
|
||||
font: message-box;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.panel-item, label, #project-panel-projects {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.project-image, .panel-item span {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.project-image {
|
||||
margin-right: 10px;
|
||||
max-height: 20px;
|
||||
}
|
||||
|
||||
label {
|
||||
color: #888;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
padding: 15px 0 5px;
|
||||
text-shadow: 1px 1px #fff;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.panel-item {
|
||||
cursor: default;
|
||||
padding: 5px 0;
|
||||
min-width: 130px;
|
||||
}
|
|
@ -151,6 +151,44 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
|
|||
max-width: 400px;
|
||||
}
|
||||
|
||||
#project-listing-panel {
|
||||
display: none;
|
||||
position: relative;
|
||||
max-width: 250px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#project-listing-wrapper {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-width: 100px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#project-listing-panel-details {
|
||||
height: inherit;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* TODO: remove once Bug 1079347 is complete */
|
||||
.project-listing, #project-listing-splitter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#project-listing-splitter[sidebar-displayed], #project-listing-panel[sidebar-displayed],
|
||||
#project-listing-panel[sidebar-displayed] .project-listing {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.panel-item {
|
||||
padding: 3px 12px;
|
||||
margin: 0;
|
||||
|
@ -280,14 +318,6 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
|
|||
}
|
||||
|
||||
.devtools-horizontal-splitter {
|
||||
-moz-appearance: none;
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
border-bottom: 1px solid rgba(118, 121, 125, .5);
|
||||
min-height: 3px;
|
||||
height: 3px;
|
||||
margin-top: -3px;
|
||||
position: relative;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
|
|
@ -32,3 +32,4 @@ pref("devtools.webide.widget.inNavbarByDefault", false);
|
|||
#endif
|
||||
pref("devtools.webide.zoom", "1");
|
||||
pref("devtools.webide.busyTimeout", 10000);
|
||||
pref("devtools.webide.sidebars", false);
|
||||
|
|
|
@ -68,13 +68,14 @@ AboutGeneric.prototype = {
|
|||
return Ci.nsIAboutModule.ALLOW_SCRIPT;
|
||||
},
|
||||
|
||||
newChannel: function(aURI) {
|
||||
newChannel: function(aURI, aLoadInfo) {
|
||||
let moduleInfo = this._getModuleInfo(aURI);
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
var channel = ios.newChannel(moduleInfo.uri, null, null);
|
||||
var newURI = ios.newURI(moduleInfo.uri, null, null);
|
||||
var channel = ios.newChannelFromURIWithLoadInfo(newURI, aLoadInfo);
|
||||
|
||||
if (!moduleInfo.privileged) {
|
||||
// Setting the owner to null means that we'll go through the normal
|
||||
|
|
|
@ -843,7 +843,15 @@ SessionStore.prototype = {
|
|||
}
|
||||
|
||||
try {
|
||||
let channel = NetUtil.newChannel(this._sessionFileBackup);
|
||||
let channel = NetUtil.newChannel2(this._sessionFileBackup,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
channel.contentType = "application/json";
|
||||
NetUtil.asyncFetch(channel, function(aStream, aResult) {
|
||||
if (!Components.isSuccessCode(aResult)) {
|
||||
|
|
|
@ -84,6 +84,11 @@ let DirectoryLinksProvider = {
|
|||
*/
|
||||
_enhancedLinks: new Map(),
|
||||
|
||||
/**
|
||||
* A mapping from site to a list of related link objects
|
||||
*/
|
||||
_relatedLinks: new Map(),
|
||||
|
||||
get _observedPrefs() Object.freeze({
|
||||
enhanced: PREF_NEWTAB_ENHANCED,
|
||||
linksURL: PREF_DIRECTORY_SOURCE,
|
||||
|
@ -187,6 +192,14 @@ let DirectoryLinksProvider = {
|
|||
}
|
||||
},
|
||||
|
||||
_cacheRelatedLinks: function(link) {
|
||||
for (let relatedSite of link.related) {
|
||||
let relatedMap = this._relatedLinks.get(relatedSite) || new Map();
|
||||
relatedMap.set(link.url, link);
|
||||
this._relatedLinks.set(relatedSite, relatedMap);
|
||||
}
|
||||
},
|
||||
|
||||
_fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {
|
||||
// Replace with the same display locale used for selecting links data
|
||||
uri = uri.replace("%LOCALE%", this.locale);
|
||||
|
@ -389,24 +402,33 @@ let DirectoryLinksProvider = {
|
|||
*/
|
||||
getLinks: function DirectoryLinksProvider_getLinks(aCallback) {
|
||||
this._readDirectoryLinksFile().then(rawLinks => {
|
||||
// Reset the cache of enhanced images for this new set of links
|
||||
// Reset the cache of related tiles and enhanced images for this new set of links
|
||||
this._enhancedLinks.clear();
|
||||
this._relatedLinks.clear();
|
||||
|
||||
return rawLinks.filter(link => {
|
||||
let links = [];
|
||||
rawLinks.filter(link => {
|
||||
// Make sure the link url is allowed and images too if they exist
|
||||
return this.isURLAllowed(link.url, ALLOWED_LINK_SCHEMES) &&
|
||||
this.isURLAllowed(link.imageURI, ALLOWED_IMAGE_SCHEMES) &&
|
||||
this.isURLAllowed(link.enhancedImageURI, ALLOWED_IMAGE_SCHEMES);
|
||||
}).map((link, position) => {
|
||||
}).forEach((link, position) => {
|
||||
// Stash the enhanced image for the site
|
||||
if (link.enhancedImageURI) {
|
||||
this._enhancedLinks.set(NewTabUtils.extractSite(link.url), link);
|
||||
}
|
||||
|
||||
link.frecency = DIRECTORY_FRECENCY;
|
||||
link.lastVisitDate = rawLinks.length - position;
|
||||
return link;
|
||||
|
||||
// We cache related tiles here but do not push any of them in the links list yet.
|
||||
// The decision for which related tile to include will be made separately.
|
||||
if ("related" == link.type) {
|
||||
this._cacheRelatedLinks(link);
|
||||
return;
|
||||
}
|
||||
link.frecency = DIRECTORY_FRECENCY;
|
||||
links.push(link);
|
||||
});
|
||||
return links;
|
||||
}).catch(ex => {
|
||||
Cu.reportError(ex);
|
||||
return [];
|
||||
|
|
|
@ -175,6 +175,71 @@ function run_test() {
|
|||
});
|
||||
}
|
||||
|
||||
add_task(function test_relatedLinksMap() {
|
||||
let relatedTile1 = {
|
||||
url: "http://turbotax.com",
|
||||
type: "related",
|
||||
lastVisitDate: 4,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"hrblock.com",
|
||||
"1040.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let relatedTile2 = {
|
||||
url: "http://irs.gov",
|
||||
type: "related",
|
||||
lastVisitDate: 3,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"hrblock.com",
|
||||
"freetaxusa.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let relatedTile3 = {
|
||||
url: "http://hrblock.com",
|
||||
type: "related",
|
||||
lastVisitDate: 2,
|
||||
related: [
|
||||
"taxact.com",
|
||||
"freetaxusa.com",
|
||||
"1040.com",
|
||||
"taxslayer.com"
|
||||
]
|
||||
};
|
||||
let someOtherSite = {url: "http://someothersite.com", title: "Not_A_Related_Site"};
|
||||
let data = {"en-US": [relatedTile1, relatedTile2, relatedTile3, someOtherSite]};
|
||||
let dataURI = 'data:application/json,' + JSON.stringify(data);
|
||||
|
||||
yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
|
||||
let links = yield fetchData();
|
||||
|
||||
// Ensure the related tiles were not considered directory tiles.
|
||||
do_check_eq(links.length, 1);
|
||||
let expected_data = [{url: "http://someothersite.com", title: "Not_A_Related_Site", frecency: DIRECTORY_FRECENCY, lastVisitDate: 1}];
|
||||
isIdentical(links, expected_data);
|
||||
|
||||
// Check for correctly saved related tiles data.
|
||||
expected_data = {
|
||||
"taxact.com": [relatedTile1, relatedTile2, relatedTile3],
|
||||
"hrblock.com": [relatedTile1, relatedTile2],
|
||||
"1040.com": [relatedTile1, relatedTile3],
|
||||
"taxslayer.com": [relatedTile1, relatedTile2, relatedTile3],
|
||||
"freetaxusa.com": [relatedTile2, relatedTile3],
|
||||
};
|
||||
|
||||
DirectoryLinksProvider._relatedLinks.forEach((relatedLinks, site) => {
|
||||
let relatedLinksItr = relatedLinks.values();
|
||||
for (let link of expected_data[site]) {
|
||||
isIdentical(relatedLinksItr.next().value, link);
|
||||
}
|
||||
})
|
||||
|
||||
yield promiseCleanDirectoryLinksProvider();
|
||||
});
|
||||
|
||||
add_task(function test_reportSitesAction() {
|
||||
yield DirectoryLinksProvider.init();
|
||||
let deferred, expectedPath, expectedPost;
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
|
||||
if [ "x$IS_NIGHTLY" = "xyes" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
# Some nightlies (eg: Mulet) don't want these set.
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
|
||||
fi
|
||||
. "$topsrcdir/build/mozconfig.common"
|
||||
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if [ "x$IS_NIGHTLY" = "xyes" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
# Some nightlies (eg: Mulet) don't want these set.
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
|
||||
fi
|
||||
|
||||
# Some builds (eg: Mulet) don't want the installer, so only set this if it
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
if [ "x$IS_NIGHTLY" = "xyes" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
# Some nightlies (eg: Mulet) don't want these set.
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
|
||||
fi
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common"
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "nsIGlobalHistory2.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIURI.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsDownloadHistory
|
||||
|
@ -42,7 +43,7 @@ nsDownloadHistory::AddDownload(nsIURI* aSource,
|
|||
|
||||
if (!visited) {
|
||||
nsCOMPtr<nsIObserverService> os =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(aSource, NS_LINK_VISITED_EVENT_TOPIC, nullptr);
|
||||
}
|
||||
|
|
|
@ -19,10 +19,11 @@
|
|||
</style>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<script type="text/javascript;version=1.8">
|
||||
<script type="text/javascript">
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -41,13 +42,42 @@
|
|||
const CSS_ANIM_EVENTS = ['animationstart', 'animationiteration', 'animationend'];
|
||||
const ANIM_DELAY_MS = 1000000; // 1000s
|
||||
const ANIM_DUR_MS = 1000000; // 1000s
|
||||
const ANIM_PROPERTY_VAL = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
|
||||
/**
|
||||
* These helpers get the value that the startTime needs to be set to, to put an
|
||||
* animation that uses the above ANIM_DELAY_MS and ANIM_DUR_MS values into the
|
||||
* middle of various phases or points through the active duration.
|
||||
*/
|
||||
function startTimeForBeforePhase(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS / 2;
|
||||
}
|
||||
function startTimeForActivePhase(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
|
||||
}
|
||||
function startTimeForAfterPhase(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
|
||||
}
|
||||
function startTimeForStartOfActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS;
|
||||
}
|
||||
function startTimeForFiftyPercentThroughActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5;
|
||||
}
|
||||
function startTimeForNinetyPercentThroughActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.9;
|
||||
}
|
||||
function startTimeForEndOfActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS;
|
||||
}
|
||||
|
||||
|
||||
// Expected computed 'margin-left' values at points during the active interval:
|
||||
// When we assert_between_inclusive using these values we could in theory cause
|
||||
// intermittent failure due to long refresh driver delays, but since the active
|
||||
// duration is 1000s long, a delay would need to be around 100s to cause that.
|
||||
// If that's happening than we have issues that we should solve anyway, so a
|
||||
// failure to make us look into that seems like a good thing.
|
||||
// intermittent failure due to very long delays between paints, but since the
|
||||
// active duration is 1000s long, a delay would need to be around 100s to cause
|
||||
// that. If that's happening then there are likely other issues that should be
|
||||
// fixed, so a failure to make us look into that seems like a good thing.
|
||||
const UNANIMATED_POSITION = 10;
|
||||
const INITIAL_POSITION = 100;
|
||||
const TEN_PCT_POSITION = 110;
|
||||
|
@ -55,17 +85,6 @@ const FIFTY_PCT_POSITION = 150;
|
|||
const NINETY_PCT_POSITION = 190;
|
||||
const END_POSITION = 200;
|
||||
|
||||
function addDiv(id)
|
||||
{
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('class', 'animated-div');
|
||||
if (id) {
|
||||
div.setAttribute('id', id);
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS animation events fire asynchronously after we set 'startTime'. This
|
||||
* helper class allows us to handle such events using Promises.
|
||||
|
@ -84,7 +103,7 @@ function addDiv(id)
|
|||
* eventWatcher.stopWatching(); // all done - stop listening for events
|
||||
* });
|
||||
*
|
||||
* This class will assert_true(false) if an event occurs when there is no
|
||||
* This class will assert_unreached() if an event occurs when there is no
|
||||
* Promise created by a waitForEvent() call waiting to be fulfilled, or if the
|
||||
* event is of a different type to the type passed to waitForEvent. This helps
|
||||
* provide test coverage to ensure that only events that are expected occur, in
|
||||
|
@ -102,13 +121,13 @@ function EventWatcher(watchedNode, eventTypes)
|
|||
|
||||
function eventHandler(evt) {
|
||||
if (!waitingFor) {
|
||||
assert_true(false, 'Not expecting event, but got: ' + evt.type +
|
||||
assert_unreached('Not expecting event, but got: ' + evt.type +
|
||||
' targeting element #' + evt.target.getAttribute('id'));
|
||||
return;
|
||||
}
|
||||
if (evt.type != waitingFor.types[0]) {
|
||||
assert_true(false, 'Expected ' + waitingFor.types[0] + ' event but got ' +
|
||||
evt.type + ' event');
|
||||
assert_unreached('Expected ' + waitingFor.types[0] + ' event but got ' +
|
||||
evt.type + ' event');
|
||||
return;
|
||||
}
|
||||
if (waitingFor.types.length > 1) {
|
||||
|
@ -124,8 +143,8 @@ function EventWatcher(watchedNode, eventTypes)
|
|||
resolveFunc(evt);
|
||||
}
|
||||
|
||||
for (let event of eventTypes) {
|
||||
watchedNode.addEventListener(event, eventHandler);
|
||||
for (var i = 0; i < eventTypes.length; i++) {
|
||||
watchedNode.addEventListener(eventTypes[i], eventHandler);
|
||||
}
|
||||
|
||||
this.waitForEvent = function(type) {
|
||||
|
@ -164,8 +183,8 @@ function EventWatcher(watchedNode, eventTypes)
|
|||
};
|
||||
|
||||
this.stopWatching = function() {
|
||||
for (let event of eventTypes) {
|
||||
watchedNode.removeEventListener(event, eventHandler);
|
||||
for (var i = 0; i < eventTypes.length; i++) {
|
||||
watchedNode.removeEventListener(eventTypes[i], eventHandler);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -206,7 +225,7 @@ function checkStateOnSettingStartTimeToAnimationCreationTime(player)
|
|||
// Called when the ready Promise's callbacks should happen
|
||||
function checkStateOnReadyPromiseResolved(player)
|
||||
{
|
||||
assert_less_than_equal(player.startTime, document.timeline.currentTime,
|
||||
assert_less_than_equal(player.startTime, player.timeline.currentTime,
|
||||
'AnimationPlayer.startTime should be less than the timeline\'s ' +
|
||||
'currentTime on the first paint tick after animation creation');
|
||||
|
||||
|
@ -288,11 +307,11 @@ function checkStateAtActiveIntervalEndTime(player)
|
|||
}
|
||||
|
||||
|
||||
test(function()
|
||||
test(function(t)
|
||||
{
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
|
@ -315,48 +334,45 @@ test(function()
|
|||
// will be called (async) regardless of whether the Promise was resolved in
|
||||
// the past or is resolved in the future.
|
||||
|
||||
var currentTime = document.timeline.currentTime;
|
||||
player.startTime = document.timeline.currentTime;
|
||||
var currentTime = player.timeline.currentTime;
|
||||
player.startTime = currentTime;
|
||||
assert_approx_equals(player.startTime, currentTime, 0.0001, // rounding error
|
||||
'Check setting of startTime actually works');
|
||||
|
||||
checkStateOnSettingStartTimeToAnimationCreationTime(player);
|
||||
|
||||
div.parentNode.removeChild(div);
|
||||
}, 'Examine newly created Animation');
|
||||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.ready.then(t.step_func(function() {
|
||||
checkStateOnReadyPromiseResolved(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS; // jump to start of active interval
|
||||
player.startTime = startTimeForStartOfActiveInterval(player.timeline);
|
||||
return eventWatcher.waitForEvent('animationstart');
|
||||
})).then(t.step_func(function() {
|
||||
checkStateAtActiveIntervalStartTime(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5; // 50% through active interval
|
||||
player.startTime = startTimeForFiftyPercentThroughActiveInterval(player.timeline);
|
||||
checkStateAtFiftyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.9; // 90% through active interval
|
||||
player.startTime = startTimeForNinetyPercentThroughActiveInterval(player.timeline);
|
||||
checkStateAtNinetyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS; // end of active interval
|
||||
player.startTime = startTimeForEndOfActiveInterval(player.timeline);
|
||||
return eventWatcher.waitForEvent('animationend');
|
||||
})).then(t.step_func(function() {
|
||||
checkStateAtActiveIntervalEndTime(player);
|
||||
|
||||
eventWatcher.stopWatching();
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
|
@ -364,14 +380,14 @@ async_test(function(t) {
|
|||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS; // end of active interval
|
||||
player.startTime = startTimeForEndOfActiveInterval(player.timeline);
|
||||
|
||||
// Skipping over the active interval will dispatch an 'animationstart' then
|
||||
// an 'animationend' event. We need to wait for these events before we start
|
||||
|
@ -382,7 +398,7 @@ async_test(function(t) {
|
|||
// that after the events we're still in the same end time state:
|
||||
checkStateAtActiveIntervalEndTime(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.9; // 90% through active interval
|
||||
player.startTime = startTimeForNinetyPercentThroughActiveInterval(player.timeline);
|
||||
|
||||
// Despite going backwards from after the end of the animation to just
|
||||
// before the end of the animation, we now expect an animationstart event
|
||||
|
@ -391,13 +407,13 @@ async_test(function(t) {
|
|||
})).then(t.step_func(function() {
|
||||
checkStateAtNinetyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5; // 50% through active interval
|
||||
player.startTime = startTimeForFiftyPercentThroughActiveInterval(player.timeline);
|
||||
checkStateAtFiftyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS; // jump to start of active interval
|
||||
player.startTime = startTimeForStartOfActiveInterval(player.timeline);
|
||||
checkStateAtActiveIntervalStartTime(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime;
|
||||
player.startTime = player.timeline.currentTime;
|
||||
// Despite going backwards from just after the active interval starts to
|
||||
// the animation start time, we now expect an animationend event
|
||||
// because we went from inside to outside the active interval.
|
||||
|
@ -406,9 +422,8 @@ async_test(function(t) {
|
|||
checkStateOnReadyPromiseResolved(player);
|
||||
|
||||
eventWatcher.stopWatching();
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
|
@ -421,102 +436,133 @@ async_test(function(t) {
|
|||
}, 'Skipping backwards through animation');
|
||||
|
||||
|
||||
// Here we have multiple tests to check that redundant startTime changes do NOT
|
||||
// Next we have multiple tests to check that redundant startTime changes do NOT
|
||||
// dispatch events. It's impossible to distinguish between events not being
|
||||
// dispatched and events just taking an incredibly long time to dispatch
|
||||
// without some sort of risk of creating intermittent failure. We have a short
|
||||
// timeout here since we don't want to delay the completion of this test file
|
||||
// waiting for a long time to make "more sure" events weren't dispatched rather
|
||||
// than being late.
|
||||
//
|
||||
// We test:
|
||||
//
|
||||
// * before -> active, then back
|
||||
// * before -> after, then back
|
||||
// * active -> before, then back
|
||||
// * active -> after, then back
|
||||
// * after -> before, then back
|
||||
// * after -> active, then back
|
||||
//
|
||||
// We do all these tests in a single async_test since that allows us to share
|
||||
// the timeout that we use to wait so that this test file isn't delayed by the
|
||||
// timeout time multiplied by number of tests.
|
||||
// without waiting an infinitely long time. Obviously we don't want to do that
|
||||
// (block this test from finishing forever), so instead we just listen for
|
||||
// events until two animation frames (i.e. requestAnimationFrame callbacks)
|
||||
// have happened, then assume that no events will ever be dispatched for the
|
||||
// redundant changes if no events were detected in that time.
|
||||
|
||||
async_test(function(t) {
|
||||
var divs = new Array(6);
|
||||
var eventWatchers = new Array(6);
|
||||
var players = new Array(6);
|
||||
for (let i = 0; i < 6; i++) {
|
||||
divs[i] = addDiv();
|
||||
eventWatchers[i] = new EventWatcher(divs[i], CSS_ANIM_EVENTS);
|
||||
divs[i].style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
players[i] = divs[i].getAnimationPlayers()[0];
|
||||
}
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
var beforeTime = document.timeline.currentTime - ANIM_DELAY_MS / 2;
|
||||
var activeTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
|
||||
var afterTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
|
||||
// before -> active, then back:
|
||||
players[0].startTime = activeTime;
|
||||
players[0].startTime = beforeTime;
|
||||
|
||||
// before -> after, then back:
|
||||
players[1].startTime = afterTime;
|
||||
players[1].startTime = beforeTime;
|
||||
|
||||
// active -> before, then back:
|
||||
eventWatchers[2].waitForEvent('animationstart').then(function() {
|
||||
players[2].startTime = beforeTime;
|
||||
players[2].startTime = activeTime;
|
||||
});
|
||||
players[2].startTime = activeTime; // get us into the initial state
|
||||
|
||||
// active -> after, then back:
|
||||
eventWatchers[3].waitForEvent('animationstart').then(function() {
|
||||
players[3].startTime = afterTime;
|
||||
players[3].startTime = activeTime;
|
||||
});
|
||||
players[3].startTime = activeTime; // get us into the initial state
|
||||
|
||||
// after -> before, then back:
|
||||
eventWatchers[4].waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
players[4].startTime = beforeTime;
|
||||
players[4].startTime = afterTime;
|
||||
});
|
||||
players[4].startTime = afterTime; // get us into the initial state
|
||||
|
||||
// after -> active, then back:
|
||||
eventWatchers[5].waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
players[5].startTime = activeTime;
|
||||
players[5].startTime = afterTime;
|
||||
});
|
||||
players[5].startTime = afterTime; // get us into the initial state
|
||||
|
||||
// See the long comment documenting this async_test for an explanation of
|
||||
// why we have this timeout and its relationship to intermittent failure.
|
||||
setTimeout(function() {
|
||||
for (let i = 0; i < 6; i++) {
|
||||
eventWatchers[i].stopWatching();
|
||||
divs[i].parentNode.removeChild(divs[i]);
|
||||
}
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
}, 1000);
|
||||
}, 'Redundant changes');
|
||||
});
|
||||
}, 'Redundant change, before -> active, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
}, 'Redundant change, before -> after, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvent('animationstart').then(function() {
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
}, 'Redundant change, active -> before, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvent('animationstart').then(function() {
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
}, 'Redundant change, active -> after, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
}, 'Redundant change, after -> before, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
}, 'Redundant change, after -> active, then back');
|
||||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.ready.then(t.step_func(function() {
|
||||
player.startTime = null;
|
||||
return player.ready;
|
||||
})).then(t.step_func(function() {
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
|
@ -524,7 +570,7 @@ async_test(function(t) {
|
|||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
div.style.animation = 'anim 100s';
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
@ -540,10 +586,8 @@ async_test(function(t) {
|
|||
'AnimationPlayer.startTime is null after paused');
|
||||
assert_equals(player.playState, 'paused',
|
||||
'AnimationPlayer.playState is "paused" after pause() call');
|
||||
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
|
|
|
@ -7,12 +7,24 @@
|
|||
* @param t The testharness.js Test object. If provided, this will be used
|
||||
* to register a cleanup callback to remove the div when the test
|
||||
* finishes.
|
||||
*
|
||||
* @param attrs A dictionary object with attribute names and values to set on
|
||||
* the div.
|
||||
*/
|
||||
function addDiv(t) {
|
||||
function addDiv(t, attrs) {
|
||||
var div = document.createElement('div');
|
||||
if (attrs) {
|
||||
for (var attrName in attrs) {
|
||||
div.setAttribute(attrName, attrs[attrName]);
|
||||
}
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
if (t && typeof t.add_cleanup === 'function') {
|
||||
t.add_cleanup(function() { div.remove(); });
|
||||
t.add_cleanup(function() {
|
||||
if (div.parentNode) {
|
||||
div.parentNode.removeChild(div);
|
||||
}
|
||||
});
|
||||
}
|
||||
return div;
|
||||
}
|
||||
|
@ -34,3 +46,19 @@ function waitForFrame() {
|
|||
function waitForAllPlayers(players) {
|
||||
return Promise.all(players.map(function(player) { return player.ready; }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that is resolved after the next two animation frames have
|
||||
* occured (that is, after two consecutive requestAnimationFrame callbacks
|
||||
* have been called).
|
||||
*/
|
||||
function waitForTwoAnimationFrames() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
window.requestAnimationFrame(function() {
|
||||
window.requestAnimationFrame(function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "nsIApplicationCacheContainer.h"
|
||||
#include "nsIApplicationCacheChannel.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
|
@ -686,6 +687,10 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
|
|||
PrefetchDNS(aHref);
|
||||
}
|
||||
|
||||
if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::ePRECONNECT)) {
|
||||
Preconnect(aHref);
|
||||
}
|
||||
|
||||
// is it a stylesheet link?
|
||||
if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
|
||||
return NS_OK;
|
||||
|
@ -857,6 +862,26 @@ nsContentSink::PrefetchDNS(const nsAString &aHref)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsContentSink::Preconnect(const nsAString &aHref)
|
||||
{
|
||||
nsCOMPtr<nsISpeculativeConnect>
|
||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||
if (!speculator) {
|
||||
return;
|
||||
}
|
||||
|
||||
// construct URI using document charset
|
||||
const nsACString& charset = mDocument->GetDocumentCharacterSet();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), aHref,
|
||||
charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(),
|
||||
mDocument->GetDocBaseURI());
|
||||
if (uri) {
|
||||
speculator->SpeculativeConnect(uri, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
|
||||
nsIURI *aManifestURI,
|
||||
|
|
|
@ -164,9 +164,10 @@ protected:
|
|||
void PrefetchHref(const nsAString &aHref, nsINode *aSource,
|
||||
bool aExplicit);
|
||||
|
||||
// aHref can either be the usual URI format or of the form "//www.hostname.com"
|
||||
// without a scheme.
|
||||
// For both PrefetchDNS() and Preconnect() aHref can either be the usual
|
||||
// URI format or of the form "//www.hostname.com" without a scheme.
|
||||
void PrefetchDNS(const nsAString &aHref);
|
||||
void Preconnect(const nsAString &aHref);
|
||||
|
||||
// Gets the cache key (used to identify items in a cache) of the channel.
|
||||
nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey);
|
||||
|
|
|
@ -8846,7 +8846,7 @@ public:
|
|||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
services::GetObserverService();
|
||||
if (observerService) {
|
||||
nsCOMPtr<nsISupportsPRUint64> wrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
|
||||
|
|
|
@ -150,6 +150,8 @@ static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
|
|||
else if (aLink.EqualsLiteral("import") &&
|
||||
nsStyleLinkElement::IsImportEnabled())
|
||||
return nsStyleLinkElement::eHTMLIMPORT;
|
||||
else if (aLink.EqualsLiteral("preconnect"))
|
||||
return nsStyleLinkElement::ePRECONNECT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ public:
|
|||
eSTYLESHEET = 0x00000004,
|
||||
eNEXT = 0x00000008,
|
||||
eALTERNATE = 0x00000010,
|
||||
eHTMLIMPORT = 0x00000020
|
||||
eHTMLIMPORT = 0x00000020,
|
||||
ePRECONNECT = 0x00000040
|
||||
};
|
||||
|
||||
// The return value is a bitwise or of 0 or more RelValues.
|
||||
|
|
|
@ -2044,11 +2044,15 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
|||
}
|
||||
nsCOMPtr<nsIFile> jarFile;
|
||||
jarChannel->GetJarFile(getter_AddRefs(jarFile));
|
||||
rv = mArrayBufferBuilder.mapToFileInPackage(file, jarFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!jarFile) {
|
||||
mIsMappedArrayBuffer = false;
|
||||
} else {
|
||||
channel->SetContentType(NS_LITERAL_CSTRING("application/mem-mapped"));
|
||||
rv = mArrayBufferBuilder.mapToFileInPackage(file, jarFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mIsMappedArrayBuffer = false;
|
||||
} else {
|
||||
channel->SetContentType(NS_LITERAL_CSTRING("application/mem-mapped"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
support-files =
|
||||
file_url.jsm
|
||||
file_empty.html
|
||||
file_bug945152.jar
|
||||
file_bug945152_worker.js
|
||||
file_bug1008126_worker.js
|
||||
|
||||
[test_anonymousContent_xul_window.xul]
|
||||
[test_bug715041.xul]
|
||||
|
@ -18,3 +21,7 @@ support-files =
|
|||
[test_messagemanager_principal.html]
|
||||
[test_messagemanager_send_principal.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_bug945152.html]
|
||||
run-if = os == 'linux'
|
||||
[test_bug1008126.html]
|
||||
run-if = os == 'linux'
|
||||
|
|
|
@ -206,13 +206,31 @@
|
|||
function recvDomTest(message) {
|
||||
savedElement = message.objects.element;
|
||||
|
||||
is(savedElement.QueryInterface(Components.interfaces.nsISupports), savedElement,
|
||||
"QI to nsISupports works");
|
||||
is(savedElement.QueryInterface(Components.interfaces.nsIDOMNode), savedElement,
|
||||
"QI to a random (implemented) interface works");
|
||||
|
||||
function testNoInterface(savedElement, i) {
|
||||
try {
|
||||
savedElement.QueryInterface(i);
|
||||
ok(false, "should have thrown an exception");
|
||||
} catch (e) {
|
||||
is(e.result, Components.results.NS_ERROR_NO_INTERFACE, "threw the right exception");
|
||||
}
|
||||
}
|
||||
|
||||
testNoInterface(savedElement, Components.interfaces.nsIDOMAttr);
|
||||
testNoInterface(savedElement, Components.interfaces.nsIClassInfo);
|
||||
|
||||
// Test to ensure that we don't pass CPOWs to C++-implemented interfaces.
|
||||
// See bug 1072980.
|
||||
if (test_state == "remote") {
|
||||
// This doesn't work because we intercept toString specially
|
||||
// This doesn't work because we intercept toString and QueryInterface specially
|
||||
// and don't cache the function pointer.
|
||||
// See bug 1140636.
|
||||
todo_is(savedElement.toString, savedElement.toString, "toString identity works");
|
||||
todo_is(savedElement.QueryInterface, savedElement.QueryInterface, "toString identity works");
|
||||
|
||||
// This does work because we create a CPOW for isEqualNode that stays
|
||||
// alive as long as we have a reference to the first CPOW (so as long
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var gJar1 = "jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_1.txt";
|
||||
var gJar2 = "jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_2.txt";
|
||||
var gJar3 = "jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_big.txt";
|
||||
var gEntry1 = "data_1.txt";
|
||||
var gEntry2 = "data_2.txt";
|
||||
var gEntry3 = "data_big.txt";
|
||||
var gPaddingChar = ".";
|
||||
var gPaddingSize = 10000;
|
||||
var gPadding = "";
|
||||
|
@ -37,6 +37,11 @@ function checkData(xhr, data, mapped, cb) {
|
|||
}
|
||||
|
||||
self.onmessage = function onmessage(event) {
|
||||
var jar = event.data;
|
||||
|
||||
function makeJarURL(entry) {
|
||||
return "jar:" + jar + "!/" + entry;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
|
||||
|
@ -71,7 +76,7 @@ self.onmessage = function onmessage(event) {
|
|||
}
|
||||
};
|
||||
xhr.onload = runTests;
|
||||
xhr.open("GET", gJar3, true);
|
||||
xhr.open("GET", makeJarURL(gEntry3), true);
|
||||
xhr.responseType = "moz-chunked-arraybuffer";
|
||||
xhr.send();
|
||||
}
|
||||
|
@ -104,7 +109,7 @@ self.onmessage = function onmessage(event) {
|
|||
loadendCount++;
|
||||
checkData(xhr, gData2, false, function() {} );
|
||||
};
|
||||
xhr.open("GET", gJar2, false);
|
||||
xhr.open("GET", makeJarURL(gEntry2), false);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
checkEventCount(runTests);
|
||||
|
@ -112,7 +117,7 @@ self.onmessage = function onmessage(event) {
|
|||
|
||||
function test_sync_xhr_data1() {
|
||||
ok(true, "Test sync XHR with data1");
|
||||
xhr.open("GET", gJar1, false);
|
||||
xhr.open("GET", makeJarURL(gEntry1), false);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
checkData(xhr, gData1, true, runTests);
|
||||
|
@ -120,7 +125,7 @@ self.onmessage = function onmessage(event) {
|
|||
|
||||
function test_sync_xhr_data2() {
|
||||
ok(true, "Test sync XHR with data2");
|
||||
xhr.open("GET", gJar2, false);
|
||||
xhr.open("GET", makeJarURL(gEntry2), false);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
checkData(xhr, gData2, false, runTests);
|
||||
|
@ -131,7 +136,7 @@ self.onmessage = function onmessage(event) {
|
|||
xhr.onload = function() {
|
||||
checkData(xhr, gData1, true, runTests);
|
||||
};
|
||||
xhr.open("GET", gJar1, true);
|
||||
xhr.open("GET", makeJarURL(gEntry1), true);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
}
|
||||
|
@ -141,7 +146,7 @@ self.onmessage = function onmessage(event) {
|
|||
xhr.onload = function() {
|
||||
checkData(xhr, gData2, false, runTests);
|
||||
};
|
||||
xhr.open("GET", gJar2, true);
|
||||
xhr.open("GET", makeJarURL(gEntry2), true);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
}
|
||||
|
|
|
@ -26,10 +26,15 @@ function checkData(response, data_head, cb) {
|
|||
}
|
||||
|
||||
self.onmessage = function onmessage(event) {
|
||||
var jar = event.data;
|
||||
|
||||
function makeJarURL(entry) {
|
||||
return "jar:" + jar + "!/" + entry;
|
||||
}
|
||||
|
||||
function test_mapped_sync() {
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', 'jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_1.txt', false);
|
||||
xhr.open('GET', makeJarURL('data_1.txt'), false);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.send();
|
||||
if (xhr.status) {
|
||||
|
@ -42,7 +47,7 @@ self.onmessage = function onmessage(event) {
|
|||
|
||||
function test_mapped_async() {
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', 'jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_1.txt');
|
||||
xhr.open('GET', makeJarURL('data_1.txt'));
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState !== xhr.DONE) {
|
||||
|
@ -62,7 +67,7 @@ self.onmessage = function onmessage(event) {
|
|||
// handled by memory allocation instead of memory mapping.
|
||||
function test_non_mapped() {
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', 'jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_2.txt');
|
||||
xhr.open('GET', makeJarURL('data_2.txt'));
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState !== xhr.DONE) {
|
||||
|
|
|
@ -162,8 +162,6 @@ support-files =
|
|||
file_bug902350_frame.html
|
||||
file_bug907892.html
|
||||
file_bug945152.jar
|
||||
file_bug945152_worker.js
|
||||
file_bug1008126_worker.js
|
||||
file_general_document.html
|
||||
file_html_in_xhr.html
|
||||
file_html_in_xhr.sjs
|
||||
|
@ -659,11 +657,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
|
|||
[test_bug907892.html]
|
||||
[test_bug922681.html]
|
||||
[test_bug927196.html]
|
||||
[test_bug945152.html]
|
||||
skip-if = os != 'linux'
|
||||
[test_bug982153.html]
|
||||
[test_bug1008126.html]
|
||||
skip-if = os != 'linux'
|
||||
[test_bug1057176.html]
|
||||
[test_bug1070015.html]
|
||||
[test_bug1075702.html]
|
||||
|
|
|
@ -10,8 +10,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1008126
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1008126</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1008126">Mozilla Bug 1008126</a>
|
||||
|
@ -20,10 +20,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1008126
|
|||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
<script type="application/javascript;version=1.7">
|
||||
function translateChrome(uriStr) {
|
||||
const { Cc, Ci } = SpecialPowers;
|
||||
let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
|
||||
let uri = ios.newURI(uriStr, null, ios.newURI(document.baseURI, null, null));
|
||||
return chromeReg.convertChromeURL(uri).spec;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
|
||||
var worker = new Worker("file_bug1008126_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
|
@ -36,11 +42,11 @@ function runTest() {
|
|||
|
||||
worker.onerror = function(event) {
|
||||
is(event.target, worker);
|
||||
ok(false, "Worker had an error: " + event.message);
|
||||
ok(false, "Worker had an error: " + event.filename + ":" + event.lineno + ":" + event.colno + ": " + event.message);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
worker.postMessage(true);
|
||||
worker.postMessage(translateChrome("file_bug945152.jar"));
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
|
|
@ -6,8 +6,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 945152</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=945152">Mozilla Bug 945152</a>
|
||||
|
@ -16,7 +16,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
|||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
<script type="application/javascript;version=1.7">
|
||||
function translateChrome(uriStr) {
|
||||
const { Cc, Ci } = SpecialPowers;
|
||||
let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
|
||||
let uri = ios.newURI(uriStr, null, ios.newURI(document.baseURI, null, null));
|
||||
return chromeReg.convertChromeURL(uri).spec;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var worker = new Worker("file_bug945152_worker.js");
|
||||
|
@ -31,11 +38,11 @@ function runTest() {
|
|||
|
||||
worker.onerror = function(event) {
|
||||
is(event.target, worker);
|
||||
ok(false, "Worker had an error: " + event.data);
|
||||
ok(false, "Worker had an error: " + event.filename + ":" + event.lineno + ":" + event.colno + ": " + event.message);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
worker.postMessage(true);
|
||||
worker.postMessage(translateChrome("file_bug945152.jar"));
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "CameraPreferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
|
||||
#include "GonkBufferQueueProducer.h"
|
||||
#endif
|
||||
#include "GonkCameraControl.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "CameraCommon.h"
|
||||
|
@ -187,6 +190,7 @@ GonkCameraHardware::Init()
|
|||
sp<IGraphicBufferProducer> producer;
|
||||
sp<IGonkGraphicBufferConsumer> consumer;
|
||||
GonkBufferQueue::createBufferQueue(&producer, &consumer);
|
||||
static_cast<GonkBufferQueueProducer*>(producer.get())->setSynchronousMode(false);
|
||||
mNativeWindow = new GonkNativeWindow(consumer, GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
|
||||
mCamera->setPreviewTarget(producer);
|
||||
#elif ANDROID_VERSION >= 19
|
||||
|
|
|
@ -31,6 +31,9 @@ public:
|
|||
NetworkError()
|
||||
{
|
||||
nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
|
||||
ErrorResult result;
|
||||
response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result);
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
response->mType = ResponseType::Error;
|
||||
return response.forget();
|
||||
}
|
||||
|
|
|
@ -112,6 +112,8 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
|
|||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
r->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, aRv);
|
||||
MOZ_ASSERT(!aRv.Failed());
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
|
|
@ -419,7 +419,8 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
// SetAttr handles setting src since it needs to catch img.src =
|
||||
// img.src, so we only need to handle the unset case
|
||||
if (InResponsiveMode()) {
|
||||
if (mResponsiveSelector->Content() == this) {
|
||||
if (mResponsiveSelector &&
|
||||
mResponsiveSelector->Content() == this) {
|
||||
mResponsiveSelector->SetDefaultSource(NullString());
|
||||
}
|
||||
QueueImageLoadTask();
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMStyleSheet.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsIStyleSheet.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "nsIURL.h"
|
||||
|
@ -147,6 +148,10 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
aDocument->RegisterPendingLinkUpdate(this);
|
||||
}
|
||||
|
||||
if (IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
|
||||
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
|
||||
nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update));
|
||||
|
||||
|
@ -292,6 +297,30 @@ HTMLLinkElement::UpdateImport()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::UpdatePreconnect()
|
||||
{
|
||||
// rel type should be preconnect
|
||||
nsAutoString rel;
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, NodePrincipal());
|
||||
if (!(linkTypes & ePRECONNECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISpeculativeConnect>
|
||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||
if (speculator) {
|
||||
nsCOMPtr<nsIURI> uri = GetHrefURI();
|
||||
if (uri) {
|
||||
speculator->SpeculativeConnect(uri, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
|
@ -326,11 +355,16 @@ HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
|||
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
|
||||
} else if (linkTypes & eHTMLIMPORT) {
|
||||
UpdateImport();
|
||||
} else if ((linkTypes & ePRECONNECT) && IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::href) {
|
||||
UpdateImport();
|
||||
if (IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
void LinkRemoved();
|
||||
|
||||
void UpdateImport();
|
||||
void UpdatePreconnect();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
|
||||
|
|
|
@ -11,10 +11,6 @@
|
|||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "nsCycleCollector.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
|
@ -76,7 +72,7 @@ IDBWrapperCache::SetScriptOwner(JSObject* aScriptOwner)
|
|||
void
|
||||
IDBWrapperCache::AssertIsRooted() const
|
||||
{
|
||||
MOZ_ASSERT(cyclecollector::IsJSHolder(const_cast<IDBWrapperCache*>(this)),
|
||||
MOZ_ASSERT(IsJSHolder(const_cast<IDBWrapperCache*>(this)),
|
||||
"Why aren't we rooted?!");
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1609,7 +1609,7 @@ void MediaDecoder::Invalidate()
|
|||
// Constructs the time ranges representing what segments of the media
|
||||
// are buffered and playable.
|
||||
nsresult MediaDecoder::GetBuffered(dom::TimeRanges* aBuffered) {
|
||||
NS_ENSURE_TRUE(mDecoderStateMachine, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(mDecoderStateMachine && !mShuttingDown, NS_ERROR_FAILURE);
|
||||
return mDecoderStateMachine->GetBuffered(aBuffered);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -51,6 +54,8 @@ MediaKeySession::MediaKeySession(JSContext* aCx,
|
|||
, mUninitialized(true)
|
||||
, mKeyStatusMap(new MediaKeyStatusMap(aCx, aParent, aRv))
|
||||
{
|
||||
EME_LOG("MediaKeySession[%p,''] session Id set", this);
|
||||
|
||||
MOZ_ASSERT(aParent);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
|
@ -60,6 +65,9 @@ MediaKeySession::MediaKeySession(JSContext* aCx,
|
|||
|
||||
void MediaKeySession::SetSessionId(const nsAString& aSessionId)
|
||||
{
|
||||
EME_LOG("MediaKeySession[%p,'%s'] session Id set",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
|
||||
if (NS_WARN_IF(!mSessionId.IsEmpty())) {
|
||||
return;
|
||||
}
|
||||
|
@ -129,6 +137,25 @@ MediaKeySession::UpdateKeyStatusMap()
|
|||
}
|
||||
|
||||
mKeyStatusMap->Update(keyStatuses);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
nsAutoCString message(
|
||||
nsPrintfCString("MediaKeySession[%p,'%s'] key statuses change {",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get()));
|
||||
for (const CDMCaps::KeyStatus& status : keyStatuses) {
|
||||
nsAutoCString base64KeyId;
|
||||
nsDependentCSubstring rawKeyId(reinterpret_cast<const char*>(status.mId.Elements()),
|
||||
status.mId.Length());
|
||||
nsresult rv = Base64Encode(rawKeyId, base64KeyId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
message.Append(nsPrintfCString(" (%s,%s)", base64KeyId.get(),
|
||||
MediaKeyStatusValues::strings[status.mStatus].value));
|
||||
}
|
||||
message.Append(" }");
|
||||
EME_LOG(message.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
MediaKeyStatusMap*
|
||||
|
@ -148,6 +175,8 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
|
|||
}
|
||||
|
||||
if (!mUninitialized) {
|
||||
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, uninitialized",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -158,15 +187,37 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
|
|||
if (aInitDataType.IsEmpty() ||
|
||||
!CopyArrayBufferViewOrArrayBufferData(aInitData, data)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, "
|
||||
"invalid initData or initDataType",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
// Convert initData to base64 for easier logging.
|
||||
// Note: UpdateSession() Move()s the data out of the array, so we have
|
||||
// to copy it here.
|
||||
nsAutoCString base64InitData;
|
||||
nsDependentCSubstring rawInitData(reinterpret_cast<const char*>(data.Elements()),
|
||||
data.Length());
|
||||
if (NS_FAILED(Base64Encode(rawInitData, base64InitData))) {
|
||||
NS_WARNING("Failed to base64 encode initData for logging");
|
||||
}
|
||||
#endif
|
||||
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->CreateSession(Token(),
|
||||
mSessionType,
|
||||
pid,
|
||||
aInitDataType, data);
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() sent, "
|
||||
"promiseId=%d initData(base64)='%s'",
|
||||
this,
|
||||
NS_ConvertUTF16toUTF8(mSessionId).get(),
|
||||
pid,
|
||||
base64InitData.get());
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -181,11 +232,14 @@ MediaKeySession::Load(const nsAString& aSessionId, ErrorResult& aRv)
|
|||
if (aSessionId.IsEmpty()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
// "The sessionId parameter is empty."
|
||||
EME_LOG("MediaKeySession[%p,''] Load() failed, no sessionId", this);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (!mUninitialized) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Load() failed, uninitialized",
|
||||
this, NS_ConvertUTF16toUTF8(aSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -199,7 +253,11 @@ MediaKeySession::Load(const nsAString& aSessionId, ErrorResult& aRv)
|
|||
// Associate with the known sessionId.
|
||||
SetSessionId(aSessionId);
|
||||
|
||||
mKeys->GetCDMProxy()->LoadSession(mKeys->StorePromise(promise), aSessionId);
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->LoadSession(pid, aSessionId);
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Load() sent to CDM, promiseId=%d",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -216,11 +274,36 @@ MediaKeySession::Update(const ArrayBufferViewOrArrayBuffer& aResponse, ErrorResu
|
|||
!mKeys->GetCDMProxy() ||
|
||||
!CopyArrayBufferViewOrArrayBufferData(aResponse, data)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Update() failed, invalid response buffer",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
// Convert response to base64 for easier logging.
|
||||
// Note: UpdateSession() Move()s the data out of the array, so we have
|
||||
// to copy it here.
|
||||
nsAutoCString base64Response;
|
||||
nsDependentCSubstring rawResponse(reinterpret_cast<const char*>(data.Elements()),
|
||||
data.Length());
|
||||
if (NS_FAILED(Base64Encode(rawResponse, base64Response))) {
|
||||
NS_WARNING("Failed to base64 encode response for logging");
|
||||
}
|
||||
#endif
|
||||
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->UpdateSession(mSessionId,
|
||||
mKeys->StorePromise(promise),
|
||||
pid,
|
||||
data);
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Update() sent to CDM, "
|
||||
"promiseId=%d Response(base64)='%s'",
|
||||
this,
|
||||
NS_ConvertUTF16toUTF8(mSessionId).get(),
|
||||
pid,
|
||||
base64Response.get());
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -232,11 +315,17 @@ MediaKeySession::Close(ErrorResult& aRv)
|
|||
return nullptr;
|
||||
}
|
||||
if (IsClosed() || !mKeys->GetCDMProxy()) {
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Close() already closed",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->CloseSession(mSessionId, mKeys->StorePromise(promise));
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Close() sent to CDM, promiseId=%d",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -246,6 +335,8 @@ MediaKeySession::OnClosed()
|
|||
if (IsClosed()) {
|
||||
return;
|
||||
}
|
||||
EME_LOG("MediaKeySession[%p,'%s'] session close operation complete.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
mIsClosed = true;
|
||||
mKeys->OnSessionClosed(this);
|
||||
mKeys = nullptr;
|
||||
|
@ -268,14 +359,22 @@ MediaKeySession::Remove(ErrorResult& aRv)
|
|||
if (mSessionType != SessionType::Persistent) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
// "The operation is not supported on session type sessions."
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Remove() failed, sesion not persisrtent.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
if (IsClosed() || !mKeys->GetCDMProxy()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
// "The session is closed."
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Remove() failed, already session closed.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
mKeys->GetCDMProxy()->RemoveSession(mSessionId, mKeys->StorePromise(promise));
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->RemoveSession(mSessionId, pid);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Remove() sent to CDM, promiseId=%d.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
@ -283,6 +382,19 @@ void
|
|||
MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
nsAutoCString base64MsgData;
|
||||
nsDependentCSubstring rawMsgData(reinterpret_cast<const char*>(aMessage.Elements()),
|
||||
aMessage.Length());
|
||||
if (NS_FAILED(Base64Encode(rawMsgData, base64MsgData))) {
|
||||
NS_WARNING("Failed to base64 encode message for logging");
|
||||
}
|
||||
EME_LOG("MediaKeySession[%p,'%s'] DispatchKeyMessage() type=%s message(base64)='%s'",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(),
|
||||
MediaKeyMessageTypeValues::strings[uint32_t(aMessageType)].value,
|
||||
base64MsgData.get());
|
||||
#endif
|
||||
|
||||
nsRefPtr<MediaKeyMessageEvent> event(
|
||||
MediaKeyMessageEvent::Constructor(this, aMessageType, aMessage));
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
|
@ -293,6 +405,9 @@ MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType,
|
|||
void
|
||||
MediaKeySession::DispatchKeyError(uint32_t aSystemCode)
|
||||
{
|
||||
EME_LOG("MediaKeySession[%p,'%s'] DispatchKeyError() systemCode=%u.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), aSystemCode);
|
||||
|
||||
RefPtr<MediaKeyError> event(new MediaKeyError(this, aSystemCode));
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, event);
|
||||
|
|
|
@ -52,6 +52,8 @@ MediaKeys::MediaKeys(nsPIDOMWindow* aParent, const nsAString& aKeySystem)
|
|||
, mKeySystem(aKeySystem)
|
||||
, mCreatePromiseId(0)
|
||||
{
|
||||
EME_LOG("MediaKeys[%p] constructed keySystem=%s",
|
||||
this, NS_ConvertUTF16toUTF8(mKeySystem).get());
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
|
@ -67,6 +69,7 @@ RejectPromises(const uint32_t& aKey,
|
|||
MediaKeys::~MediaKeys()
|
||||
{
|
||||
Shutdown();
|
||||
EME_LOG("MediaKeys[%p] destroyed", this);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
|
@ -91,6 +94,8 @@ CloseSessions(const nsAString& aKey,
|
|||
void
|
||||
MediaKeys::Terminated()
|
||||
{
|
||||
EME_LOG("MediaKeys[%p] CDM crashed unexpectedly", this);
|
||||
|
||||
KeySessionHashMap keySessions;
|
||||
// Remove entries during iteration will screw it. Make a copy first.
|
||||
mKeySessions.Enumerate(&CopySessions, &keySessions);
|
||||
|
@ -385,6 +390,8 @@ MediaKeys::CreateSession(JSContext* aCx,
|
|||
SessionType aSessionType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
EME_LOG("MediaKeys[%p] Creating session", this);
|
||||
|
||||
nsRefPtr<MediaKeySession> session = new MediaKeySession(aCx,
|
||||
GetParentObject(),
|
||||
this,
|
||||
|
|
|
@ -265,14 +265,23 @@ GetWorkerPref(const nsACString& aPref,
|
|||
return result;
|
||||
}
|
||||
|
||||
// This function creates a key for a SharedWorker composed by "name|scriptSpec".
|
||||
// This function creates a key for a SharedWorker composed by "shared|name|scriptSpec"
|
||||
// and a key for a ServiceWorker composed by "service|scope|scriptSpec".
|
||||
// If the name contains a '|', this will be replaced by '||'.
|
||||
void
|
||||
GenerateSharedWorkerKey(const nsACString& aScriptSpec, const nsACString& aName,
|
||||
nsCString& aKey)
|
||||
WorkerType aWorkerType, nsCString& aKey)
|
||||
{
|
||||
aKey.Truncate();
|
||||
aKey.SetCapacity(aScriptSpec.Length() + aName.Length() + 1);
|
||||
NS_NAMED_LITERAL_CSTRING(sharedPrefix, "shared|");
|
||||
NS_NAMED_LITERAL_CSTRING(servicePrefix, "service|");
|
||||
MOZ_ASSERT(servicePrefix.Length() > sharedPrefix.Length());
|
||||
MOZ_ASSERT(aWorkerType == WorkerTypeShared ||
|
||||
aWorkerType == WorkerTypeService);
|
||||
aKey.SetCapacity(servicePrefix.Length() + aScriptSpec.Length() +
|
||||
aName.Length() + 1);
|
||||
|
||||
aKey.Append(aWorkerType == WorkerTypeService ? servicePrefix : sharedPrefix);
|
||||
|
||||
nsACString::const_iterator start, end;
|
||||
aName.BeginReading(start);
|
||||
|
@ -1463,7 +1472,8 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
const nsCString& sharedWorkerName = aWorkerPrivate->SharedWorkerName();
|
||||
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName, key);
|
||||
GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName,
|
||||
aWorkerPrivate->Type(), key);
|
||||
MOZ_ASSERT(!domainInfo->mSharedWorkerInfos.Get(key));
|
||||
|
||||
SharedWorkerInfo* sharedWorkerInfo =
|
||||
|
@ -1568,7 +1578,8 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
|||
if (match.mSharedWorkerInfo) {
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
|
||||
match.mSharedWorkerInfo->mName, key);
|
||||
match.mSharedWorkerInfo->mName,
|
||||
aWorkerPrivate->Type(), key);
|
||||
domainInfo->mSharedWorkerInfos.Remove(key);
|
||||
}
|
||||
}
|
||||
|
@ -2297,7 +2308,7 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(scriptSpec, aName, key);
|
||||
GenerateSharedWorkerKey(scriptSpec, aName, aType, key);
|
||||
|
||||
if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo) &&
|
||||
domainInfo->mSharedWorkerInfos.Get(key, &sharedWorkerInfo)) {
|
||||
|
@ -2372,7 +2383,8 @@ RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
|
|||
if (match.mSharedWorkerInfo) {
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
|
||||
match.mSharedWorkerInfo->mName, key);
|
||||
match.mSharedWorkerInfo->mName,
|
||||
aWorkerPrivate->Type(), key);
|
||||
domainInfo->mSharedWorkerInfos.Remove(key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,11 +77,28 @@ function testClone() {
|
|||
});
|
||||
}
|
||||
|
||||
function testError() {
|
||||
var res = Response.error();
|
||||
is(res.status, 0, "Error response status should be 0");
|
||||
try {
|
||||
res.headers.set("someheader", "not allowed");
|
||||
ok(false, "Error response should have immutable headers");
|
||||
} catch(e) {
|
||||
ok(true, "Error response should have immutable headers");
|
||||
}
|
||||
}
|
||||
|
||||
function testRedirect() {
|
||||
var res = Response.redirect("./redirect.response");
|
||||
is(res.status, 302, "Default redirect has status code 302");
|
||||
var h = res.headers.get("location");
|
||||
ok(h === (new URL("./redirect.response", self.location.href)).href, "Location header should be correct absolute URL");
|
||||
try {
|
||||
res.headers.set("someheader", "not allowed");
|
||||
ok(false, "Redirects should have immutable headers");
|
||||
} catch(e) {
|
||||
ok(true, "Redirects should have immutable headers");
|
||||
}
|
||||
|
||||
var successStatus = [301, 302, 303, 307, 308];
|
||||
for (var i = 0; i < successStatus.length; ++i) {
|
||||
|
@ -217,6 +234,7 @@ onmessage = function() {
|
|||
var done = function() { postMessage({ type: 'finish' }) }
|
||||
|
||||
testDefaultCtor();
|
||||
testError();
|
||||
testRedirect();
|
||||
testOk();
|
||||
testFinalURL();
|
||||
|
|
|
@ -30,6 +30,7 @@ support-files =
|
|||
serviceworker_wrapper.js
|
||||
message_receiver.html
|
||||
close_test.js
|
||||
serviceworker_not_sharedworker.js
|
||||
|
||||
[test_unregister.html]
|
||||
[test_installation_simple.html]
|
||||
|
@ -46,3 +47,4 @@ support-files =
|
|||
[test_match_all_client_properties.html]
|
||||
[test_close.html]
|
||||
[test_serviceworker_interfaces.html]
|
||||
[test_serviceworker_not_sharedworker.html]
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
function OnMessage(e)
|
||||
{
|
||||
if (e.data.msg == "whoareyou") {
|
||||
if ("ServiceWorker" in self) {
|
||||
self.clients.matchAll().then(function(clients) {
|
||||
clients[0].postMessage({result: "serviceworker"});
|
||||
});
|
||||
} else {
|
||||
port.postMessage({result: "sharedworker"});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var port;
|
||||
onconnect = function(e) {
|
||||
port = e.ports[0];
|
||||
port.onmessage = OnMessage;
|
||||
port.start();
|
||||
};
|
||||
|
||||
onmessage = OnMessage;
|
|
@ -0,0 +1,72 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1141274 - test that service workers and shared workers are separate</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
const SCOPE = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/";
|
||||
function runTest() {
|
||||
navigator.serviceWorker.register("serviceworker_not_sharedworker.js",
|
||||
{scope: SCOPE})
|
||||
.then(function(registration) {
|
||||
if (registration.installing) {
|
||||
registration.installing.onstatechange = function(e) {
|
||||
e.target.onstatechange = null;
|
||||
setupSW(registration);
|
||||
};
|
||||
} else {
|
||||
setupSW(registration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var sw, worker;
|
||||
function setupSW(registration) {
|
||||
sw = registration.waiting || registration.active;
|
||||
worker = new SharedWorker("serviceworker_not_sharedworker.js", SCOPE);
|
||||
worker.port.start();
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "message_receiver.html";
|
||||
iframe.onload = function() {
|
||||
window.onmessage = function(e) {
|
||||
is(e.data.result, "serviceworker", "We should be talking to a service worker");
|
||||
window.onmessage = null;
|
||||
worker.port.onmessage = function(e) {
|
||||
is(e.data.result, "sharedworker", "We should be talking to a shared worker");
|
||||
registration.unregister().then(function(success) {
|
||||
ok(success, "unregister should succeed");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
worker.port.postMessage({msg: "whoareyou"});
|
||||
};
|
||||
sw.postMessage({msg: "whoareyou"});
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -15,7 +15,7 @@
|
|||
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for LayerManager::AddRef, etc
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "mozilla/layers/Effects.h" // for EffectChain
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsString.h" // for nsAutoCString
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "TiledContentHost.h" // for TiledContentHost
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_WARNING
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
#include "ipc/ShadowLayerUtils.h"
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
#include "nsAppRunner.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_WARNING, NS_RUNTIMEABORT, etc
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "mozilla/layers/Effects.h" // for EffectChain
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsMathUtils.h" // for NS_lround
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "mozilla/layers/PTextureParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
|
|
@ -37,6 +37,7 @@ struct RemoteObject
|
|||
uint64_t serializedId;
|
||||
bool isCallable;
|
||||
bool isConstructor;
|
||||
bool isDOMObject;
|
||||
nsCString objectTag;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "CPOWTimer.h"
|
||||
#include "WrapperFactory.h"
|
||||
|
@ -26,15 +27,21 @@ struct AuxCPOWData
|
|||
ObjectId id;
|
||||
bool isCallable;
|
||||
bool isConstructor;
|
||||
bool isDOMObject;
|
||||
|
||||
// The object tag is just some auxilliary information that clients can use
|
||||
// however they see fit.
|
||||
nsCString objectTag;
|
||||
|
||||
AuxCPOWData(ObjectId id, bool isCallable, bool isConstructor, const nsACString &objectTag)
|
||||
AuxCPOWData(ObjectId id,
|
||||
bool isCallable,
|
||||
bool isConstructor,
|
||||
bool isDOMObject,
|
||||
const nsACString &objectTag)
|
||||
: id(id),
|
||||
isCallable(isCallable),
|
||||
isConstructor(isConstructor),
|
||||
isDOMObject(isDOMObject),
|
||||
objectTag(objectTag)
|
||||
{}
|
||||
};
|
||||
|
@ -153,7 +160,7 @@ CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, Handl
|
|||
|
||||
bool
|
||||
WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
|
@ -183,7 +190,7 @@ CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, Ha
|
|||
|
||||
bool
|
||||
WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
|
@ -214,7 +221,7 @@ CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
|||
|
||||
bool
|
||||
WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
ObjectOpResult &result)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
@ -338,6 +345,19 @@ CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
|||
FORWARD(get, (cx, proxy, receiver, id, vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
CPOWDOMQI(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) {
|
||||
JS_ReportError(cx, "bad this object passed to special QI");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject proxy(cx, &args.thisv().toObject());
|
||||
FORWARD(DOMQI, (cx, proxy, args));
|
||||
}
|
||||
|
||||
static bool
|
||||
CPOWToString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
|
@ -392,6 +412,49 @@ WrapperOwner::toString(JSContext *cx, HandleObject cpow, JS::CallArgs &args)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::DOMQI(JSContext *cx, JS::HandleObject proxy, JS::CallArgs &args)
|
||||
{
|
||||
// Someone's calling us, handle nsISupports specially to avoid unnecessary
|
||||
// CPOW traffic.
|
||||
HandleValue id = args[0];
|
||||
if (id.isObject()) {
|
||||
RootedObject idobj(cx, &id.toObject());
|
||||
nsCOMPtr<nsIJSID> jsid;
|
||||
|
||||
nsresult rv = UnwrapArg<nsIJSID>(idobj, getter_AddRefs(jsid));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(jsid, "bad wrapJS");
|
||||
const nsID *idptr = jsid->GetID();
|
||||
if (idptr->Equals(NS_GET_IID(nsISupports))) {
|
||||
args.rval().set(args.thisv());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Webidl-implemented DOM objects never have nsIClassInfo.
|
||||
if (idptr->Equals(NS_GET_IID(nsIClassInfo)))
|
||||
return Throw(cx, NS_ERROR_NO_INTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
// It wasn't nsISupports, call into the other process to do the QI for us
|
||||
// (since we don't know what other interfaces our object supports). Note
|
||||
// that we have to use JS_GetPropertyDescriptor here to avoid infinite
|
||||
// recursion back into CPOWDOMQI via WrapperOwner::get().
|
||||
// We could stash the actual QI function on our own function object to avoid
|
||||
// if we're called multiple times, but since we're transient, there's no
|
||||
// point right now.
|
||||
JS::Rooted<JSPropertyDescriptor> propDesc(cx);
|
||||
if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc))
|
||||
return false;
|
||||
|
||||
if (!propDesc.value().isObject()) {
|
||||
MOZ_ASSERT_UNREACHABLE("We didn't get QueryInterface off a node");
|
||||
return Throw(cx, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
return JS_CallFunctionValue(cx, proxy, propDesc.value(), args, args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp)
|
||||
|
@ -406,6 +469,22 @@ WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
|||
if (!toJSIDVariant(cx, id, &idVar))
|
||||
return false;
|
||||
|
||||
AuxCPOWData *data = AuxCPOWDataOf(proxy);
|
||||
if (data->isDOMObject &&
|
||||
idVar.type() == JSIDVariant::TnsString &&
|
||||
idVar.get_nsString().EqualsLiteral("QueryInterface"))
|
||||
{
|
||||
// Handle QueryInterface on DOM Objects specially since we can assume
|
||||
// certain things about their implementation.
|
||||
RootedFunction qi(cx, JS_NewFunction(cx, CPOWDOMQI, 1, 0,
|
||||
"QueryInterface"));
|
||||
if (!qi)
|
||||
return false;
|
||||
|
||||
vp.set(ObjectValue(*JS_GetFunctionObject(qi)));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSVariant val;
|
||||
ReturnStatus status;
|
||||
if (!SendGet(objId, receiverVar, idVar, &status, &val))
|
||||
|
@ -967,6 +1046,7 @@ MakeRemoteObject(JSContext *cx, ObjectId id, HandleObject obj)
|
|||
return RemoteObject(id.serialize(),
|
||||
JS::IsCallable(obj),
|
||||
JS::IsConstructor(obj),
|
||||
dom::IsDOMObject(obj),
|
||||
objectTag);
|
||||
}
|
||||
|
||||
|
@ -1051,6 +1131,7 @@ WrapperOwner::fromRemoteObjectVariant(JSContext *cx, RemoteObject objVar)
|
|||
AuxCPOWData *aux = new AuxCPOWData(objId,
|
||||
objVar.isCallable(),
|
||||
objVar.isConstructor(),
|
||||
objVar.isDOMObject(),
|
||||
objVar.objectTag());
|
||||
|
||||
SetProxyExtra(obj, 0, PrivateValue(this));
|
||||
|
|
|
@ -63,6 +63,7 @@ class WrapperOwner : public virtual JavaScriptShared
|
|||
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
|
||||
|
||||
bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
|
||||
bool DOMQI(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
|
||||
|
||||
/*
|
||||
* Check that |obj| is a DOM wrapper whose prototype chain contains
|
||||
|
|
|
@ -214,6 +214,9 @@ $(LIBRARY_NAME).pc: js.pc
|
|||
install:: $(LIBRARY_NAME).pc
|
||||
$(SYSINSTALL) $^ $(DESTDIR)$(libdir)/pkgconfig
|
||||
|
||||
install:: js-config.h
|
||||
$(SYSINSTALL) $^ $(DESTDIR)$(includedir)
|
||||
|
||||
######################################################
|
||||
# BEGIN SpiderMonkey header installation
|
||||
#
|
||||
|
|
|
@ -889,7 +889,6 @@ class GCRuntime
|
|||
void markGrayReferencesInCurrentGroup(gcstats::Phase phase);
|
||||
void markAllWeakReferences(gcstats::Phase phase);
|
||||
void markAllGrayReferences(gcstats::Phase phase);
|
||||
void markJitcodeGlobalTable();
|
||||
|
||||
void beginSweepPhase(bool lastGC);
|
||||
void findZoneGroups();
|
||||
|
|
|
@ -337,7 +337,6 @@ static const PhaseInfo phases[] = {
|
|||
{ PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK },
|
||||
{ PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK },
|
||||
{ PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK },
|
||||
{ PHASE_SWEEP_MARK_JITCODE_GLOBAL_TABLE, "Mark JitcodeGlobalTable", PHASE_SWEEP_MARK },
|
||||
{ PHASE_FINALIZE_START, "Finalize Start Callback", PHASE_SWEEP },
|
||||
{ PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP },
|
||||
{ PHASE_SWEEP_SYMBOL_REGISTRY, "Sweep Symbol Registry", PHASE_SWEEP },
|
||||
|
|
|
@ -43,7 +43,6 @@ enum Phase {
|
|||
PHASE_SWEEP_MARK_INCOMING_GRAY,
|
||||
PHASE_SWEEP_MARK_GRAY,
|
||||
PHASE_SWEEP_MARK_GRAY_WEAK,
|
||||
PHASE_SWEEP_MARK_JITCODE_GLOBAL_TABLE,
|
||||
PHASE_FINALIZE_START,
|
||||
PHASE_SWEEP_ATOMS,
|
||||
PHASE_SWEEP_SYMBOL_REGISTRY,
|
||||
|
|
|
@ -177,325 +177,78 @@ function loadModule_int32(stdlib, foreign, heap) {
|
|||
cas2_i: do_cas2_i };
|
||||
}
|
||||
|
||||
function loadModule_int8(stdlib, foreign, heap) {
|
||||
"use asm";
|
||||
|
||||
var atomic_load = stdlib.Atomics.load;
|
||||
var atomic_store = stdlib.Atomics.store;
|
||||
var atomic_cmpxchg = stdlib.Atomics.compareExchange;
|
||||
var atomic_add = stdlib.Atomics.add;
|
||||
var atomic_sub = stdlib.Atomics.sub;
|
||||
var atomic_and = stdlib.Atomics.and;
|
||||
var atomic_or = stdlib.Atomics.or;
|
||||
var atomic_xor = stdlib.Atomics.xor;
|
||||
|
||||
var i8a = new stdlib.SharedInt8Array(heap);
|
||||
|
||||
// Load element 0
|
||||
function do_load() {
|
||||
var v = 0;
|
||||
v = atomic_load(i8a, 0);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Load element i
|
||||
function do_load_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_load(i8a, i);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Store 37 in element 0
|
||||
function do_store() {
|
||||
var v = 0;
|
||||
v = atomic_store(i8a, 0, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Store 37 in element i
|
||||
function do_store_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_store(i8a, i, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Add 37 to element 10
|
||||
function do_add() {
|
||||
var v = 0;
|
||||
v = atomic_add(i8a, 10, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Add 37 to element i
|
||||
function do_add_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_add(i8a, i, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Subtract 108 from element 20
|
||||
function do_sub() {
|
||||
var v = 0;
|
||||
v = atomic_sub(i8a, 20, 108);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Subtract 108 from element i
|
||||
function do_sub_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_sub(i8a, i, 108);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// AND 0x33 into element 30
|
||||
function do_and() {
|
||||
var v = 0;
|
||||
v = atomic_and(i8a, 30, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// AND 0x33 into element i
|
||||
function do_and_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_and(i8a, i, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// OR 0x33 into element 40
|
||||
function do_or() {
|
||||
var v = 0;
|
||||
v = atomic_or(i8a, 40, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// OR 0x33 into element i
|
||||
function do_or_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_or(i8a, i, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// XOR 0x33 into element 50
|
||||
function do_xor() {
|
||||
var v = 0;
|
||||
v = atomic_xor(i8a, 50, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// XOR 0x33 into element i
|
||||
function do_xor_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_xor(i8a, i, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element 100: 0 -> -1
|
||||
function do_cas1() {
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, 100, 0, -1);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element 100: -1 -> 0x5A
|
||||
function do_cas2() {
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, 100, -1, 0x5A);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element i: 0 -> -1
|
||||
function do_cas1_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, i, 0, -1);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element i: -1 -> 0x5A
|
||||
function do_cas2_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, i, -1, 0x5A);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
return { load: do_load,
|
||||
load_i: do_load_i,
|
||||
store: do_store,
|
||||
store_i: do_store_i,
|
||||
add: do_add,
|
||||
add_i: do_add_i,
|
||||
sub: do_sub,
|
||||
sub_i: do_sub_i,
|
||||
and: do_and,
|
||||
and_i: do_and_i,
|
||||
or: do_or,
|
||||
or_i: do_or_i,
|
||||
xor: do_xor,
|
||||
xor_i: do_xor_i,
|
||||
cas1: do_cas1,
|
||||
cas2: do_cas2,
|
||||
cas1_i: do_cas1_i,
|
||||
cas2_i: do_cas2_i };
|
||||
}
|
||||
|
||||
// TODO: byte arrays
|
||||
// TODO: halfword arrays
|
||||
// TODO: signed vs unsigned; negative results
|
||||
|
||||
var heap = new SharedArrayBuffer(65536);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// int32 tests
|
||||
|
||||
var i32a = new SharedInt32Array(heap);
|
||||
var i32m = loadModule_int32(this, {}, heap);
|
||||
var module = loadModule_int32(this, {}, heap);
|
||||
|
||||
var size = 4;
|
||||
|
||||
i32m.fence();
|
||||
module.fence();
|
||||
|
||||
i32a[0] = 12345;
|
||||
assertEq(i32m.load(), 12345);
|
||||
assertEq(i32m.load_i(size*0), 12345);
|
||||
assertEq(module.load(), 12345);
|
||||
assertEq(module.load_i(size*0), 12345);
|
||||
|
||||
assertEq(i32m.store(), 37);
|
||||
assertEq(module.store(), 37);
|
||||
assertEq(i32a[0], 37);
|
||||
assertEq(i32m.store_i(size*0), 37);
|
||||
assertEq(module.store_i(size*0), 37);
|
||||
|
||||
i32a[10] = 18;
|
||||
assertEq(i32m.add(), 18);
|
||||
assertEq(module.add(), 18);
|
||||
assertEq(i32a[10], 18+37);
|
||||
assertEq(i32m.add_i(size*10), 18+37);
|
||||
assertEq(module.add_i(size*10), 18+37);
|
||||
assertEq(i32a[10], 18+37+37);
|
||||
|
||||
i32a[20] = 4972;
|
||||
assertEq(i32m.sub(), 4972);
|
||||
assertEq(module.sub(), 4972);
|
||||
assertEq(i32a[20], 4972 - 148);
|
||||
assertEq(i32m.sub_i(size*20), 4972 - 148);
|
||||
assertEq(module.sub_i(size*20), 4972 - 148);
|
||||
assertEq(i32a[20], 4972 - 148 - 148);
|
||||
|
||||
i32a[30] = 0x66666666;
|
||||
assertEq(i32m.and(), 0x66666666);
|
||||
assertEq(module.and(), 0x66666666);
|
||||
assertEq(i32a[30], 0x22222222);
|
||||
i32a[30] = 0x66666666;
|
||||
assertEq(i32m.and_i(size*30), 0x66666666);
|
||||
assertEq(module.and_i(size*30), 0x66666666);
|
||||
assertEq(i32a[30], 0x22222222);
|
||||
|
||||
i32a[40] = 0x22222222;
|
||||
assertEq(i32m.or(), 0x22222222);
|
||||
assertEq(module.or(), 0x22222222);
|
||||
assertEq(i32a[40], 0x33333333);
|
||||
i32a[40] = 0x22222222;
|
||||
assertEq(i32m.or_i(size*40), 0x22222222);
|
||||
assertEq(module.or_i(size*40), 0x22222222);
|
||||
assertEq(i32a[40], 0x33333333);
|
||||
|
||||
i32a[50] = 0x22222222;
|
||||
assertEq(i32m.xor(), 0x22222222);
|
||||
assertEq(module.xor(), 0x22222222);
|
||||
assertEq(i32a[50], 0x11111111);
|
||||
i32a[50] = 0x22222222;
|
||||
assertEq(i32m.xor_i(size*50), 0x22222222);
|
||||
assertEq(module.xor_i(size*50), 0x22222222);
|
||||
assertEq(i32a[50], 0x11111111);
|
||||
|
||||
i32a[100] = 0;
|
||||
assertEq(i32m.cas1(), 0);
|
||||
assertEq(i32m.cas2(), -1);
|
||||
assertEq(module.cas1(), 0);
|
||||
assertEq(module.cas2(), -1);
|
||||
assertEq(i32a[100], 0x5A5A5A5A);
|
||||
|
||||
i32a[100] = 0;
|
||||
assertEq(i32m.cas1_i(size*100), 0);
|
||||
assertEq(i32m.cas2_i(size*100), -1);
|
||||
assertEq(module.cas1_i(size*100), 0);
|
||||
assertEq(module.cas2_i(size*100), -1);
|
||||
assertEq(i32a[100], 0x5A5A5A5A);
|
||||
|
||||
// Out-of-bounds accesses.
|
||||
|
||||
assertEq(i32m.cas1_i(size*20000), 0);
|
||||
assertEq(i32m.cas2_i(size*20000), 0);
|
||||
assertEq(module.cas1_i(size*20000), 0);
|
||||
assertEq(module.cas2_i(size*20000), 0);
|
||||
|
||||
assertEq(i32m.or_i(size*20001), 0);
|
||||
assertEq(i32m.xor_i(size*20001), 0);
|
||||
assertEq(i32m.and_i(size*20001), 0);
|
||||
assertEq(i32m.add_i(size*20001), 0);
|
||||
assertEq(i32m.sub_i(size*20001), 0);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// int8 tests
|
||||
|
||||
var i8a = new SharedInt8Array(heap);
|
||||
var i8m = loadModule_int8(this, {}, heap);
|
||||
|
||||
for ( var i=0 ; i < i8a.length ; i++ )
|
||||
i8a[i] = 0;
|
||||
|
||||
var size = 1;
|
||||
|
||||
i8a[0] = 123;
|
||||
assertEq(i8m.load(), 123);
|
||||
assertEq(i8m.load_i(0), 123);
|
||||
|
||||
assertEq(i8m.store(), 37);
|
||||
assertEq(i8a[0], 37);
|
||||
assertEq(i8m.store_i(0), 37);
|
||||
|
||||
i8a[10] = 18;
|
||||
assertEq(i8m.add(), 18);
|
||||
assertEq(i8a[10], 18+37);
|
||||
assertEq(i8m.add_i(10), 18+37);
|
||||
assertEq(i8a[10], 18+37+37);
|
||||
|
||||
i8a[20] = 49;
|
||||
assertEq(i8m.sub(), 49);
|
||||
assertEq(i8a[20], 49 - 108);
|
||||
assertEq(i8m.sub_i(20), 49 - 108);
|
||||
assertEq(i8a[20], ((49 - 108 - 108) << 24) >> 24); // Byte, sign extended
|
||||
|
||||
i8a[30] = 0x66;
|
||||
assertEq(i8m.and(), 0x66);
|
||||
assertEq(i8a[30], 0x22);
|
||||
i8a[30] = 0x66;
|
||||
assertEq(i8m.and_i(30), 0x66);
|
||||
assertEq(i8a[30], 0x22);
|
||||
|
||||
i8a[40] = 0x22;
|
||||
assertEq(i8m.or(), 0x22);
|
||||
assertEq(i8a[40], 0x33);
|
||||
i8a[40] = 0x22;
|
||||
assertEq(i8m.or_i(40), 0x22);
|
||||
assertEq(i8a[40], 0x33);
|
||||
|
||||
i8a[50] = 0x22;
|
||||
assertEq(i8m.xor(), 0x22);
|
||||
assertEq(i8a[50], 0x11);
|
||||
i8a[50] = 0x22;
|
||||
assertEq(i8m.xor_i(50), 0x22);
|
||||
assertEq(i8a[50], 0x11);
|
||||
|
||||
i8a[100] = 0;
|
||||
assertEq(i8m.cas1(), 0);
|
||||
assertEq(i8m.cas2(), -1);
|
||||
assertEq(i8a[100], 0x5A);
|
||||
|
||||
i8a[100] = 0;
|
||||
assertEq(i8m.cas1_i(100), 0);
|
||||
assertEq(i8m.cas2_i(100), -1);
|
||||
assertEq(i8a[100], 0x5A);
|
||||
|
||||
// Out-of-bounds accesses.
|
||||
|
||||
assertEq(i8m.cas1_i(80000), 0);
|
||||
assertEq(i8m.cas2_i(80000), 0);
|
||||
|
||||
assertEq(i8m.or_i(80001), 0);
|
||||
assertEq(i8m.xor_i(80001), 0);
|
||||
assertEq(i8m.and_i(80001), 0);
|
||||
assertEq(i8m.add_i(80001), 0);
|
||||
assertEq(i8m.sub_i(80001), 0);
|
||||
assertEq(module.or_i(size*20001), 0);
|
||||
assertEq(module.xor_i(size*20001), 0);
|
||||
assertEq(module.and_i(size*20001), 0);
|
||||
assertEq(module.add_i(size*20001), 0);
|
||||
assertEq(module.sub_i(size*20001), 0);
|
||||
|
||||
print("Done");
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// |jit-test| allow-oom
|
||||
enableSPSProfiling();
|
||||
loadFile('\
|
||||
for (var i = 0; i < 2; i++) {\
|
||||
obj = { m: function () {} };\
|
||||
obj.watch("m", function () { float32 = 0 + obj.foo; });\
|
||||
obj.m = 0;\
|
||||
}\
|
||||
');
|
||||
gcparam("maxBytes", gcparam("gcBytes") + (1)*1024);
|
||||
newGlobal("same-compartment");
|
||||
function loadFile(lfVarx) {
|
||||
evaluate(lfVarx, { noScriptRval : true, compileAndGo : true });
|
||||
}
|
|
@ -500,14 +500,15 @@ JitRuntime::Mark(JSTracer *trc)
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
JitRuntime::MarkJitcodeGlobalTable(JSTracer *trc)
|
||||
/* static */ bool
|
||||
JitRuntime::MarkJitcodeGlobalTableIteratively(JSTracer *trc)
|
||||
{
|
||||
if (trc->runtime()->hasJitRuntime() &&
|
||||
trc->runtime()->jitRuntime()->hasJitcodeGlobalTable())
|
||||
{
|
||||
trc->runtime()->jitRuntime()->getJitcodeGlobalTable()->mark(trc);
|
||||
return trc->runtime()->jitRuntime()->getJitcodeGlobalTable()->markIteratively(trc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
|
|
@ -257,7 +257,7 @@ class JitRuntime
|
|||
void freeOsrTempData();
|
||||
|
||||
static void Mark(JSTracer *trc);
|
||||
static void MarkJitcodeGlobalTable(JSTracer *trc);
|
||||
static bool MarkJitcodeGlobalTableIteratively(JSTracer *trc);
|
||||
static void SweepJitcodeGlobalTable(JSRuntime *rt);
|
||||
|
||||
ExecutableAllocator &execAlloc() {
|
||||
|
|
|
@ -718,8 +718,8 @@ JitcodeGlobalTable::verifySkiplist()
|
|||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
JitcodeGlobalTable::mark(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalTable::markIteratively(JSTracer *trc)
|
||||
{
|
||||
// JitcodeGlobalTable must keep entries that are in the sampler buffer
|
||||
// alive. This conditionality is akin to holding the entries weakly.
|
||||
|
@ -731,19 +731,17 @@ JitcodeGlobalTable::mark(JSTracer *trc)
|
|||
// itself.
|
||||
//
|
||||
// Instead, JitcodeGlobalTable is marked at the beginning of the sweep
|
||||
// phase. The key assumption is the following. At the beginning of the
|
||||
// sweep phase, any JS frames that the sampler may put in its buffer that
|
||||
// are not already there at the beginning of the mark phase must have
|
||||
// already been marked, as either 1) the frame was on-stack at the
|
||||
// beginning of the sweep phase, or 2) the frame was pushed between
|
||||
// incremental sweep slices. Frames of case 1) are already marked. Frames
|
||||
// of case 2) must have been reachable to have been newly pushed, and thus
|
||||
// are already marked.
|
||||
// phase, along with weak references. The key assumption is the
|
||||
// following. At the beginning of the sweep phase, any JS frames that the
|
||||
// sampler may put in its buffer that are not already there at the
|
||||
// beginning of the mark phase must have already been marked, as either 1)
|
||||
// the frame was on-stack at the beginning of the sweep phase, or 2) the
|
||||
// frame was pushed between incremental sweep slices. Frames of case 1)
|
||||
// are already marked. Frames of case 2) must have been reachable to have
|
||||
// been newly pushed, and thus are already marked.
|
||||
//
|
||||
// The approach above obviates the need for read barriers. The assumption
|
||||
// above is checked in JitcodeGlobalTable::lookupForSampler.
|
||||
MOZ_ASSERT(trc->runtime()->gc.stats.currentPhase() ==
|
||||
gcstats::PHASE_SWEEP_MARK_JITCODE_GLOBAL_TABLE);
|
||||
|
||||
AutoSuppressProfilerSampling suppressSampling(trc->runtime());
|
||||
uint32_t gen = trc->runtime()->profilerSampleBufferGen();
|
||||
|
@ -752,7 +750,7 @@ JitcodeGlobalTable::mark(JSTracer *trc)
|
|||
if (!trc->runtime()->spsProfiler.enabled())
|
||||
gen = UINT32_MAX;
|
||||
|
||||
// Find start entry.
|
||||
bool markedAny = false;
|
||||
for (Range r(*this); !r.empty(); r.popFront()) {
|
||||
JitcodeGlobalEntry *entry = r.front();
|
||||
|
||||
|
@ -774,8 +772,10 @@ JitcodeGlobalTable::mark(JSTracer *trc)
|
|||
if (!entry->zone()->isCollecting() || entry->zone()->isGCFinished())
|
||||
continue;
|
||||
|
||||
entry->mark(trc);
|
||||
markedAny |= entry->markIfUnmarked(trc);
|
||||
}
|
||||
|
||||
return markedAny;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -795,15 +795,21 @@ JitcodeGlobalTable::sweep(JSRuntime *rt)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
JitcodeGlobalEntry::BaseEntry::markJitcode(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalEntry::BaseEntry::markJitcodeIfUnmarked(JSTracer *trc)
|
||||
{
|
||||
MarkJitCodeUnbarriered(trc, &jitcode_, "jitcodglobaltable-baseentry-jitcode");
|
||||
if (!isJitcodeMarkedFromAnyThread()) {
|
||||
MarkJitCodeUnbarriered(trc, &jitcode_, "jitcodglobaltable-baseentry-jitcode");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
JitcodeGlobalEntry::BaseEntry::isJitcodeMarkedFromAnyThread()
|
||||
{
|
||||
if (jitcode_->asTenured().arenaHeader()->allocatedDuringIncremental)
|
||||
return false;
|
||||
return IsJitCodeMarkedFromAnyThread(&jitcode_);
|
||||
}
|
||||
|
||||
|
@ -813,10 +819,14 @@ JitcodeGlobalEntry::BaseEntry::isJitcodeAboutToBeFinalized()
|
|||
return IsJitCodeAboutToBeFinalized(&jitcode_);
|
||||
}
|
||||
|
||||
void
|
||||
JitcodeGlobalEntry::BaselineEntry::mark(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalEntry::BaselineEntry::markIfUnmarked(JSTracer *trc)
|
||||
{
|
||||
MarkScriptUnbarriered(trc, &script_, "jitcodeglobaltable-baselineentry-script");
|
||||
if (!isMarkedFromAnyThread()) {
|
||||
MarkScriptUnbarriered(trc, &script_, "jitcodeglobaltable-baselineentry-script");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -831,29 +841,41 @@ JitcodeGlobalEntry::BaselineEntry::isMarkedFromAnyThread()
|
|||
return IsScriptMarkedFromAnyThread(&script_);
|
||||
}
|
||||
|
||||
void
|
||||
JitcodeGlobalEntry::IonEntry::mark(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalEntry::IonEntry::markIfUnmarked(JSTracer *trc)
|
||||
{
|
||||
bool markedAny = false;
|
||||
|
||||
for (unsigned i = 0; i < numScripts(); i++) {
|
||||
MarkScriptUnbarriered(trc, &sizedScriptList()->pairs[i].script,
|
||||
"jitcodeglobaltable-ionentry-script");
|
||||
if (!IsScriptMarkedFromAnyThread(&sizedScriptList()->pairs[i].script)) {
|
||||
MarkScriptUnbarriered(trc, &sizedScriptList()->pairs[i].script,
|
||||
"jitcodeglobaltable-ionentry-script");
|
||||
markedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!optsAllTypes_)
|
||||
return;
|
||||
return markedAny;
|
||||
|
||||
for (IonTrackedTypeWithAddendum *iter = optsAllTypes_->begin();
|
||||
iter != optsAllTypes_->end(); iter++)
|
||||
{
|
||||
TypeSet::MarkTypeUnbarriered(trc, &(iter->type), "jitcodeglobaltable-ionentry-type");
|
||||
if (iter->hasAllocationSite()) {
|
||||
if (!TypeSet::IsTypeMarkedFromAnyThread(&iter->type)) {
|
||||
TypeSet::MarkTypeUnbarriered(trc, &iter->type, "jitcodeglobaltable-ionentry-type");
|
||||
markedAny = true;
|
||||
}
|
||||
if (iter->hasAllocationSite() && !IsScriptMarkedFromAnyThread(&iter->script)) {
|
||||
MarkScriptUnbarriered(trc, &iter->script,
|
||||
"jitcodeglobaltable-ionentry-type-addendum-script");
|
||||
} else if (iter->hasConstructor()) {
|
||||
markedAny = true;
|
||||
} else if (iter->hasConstructor() && !IsObjectMarkedFromAnyThread(&iter->constructor)) {
|
||||
MarkObjectUnbarriered(trc, &iter->constructor,
|
||||
"jitcodeglobaltable-ionentry-type-addendum-constructor");
|
||||
markedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
return markedAny;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче