Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-03-11 13:10:46 +01:00
Родитель e41370dd2f 8a066b437a
Коммит 7e5877b7aa
212 изменённых файлов: 4873 добавлений и 5128 удалений

Просмотреть файл

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше