Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2013-06-12 12:23:19 -04:00
commit 217b7ca184
62 changed files with 1736 additions and 161 deletions

View File

@ -143,8 +143,17 @@ pref("app.update.auto", true);
// 2 download no prompt prompt
//
// See chart in nsUpdateService.js source for more details
// incompatibilities are ignored by updates in Metro
//
pref("app.update.mode", 1);
pref("app.update.mode", 0);
#ifdef XP_WIN
#ifdef MOZ_METRO
// Enables update checking in the Metro environment.
// add-on incompatibilities are ignored by updates in Metro.
pref("app.update.metro.enabled", true);
#endif
#endif
// If set to true, the Update Service will present no UI for any event.
pref("app.update.silent", false);
@ -1067,7 +1076,7 @@ pref("devtools.debugger.remote-host", "localhost");
pref("devtools.debugger.remote-autoconnect", false);
pref("devtools.debugger.remote-connection-retries", 3);
pref("devtools.debugger.remote-timeout", 20000);
pref("devtools.debugger.source-maps-enabled", false);
pref("devtools.debugger.source-maps-enabled", true);
// The default Debugger UI settings
pref("devtools.debugger.ui.win-x", 0);

View File

@ -1266,10 +1266,6 @@ var gBrowserInit = {
Cu.reportError("Could not end startup crash tracking: " + ex);
}
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
setTimeout(function () { BrowserChromeTest.markAsReady(); }, 0);
TelemetryTimestamps.add("delayedStartupFinished");
#ifdef XP_WIN
#ifdef MOZ_METRO
gMetroPrefs.prefDomain.forEach(function(prefName) {
@ -1278,6 +1274,10 @@ var gBrowserInit = {
}, this);
#endif
#endif
Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
setTimeout(function () { BrowserChromeTest.markAsReady(); }, 0);
TelemetryTimestamps.add("delayedStartupFinished");
},
onUnload: function() {
@ -4858,7 +4858,8 @@ function fireSidebarFocusedEvent() {
*/
var gMetroPrefs = {
prefDomain: ["app.update.auto", "app.update.enabled",
"app.update.service.enabled"],
"app.update.service.enabled",
"app.update.metro.enabled"],
observe: function (aSubject, aTopic, aPrefName)
{
if (aTopic != "nsPref:changed")

View File

@ -37,6 +37,21 @@ var gAdvancedPane = {
// in case the default changes. On other Windows OS's defaults can also
// be set while the prefs are open.
window.setInterval(this.updateSetDefaultBrowser, 1000);
#ifdef MOZ_METRO
// Pre Windows 8, we should hide the update related settings
// for the Metro browser
let version = Components.classes["@mozilla.org/system-info;1"].
getService(Components.interfaces.nsIPropertyBag2).
getProperty("version");
let preWin8 = parseFloat(version) < 6.2;
this._showingWin8Prefs = !preWin8;
if (preWin8) {
["autoMetro", "autoMetroIndent"].forEach(
function(id) document.getElementById(id).collapsed = true
);
}
#endif
#endif
#endif
@ -567,12 +582,24 @@ var gAdvancedPane = {
{
var enabledPref = document.getElementById("app.update.enabled");
var autoPref = document.getElementById("app.update.auto");
#ifdef XP_WIN
#ifdef MOZ_METRO
var metroEnabledPref = document.getElementById("app.update.metro.enabled");
#endif
#endif
var radiogroup = document.getElementById("updateRadioGroup");
if (!enabledPref.value) // Don't care for autoPref.value in this case.
radiogroup.value="manual" // 3. Never check for updates.
radiogroup.value="manual"; // 3. Never check for updates.
#ifdef XP_WIN
#ifdef MOZ_METRO
// enabledPref.value && autoPref.value && metroEnabledPref.value
else if (metroEnabledPref.value && this._showingWin8Prefs)
radiogroup.value="autoMetro"; // 0. Automatically install updates for both Metro and Desktop
#endif
#endif
else if (autoPref.value) // enabledPref.value && autoPref.value
radiogroup.value="auto"; // 1. Automatically install updates
radiogroup.value="auto"; // 1. Automatically install updates for Desktop only
else // enabledPref.value && !autoPref.value
radiogroup.value="checkOnly"; // 2. Check, but let me choose
@ -589,6 +616,13 @@ var gAdvancedPane = {
// the warnIncompatible checkbox value is set by readAddonWarn
warnIncompatible.disabled = radiogroup.disabled || modePref.locked ||
!enabledPref.value || !autoPref.value;
#ifdef XP_WIN
#ifdef MOZ_METRO
if (this._showingWin8Prefs) {
warnIncompatible.disabled |= metroEnabledPref.value;
}
#endif
#endif
#ifdef MOZ_MAINTENANCE_SERVICE
// Check to see if the maintenance service is installed.
@ -636,12 +670,30 @@ var gAdvancedPane = {
{
var enabledPref = document.getElementById("app.update.enabled");
var autoPref = document.getElementById("app.update.auto");
#ifdef XP_WIN
#ifdef MOZ_METRO
var metroEnabledPref = document.getElementById("app.update.metro.enabled");
// Initialize the pref to false only if we're showing the option
if (this._showingWin8Prefs) {
metroEnabledPref.value = false;
}
#endif
#endif
var radiogroup = document.getElementById("updateRadioGroup");
switch (radiogroup.value) {
case "auto": // 1. Automatically install updates
case "auto": // 1. Automatically install updates for Desktop only
enabledPref.value = true;
autoPref.value = true;
break;
#ifdef XP_WIN
#ifdef MOZ_METRO
case "autoMetro": // 0. Automatically install updates for both Metro and Desktop
enabledPref.value = true;
autoPref.value = true;
metroEnabledPref.value = true;
break;
#endif
#endif
case "checkOnly": // 2. Check, but let me choose
enabledPref.value = true;
autoPref.value = false;
@ -656,6 +708,14 @@ var gAdvancedPane = {
warnIncompatible.disabled = enabledPref.locked || !enabledPref.value ||
autoPref.locked || !autoPref.value ||
modePref.locked;
#ifdef XP_WIN
#ifdef MOZ_METRO
if (this._showingWin8Prefs) {
warnIncompatible.disabled |= metroEnabledPref.value;
}
#endif
#endif
},
/**

View File

@ -75,6 +75,11 @@
#ifdef MOZ_UPDATER
<preference id="app.update.enabled" name="app.update.enabled" type="bool"/>
<preference id="app.update.auto" name="app.update.auto" type="bool"/>
#ifdef XP_WIN
#ifdef MOZ_METRO
<preference id="app.update.metro.enabled" name="app.update.metro.enabled" type="bool"/>
#endif
#endif
<preference id="app.update.mode" name="app.update.mode" type="int"/>
<preference id="app.update.disable_button.showUpdateHistory"
@ -340,6 +345,18 @@
<caption label="&updateApp.label;"/>
<radiogroup id="updateRadioGroup"
oncommand="gAdvancedPane.updateWritePrefs();">
#ifdef XP_WIN
#ifdef MOZ_METRO
<radio id="autoMetro"
value="autoMetro"
label="&updateAutoMetro.label;"
accesskey="&updateAutoMetro.accesskey;"/>
<hbox id="autoMetroIndent"
class="indent">
<label value="&updateAutoMetroWarn.label;"/>
</hbox>
#endif
#endif
<radio value="auto"
label="&updateAuto.label;"
accesskey="&updateAuto.accesskey;"/>

View File

@ -29,6 +29,21 @@ var gAdvancedPane = {
// in case the default changes. On other Windows OS's defaults can also
// be set while the prefs are open.
window.setInterval(this.updateSetDefaultBrowser, 1000);
#ifdef MOZ_METRO
// Pre Windows 8, we should hide the update related settings
// for the Metro browser
let version = Components.classes["@mozilla.org/system-info;1"].
getService(Components.interfaces.nsIPropertyBag2).
getProperty("version");
let preWin8 = parseFloat(version) < 6.2;
this._showingWin8Prefs = !preWin8;
if (preWin8) {
["autoMetro", "autoMetroIndent"].forEach(
function(id) document.getElementById(id).collapsed = true
);
}
#endif
#endif
#endif
#ifdef MOZ_UPDATER
@ -550,10 +565,22 @@ var gAdvancedPane = {
{
var enabledPref = document.getElementById("app.update.enabled");
var autoPref = document.getElementById("app.update.auto");
#ifdef XP_WIN
#ifdef MOZ_METRO
var metroEnabledPref = document.getElementById("app.update.metro.enabled");
#endif
#endif
var radiogroup = document.getElementById("updateRadioGroup");
if (!enabledPref.value) // Don't care for autoPref.value in this case.
radiogroup.value="manual" // 3. Never check for updates.
radiogroup.value="manual"; // 3. Never check for updates.
#ifdef XP_WIN
#ifdef MOZ_METRO
// enabledPref.value && autoPref.value && metroEnabledPref.value
else if (metroEnabledPref.value && this._showingWin8Prefs)
radiogroup.value="autoMetro"; // 0. Automatically install updates
#endif
#endif
else if (autoPref.value) // enabledPref.value && autoPref.value
radiogroup.value="auto"; // 1. Automatically install updates
else // enabledPref.value && !autoPref.value
@ -572,6 +599,13 @@ var gAdvancedPane = {
// the warnIncompatible checkbox value is set by readAddonWarn
warnIncompatible.disabled = radiogroup.disabled || modePref.locked ||
!enabledPref.value || !autoPref.value;
#ifdef XP_WIN
#ifdef MOZ_METRO
if (this._showingWin8Prefs) {
warnIncompatible.disabled |= metroEnabledPref.value;
}
#endif
#endif
#ifdef MOZ_MAINTENANCE_SERVICE
// Check to see if the maintenance service is installed.
@ -601,12 +635,30 @@ var gAdvancedPane = {
{
var enabledPref = document.getElementById("app.update.enabled");
var autoPref = document.getElementById("app.update.auto");
#ifdef XP_WIN
#ifdef MOZ_METRO
var metroEnabledPref = document.getElementById("app.update.metro.enabled");
// Initialize the pref to false only if we're showing the option
if (this._showingWin8Prefs) {
metroEnabledPref.value = false;
}
#endif
#endif
var radiogroup = document.getElementById("updateRadioGroup");
switch (radiogroup.value) {
case "auto": // 1. Automatically install updates
case "auto": // 1. Automatically install updates for Desktop only
enabledPref.value = true;
autoPref.value = true;
break;
#ifdef XP_WIN
#ifdef MOZ_METRO
case "autoMetro": // 0. Automatically install updates for both Metro and Desktop
enabledPref.value = true;
autoPref.value = true;
metroEnabledPref.value = true;
break;
#endif
#endif
case "checkOnly": // 2. Check, but let me choose
enabledPref.value = true;
autoPref.value = false;
@ -621,6 +673,13 @@ var gAdvancedPane = {
warnIncompatible.disabled = enabledPref.locked || !enabledPref.value ||
autoPref.locked || !autoPref.value ||
modePref.locked;
#ifdef XP_WIN
#ifdef MOZ_METRO
if (this._showingWin8Prefs) {
warnIncompatible.disabled |= metroEnabledPref.value;
}
#endif
#endif
},
/**

View File

@ -83,6 +83,13 @@
<preference id="app.update.auto"
name="app.update.auto"
type="bool"/>
#ifdef XP_WIN
#ifdef MOZ_METRO
<preference id="app.update.metro.enabled"
name="app.update.metro.enabled"
type="bool"/>
#endif
#endif
<preference id="app.update.mode"
name="app.update.mode"
type="int"/>
@ -352,6 +359,18 @@
<caption label="&updateApp.label;"/>
<radiogroup id="updateRadioGroup"
oncommand="gAdvancedPane.updateWritePrefs();">
#ifdef XP_WIN
#ifdef MOZ_METRO
<radio id="autoMetro"
value="autoMetro"
label="&updateAutoMetro.label;"
accesskey="&updateAutoMetro.accesskey;"/>
<hbox id="autoMetroIndent"
class="indent">
<label value="&updateAutoMetroWarn.label;"/>
</hbox>
#endif
#endif
<radio value="auto"
label="&updateAuto.label;"
accesskey="&updateAuto.accesskey;"/>

View File

@ -33,12 +33,12 @@ function test() {
output: [
/Manifest has a character encoding of ISO-8859-1\. Manifests must have the utf-8 character encoding\./,
/The first line of the manifest must be "CACHE MANIFEST" at line 1\./,
/"CACHE MANIFEST" is only valid on the first line at line 3\./,
/"CACHE MANIFEST" is only valid on the first line but was found at line 3\./,
/images\/sound-icon\.png points to a resource that is not available at line 9\./,
/images\/background\.png points to a resource that is not available at line 10\./,
/NETWORK section line 13 \(\/checking\.cgi\) prevents caching of line 13 \(\/checking\.cgi\) in the NETWORK section\./,
/\/checking\.cgi points to a resource that is not available at line 13\./,
/Asterisk used as a wildcard in the NETWORK section at line 14\. A single line containing an asterisk is called the online whitelist wildcard flag and is only valid in the NETWORK section\. Other uses of the \* character are prohibited\. The presence of this flag indicates that any URI not listed as cached is to be implicitly treated as being in the online whitelist namespaces\. If the flag is not present then the blocking state indicates that URIs not listed explicitly in the manifest are to be treated as unavailable\./,
/Asterisk \(\*\) incorrectly used in the NETWORK section at line 14\. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section\. Otherwice such URIs will be treated as unavailable\. Other uses of the \* character are prohibited/,
/\.\.\/rel\.html points to a resource that is not available at line 17\./,
/\.\.\/\.\.\/rel\.html points to a resource that is not available at line 18\./,
/\.\.\/\.\.\/\.\.\/rel\.html points to a resource that is not available at line 19\./,
@ -64,14 +64,14 @@ function test() {
/http:\/\/example\.com\/check\.png points to a resource that is not available at line 41\./,
/Spaces in URIs need to be replaced with % at line 42\./,
/http:\/\/example\.com\/cr oss\.png points to a resource that is not available at line 42\./,
/Asterisk used as a wildcard in the CACHE section at line 43\. A single line containing an asterisk is called the online whitelist wildcard flag and is only valid in the NETWORK section\. Other uses of the \* character are prohibited\. The presence of this flag indicates that any URI not listed as cached is to be implicitly treated as being in the online whitelist namespaces\. If the flag is not present then the blocking state indicates that URIs not listed explicitly in the manifest are to be treated as unavailable\./,
/Asterisk \(\*\) incorrectly used in the CACHE section at line 43\. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section\. Otherwice such URIs will be treated as unavailable\. Other uses of the \* character are prohibited/,
/The SETTINGS section may only contain a single value, "prefer-online" or "fast" at line 47\./,
/FALLBACK section line 50 \(\/section1\/ \/offline1\.html\) prevents caching of line 30 \(\/section1\/blockedbyfallback\.html\) in the CACHE section\./,
/\/offline1\.html points to a resource that is not available at line 50\./,
/FALLBACK section line 51 \(\/section2\/ offline2\.html\) prevents caching of line 32 \(\/section2\/blockedbyfallback\.html\) in the CACHE section\./,
/offline2\.html points to a resource that is not available at line 51\./,
/Only two URIs separated by spaces are allowed in the FALLBACK section at line 52\./,
/Asterisk \(\*\) incorrectly used as a wildcard in a fallback namespace at line 53\. Namespaces simply need to match a path prefix\./,
/Asterisk \(\*\) incorrectly used in the FALLBACK section at line 53\. URIs in the FALLBACK section simply need to match a prefix of the request URI\./,
/offline3\.html points to a resource that is not available at line 53\./,
/Invalid section name \(BLAH\) at line 55\./,
/Only two URIs separated by spaces are allowed in the FALLBACK section at line 55\./

View File

@ -428,6 +428,7 @@ StackFrames.prototype = {
currentBreakpointLocation: null,
currentEvaluation: null,
currentException: null,
currentReturnedValue: null,
/**
* Connect to the current thread client.
@ -485,6 +486,17 @@ StackFrames.prototype = {
case "exception":
this.currentException = aPacket.why.exception;
break;
// If paused while stepping out of a frame, store the returned value or
// thrown exception.
case "resumeLimit":
if (!aPacket.why.frameFinished) {
break;
} else if (aPacket.why.frameFinished.throw) {
this.currentException = aPacket.why.frameFinished.throw;
} else if (aPacket.why.frameFinished.return) {
this.currentReturnedValue = aPacket.why.frameFinished.return;
}
break;
}
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
@ -595,6 +607,7 @@ StackFrames.prototype = {
this.currentBreakpointLocation = null;
this.currentEvaluation = null;
this.currentException = null;
this.currentReturnedValue = null;
// After each frame step (in, over, out), framescleared is fired, which
// forces the UI to be emptied and rebuilt on framesadded. Most of the times
// this is not necessary, and will result in a brief redraw flicker.
@ -832,6 +845,11 @@ StackFrames.prototype = {
let excRef = aScope.addVar("<exception>", { value: this.currentException });
this._addVarExpander(excRef, this.currentException);
}
// Add any returned value.
if (this.currentReturnedValue) {
let retRef = aScope.addVar("<return>", { value: this.currentReturnedValue });
this._addVarExpander(retRef, this.currentReturnedValue);
}
// Add "this".
if (aFrame.this) {
let thisRef = aScope.addVar("this", { value: aFrame.this });

View File

@ -102,6 +102,7 @@ MOCHITEST_BROWSER_TESTS = \
browser_dbg_chrome-debugging.js \
browser_dbg_source_maps-01.js \
browser_dbg_source_maps-02.js \
browser_dbg_step-out.js \
head.js \
$(NULL)
@ -139,6 +140,7 @@ MOCHITEST_BROWSER_PAGES = \
binary_search.map \
test-location-changes-bp.js \
test-location-changes-bp.html \
test-step-out.html \
$(NULL)
ifneq (Linux,$(OS_ARCH))

View File

@ -0,0 +1,133 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that stepping out of a function displays the right return value.
*/
const TAB_URL = EXAMPLE_URL + "test-step-out.html";
var gPane = null;
var gTab = null;
var gDebugger = null;
function test()
{
debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) {
gTab = aTab;
gPane = aPane;
gDebugger = gPane.panelWin;
expectUncaughtException();
testNormalReturn();
});
}
function testNormalReturn()
{
gPane.panelWin.gClient.addOneTimeListener("paused", function() {
gDebugger.addEventListener("Debugger:SourceShown", function dbgstmt(aEvent) {
gDebugger.removeEventListener(aEvent.type, dbgstmt);
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should be paused now.");
let count = 0;
gPane.panelWin.gClient.addOneTimeListener("paused", function() {
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should be paused again.");
gDebugger.addEventListener("Debugger:FetchedVariables", function stepout() {
ok(true, "Debugger:FetchedVariables event received.");
gDebugger.removeEventListener("Debugger:FetchedVariables", stepout, false);
Services.tm.currentThread.dispatch({ run: function() {
var scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.firstChild,
innerNodes = innerScope.querySelector(".variables-view-element-details").childNodes;
is(innerNodes[0].querySelector(".name").getAttribute("value"), "<return>",
"Should have the right property name for the return value.");
is(innerNodes[0].querySelector(".value").getAttribute("value"), 10,
"Should have the right property value for the return value.");
testReturnWithException();
}}, 0);
}, false);
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("step-out"),
gDebugger);
});
});
EventUtils.sendMouseEvent({ type: "click" },
content.document.getElementById("return"),
content.window);
}
function testReturnWithException()
{
gDebugger.DebuggerController.activeThread.resume(function() {
gPane.panelWin.gClient.addOneTimeListener("paused", function() {
gDebugger.addEventListener("Debugger:FetchedVariables", function dbgstmt(aEvent) {
gDebugger.removeEventListener(aEvent.type, dbgstmt, false);
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should be paused now.");
let count = 0;
gPane.panelWin.gClient.addOneTimeListener("paused", function() {
is(gDebugger.DebuggerController.activeThread.state, "paused",
"Should be paused again.");
gDebugger.addEventListener("Debugger:FetchedVariables", function stepout() {
ok(true, "Debugger:FetchedVariables event received.");
gDebugger.removeEventListener("Debugger:FetchedVariables", stepout, false);
Services.tm.currentThread.dispatch({ run: function() {
var scopes = gDebugger.DebuggerView.Variables._list,
innerScope = scopes.firstChild,
innerNodes = innerScope.querySelector(".variables-view-element-details").childNodes;
is(innerNodes[0].querySelector(".name").getAttribute("value"), "<exception>",
"Should have the right property name for the exception value.");
is(innerNodes[0].querySelector(".value").getAttribute("value"), '"boom"',
"Should have the right property value for the exception value.");
resumeAndFinish();
}}, 0);
}, false);
});
EventUtils.sendMouseEvent({ type: "mousedown" },
gDebugger.document.getElementById("step-out"),
gDebugger);
}, false);
});
EventUtils.sendMouseEvent({ type: "click" },
content.document.getElementById("throw"),
content.window);
});
}
function resumeAndFinish() {
gPane.panelWin.gClient.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: closeDebuggerAndFinish }, 0);
});
gDebugger.DebuggerController.activeThread.resume();
}
registerCleanupFunction(function() {
removeTab(gTab);
gPane = null;
gTab = null;
gDebugger = null;
});

View File

@ -0,0 +1,32 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset='utf-8'/>
<title>Debugger Step Out Return Value Test</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<button id="return">return</button>
<button id="throw">throw</button>
</body>
<script type="text/javascript">
window.addEventListener("load", function() {
function normal(aArg) {
debugger;
var r = 10;
return r;
}
function error(aArg) {
debugger;
var r = 10;
throw "boom";
return r;
}
var button = document.getElementById("return");
button.addEventListener("click", normal, false);
button = document.getElementById("throw");
button.addEventListener("click", error, false);
});
</script>
</html>

View File

@ -122,17 +122,19 @@ InspectorPanel.prototype = {
// All the components are initialized. Let's select a node.
if (this.target.isLocalTab) {
let root = this.browser.contentDocument.documentElement;
this._selection.setNode(root);
this._selection.setNode(
this._getDefaultNodeForSelection(this.browser.contentDocument));
} else if (this.target.window) {
let root = this.target.window.document.documentElement;
this._selection.setNode(root);
this._selection.setNode(
this._getDefaultNodeForSelection(this.target.window.document));
}
if (this.highlighter) {
this.highlighter.unlock();
}
this.markup.expandNode(this.selection.node);
this.emit("ready");
deferred.resolve(this);
}.bind(this));
@ -143,6 +145,16 @@ InspectorPanel.prototype = {
return deferred.promise;
},
/**
* Select node for default selection
*/
_getDefaultNodeForSelection : function(document) {
// if available set body node as default selected node
// else set documentElement
var defaultNode = document.body || document.documentElement;
return defaultNode;
},
/**
* Selection object (read only)
*/
@ -253,21 +265,26 @@ InspectorPanel.prototype = {
this.selection.setNode(null);
this._destroyMarkup();
this.isDirty = false;
let self = this;
function onDOMReady() {
let onDOMReady = function() {
newWindow.removeEventListener("DOMContentLoaded", onDOMReady, true);
if (self._destroyed) {
if (this._destroyed) {
return;
}
if (!self.selection.node) {
self.selection.setNode(newWindow.document.documentElement, "navigateaway");
if (!this.selection.node) {
let defaultNode = this._getDefaultNodeForSelection(newWindow.document);
this.selection.setNode(defaultNode, "navigateaway");
}
self._initMarkup();
self.setupSearchBox();
}
this._initMarkup();
this.once("markuploaded", () => {
this.markup.expandNode(this.selection.node);
});
this.setupSearchBox();
}.bind(this);
if (newWindow.document.readyState == "loading") {
newWindow.addEventListener("DOMContentLoaded", onDOMReady, true);

View File

@ -35,28 +35,16 @@ function test()
inspector = aInspector;
executeSoon(function() {
inspector.selection.once("new-node", highlightBodyNode);
inspector.selection.once("new-node", highlightHeaderNode);
// Test that navigating around without a selected node gets us to the
// body element.
node = doc.querySelector("body");
// head element.
node = doc.querySelector("h1");
let bc = inspector.breadcrumbs;
bc.nodeHierarchy[bc.currentIndex].button.focus();
EventUtils.synthesizeKey("VK_RIGHT", { });
});
}
function highlightBodyNode()
{
is(inspector.selection.node, node, "selected body element");
executeSoon(function() {
inspector.selection.once("new-node", highlightHeaderNode);
// Test that moving to the child works.
node = doc.querySelector("h1");
EventUtils.synthesizeKey("VK_RIGHT", { });
});
}
function highlightHeaderNode()
{
is(inspector.selection.node, node, "selected h1 element");

View File

@ -255,14 +255,7 @@ function test() {
var target = TargetFactory.forTab(gBrowser.selectedTab);
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
inspector = toolbox.getCurrentPanel();
runTests();
});
}
function runTests() {
inspector.selection.once("new-node", startTests);
executeSoon(function() {
inspector.selection.setNode(doc.body);
startTests();
});
}

View File

@ -10,10 +10,10 @@ function test() {
let doc;
let keySequences = [
["right", "html"],
["pageup", "*doctype*"],
["down", "html"],
["down", "head"],
["down", "body"],
["right", "body"],
["down", "node0"],
["right", "node0"],
["down", "node1"],

View File

@ -1315,6 +1315,7 @@ NetworkDetailsView.prototype = {
$("#request-params-box").setAttribute("flex", "1");
$("#request-params-box").hidden = false;
$("#request-post-data-textarea-box").hidden = true;
$("#response-content-info-header").hidden = true;
$("#response-content-json-box").hidden = true;
$("#response-content-textarea-box").hidden = true;
$("#response-content-image-box").hidden = true;
@ -1529,20 +1530,23 @@ NetworkDetailsView.prototype = {
*
* @param object aHeadersResponse
* The "requestHeaders" message received from the server.
* @param object aPostResponse
* @param object aPostDataResponse
* The "requestPostData" message received from the server.
*/
_setRequestPostParams: function(aHeadersResponse, aPostResponse) {
if (!aHeadersResponse || !aPostResponse) {
_setRequestPostParams: function(aHeadersResponse, aPostDataResponse) {
if (!aHeadersResponse || !aPostDataResponse) {
return;
}
let contentType = aHeadersResponse.headers.filter(({ name }) => name == "Content-Type")[0];
let text = aPostResponse.postData.text;
gNetwork.getString(text).then((aString) => {
gNetwork.getString(aPostDataResponse.postData.text).then((aString) => {
// Handle query strings (poor man's forms, e.g. "?foo=bar&baz=42").
if (contentType.value.contains("x-www-form-urlencoded")) {
this._addParams(this._paramsFormData, aString);
let cType = aHeadersResponse.headers.filter(({ name }) => name == "Content-Type")[0];
let cString = cType ? cType.value : "";
if (cString.contains("x-www-form-urlencoded") ||
aString.contains("x-www-form-urlencoded")) {
let formDataGroups = aString.split(/\r\n|\n|\r/);
for (let group of formDataGroups) {
this._addParams(this._paramsFormData, group);
}
}
// Handle actual forms ("multipart/form-data" content type).
else {
@ -1572,6 +1576,10 @@ NetworkDetailsView.prototype = {
* A query string of params (e.g. "?foo=bar&baz=42").
*/
_addParams: function(aName, aParams) {
// Make sure there's at least one param available.
if (!aParams || !aParams.contains("=")) {
return;
}
// Turn the params string into an array containing { name: value } tuples.
let paramsArray = aParams.replace(/^[?&]/, "").split("&").map((e) =>
let (param = e.split("=")) {
@ -1605,18 +1613,42 @@ NetworkDetailsView.prototype = {
gNetwork.getString(text).then((aString) => {
// Handle json.
if (mimeType.contains("/json")) {
$("#response-content-json-box").hidden = false;
let jsonpRegex = /^[a-zA-Z0-9_$]+\(|\)$/g; // JSONP with callback.
let sanitizedJSON = aString.replace(jsonpRegex, "");
let callbackPadding = aString.match(jsonpRegex);
let jsonScopeName = callbackPadding
? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1))
: L10N.getStr("jsonScopeName");
// Make sure this is an valid JSON object first. If so, nicely display
// the parsing results in a variables view. Otherwise, simply show
// the contents as plain text.
try {
var jsonObject = JSON.parse(sanitizedJSON);
} catch (e) {
var parsingError = e;
}
let jsonScope = this._json.addScope(jsonScopeName);
jsonScope.addVar().populate(JSON.parse(sanitizedJSON), { expanded: true });
jsonScope.expanded = true;
// Valid JSON.
if (jsonObject) {
$("#response-content-json-box").hidden = false;
let jsonScopeName = callbackPadding
? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1))
: L10N.getStr("jsonScopeName");
let jsonScope = this._json.addScope(jsonScopeName);
jsonScope.addVar().populate(jsonObject, { expanded: true });
jsonScope.expanded = true;
}
// Malformed JSON.
else {
$("#response-content-textarea-box").hidden = false;
NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
aEditor.setMode(SourceEditor.MODES.JAVASCRIPT);
aEditor.setText(aString);
});
let infoHeader = $("#response-content-info-header");
infoHeader.setAttribute("value", parsingError);
infoHeader.setAttribute("tooltiptext", parsingError);
infoHeader.hidden = false;
}
}
// Handle images.
else if (mimeType.contains("image/")) {

View File

@ -272,6 +272,7 @@
<tabpanel id="response-tabpanel"
class="tabpanel-content">
<vbox flex="1">
<label id="response-content-info-header"/>
<vbox id="response-content-json-box" flex="1" hidden="true">
<vbox id="response-content-json" flex="1"/>
</vbox>

View File

@ -27,9 +27,11 @@ MOCHITEST_BROWSER_TESTS = \
browser_net_cyrillic-02.js \
browser_net_large-response.js \
browser_net_status-codes.js \
browser_net_post-data.js \
browser_net_post-data-01.js \
browser_net_post-data-02.js \
browser_net_jsonp.js \
browser_net_json-long.js \
browser_net_json-malformed.js \
browser_net_timeline_ticks.js \
browser_net_sort-01.js \
browser_net_sort-02.js \
@ -51,8 +53,10 @@ MOCHITEST_BROWSER_PAGES = \
html_cyrillic-test-page.html \
html_status-codes-test-page.html \
html_post-data-test-page.html \
html_post-raw-test-page.html \
html_jsonp-test-page.html \
html_json-long-test-page.html \
html_json-malformed-test-page.html \
html_sorting-test-page.html \
html_filter-test-page.html \
html_infinite-get-page.html \

View File

@ -109,14 +109,15 @@ function test() {
"The response tab in the network details pane should be selected.");
function checkVisibility(aBox) {
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), aBox != "json",
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), aBox != "textarea",
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), aBox != "image",
"The response content image box doesn't have the intended visibility.");

View File

@ -46,14 +46,15 @@ function test() {
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), false,
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), true,
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box doesn't have the intended visibility.");

View File

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if malformed JSON responses are handled correctly.
*/
function test() {
initNetMonitor(JSON_MALFORMED_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, SourceEditor, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
waitForNetworkEvents(aMonitor, 1).then(() => {
verifyRequestItemTarget(RequestsMenu.getItemAtIndex(0),
"GET", CONTENT_TYPE_SJS + "?fmt=json-malformed", {
status: 200,
statusText: "OK",
type: "json",
fullMimeType: "text/json; charset=utf-8"
});
EventUtils.sendMouseEvent({ type: "mousedown" },
document.getElementById("details-pane-toggle"));
EventUtils.sendMouseEvent({ type: "mousedown" },
document.querySelectorAll("#details-pane tab")[3]);
let tab = document.querySelectorAll("#details-pane tab")[3];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3];
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), false,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-info-header")
.getAttribute("value"),
"SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
"The response info header doesn't have the intended value attribute.");
is(tabpanel.querySelector("#response-content-info-header")
.getAttribute("tooltiptext"),
"SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data",
"The response info header doesn't have the intended tooltiptext attribute.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), true,
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), false,
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box doesn't have the intended visibility.");
NetMonitorView.editor("#response-content-textarea").then((aEditor) => {
is(aEditor.getText(), "{ \"greeting\": \"Hello malformed JSON!\" },",
"The text shown in the source editor is incorrect.");
is(aEditor.getMode(), SourceEditor.MODES.JAVASCRIPT,
"The mode active in the source editor is incorrect.");
teardown(aMonitor).then(finish);
});
});
aDebuggee.performRequests();
});
}

View File

@ -40,14 +40,15 @@ function test() {
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), false,
"The response content json box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), true,
"The response content textarea box doesn't have the intended visibility.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box doesn't have the intended visibility.");

View File

@ -61,7 +61,6 @@ function test() {
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), !aBox.contains("params"),
"The request params box doesn't have the indended visibility.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), !aBox.contains("textarea"),
"The request post data textarea box doesn't have the indended visibility.");
@ -100,11 +99,11 @@ function test() {
checkVisibility("params");
is(tabpanel.querySelectorAll(".variables-view-variable").length, 5,
"There should be 6 param values displayed in this tabpanel.");
"There should be 5 param values displayed in this tabpanel.");
is(queryScope.querySelectorAll(".variables-view-variable").length, 3,
"There should be 3 param values displayed in the query scope.");
is(postScope.querySelectorAll(".variables-view-variable").length, 2,
"There should be 3 param values displayed in the post scope.");
"There should be 2 param values displayed in the post scope.");
is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
"foo", "The first post param name was incorrect.");

View File

@ -0,0 +1,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the POST requests display the correct information in the UI,
* even for raw payloads without attached content-type headers.
*/
function test() {
initNetMonitor(POST_RAW_URL).then(([aTab, aDebuggee, aMonitor]) => {
info("Starting test... ");
let { document, L10N, NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu, NetworkDetails } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
NetworkDetails._params.lazyEmpty = false;
waitForNetworkEvents(aMonitor, 0, 1).then(() => {
NetMonitorView.toggleDetailsPane({ visible: true }, 2)
RequestsMenu.selectedIndex = 0;
let tab = document.querySelectorAll("#details-pane tab")[2];
let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2];
is(tab.getAttribute("selected"), "true",
"The params tab in the network details pane should be selected.");
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box doesn't have the indended visibility.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box doesn't have the indended visibility.");
is(tabpanel.querySelectorAll(".variables-view-scope").length, 1,
"There should be 1 param scopes displayed in this tabpanel.");
is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0,
"The empty notice should not be displayed in this tabpanel.");
let postScope = tabpanel.querySelectorAll(".variables-view-scope")[0];
is(postScope.querySelector(".name").getAttribute("value"),
L10N.getStr("paramsFormData"),
"The post scope doesn't have the correct title.");
is(postScope.querySelectorAll(".variables-view-variable").length, 2,
"There should be 2 param values displayed in the post scope.");
is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"),
"foo", "The first query param name was incorrect.");
is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"),
"\"bar\"", "The first query param value was incorrect.");
is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"),
"baz", "The second query param name was incorrect.");
is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"),
"\"123\"", "The second query param value was incorrect.");
teardown(aMonitor).then(finish);
});
aDebuggee.performRequest();
});
}

View File

@ -163,7 +163,6 @@ function test() {
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box should not be hidden.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box should be hidden.");
@ -179,14 +178,15 @@ function test() {
is(tab.getAttribute("selected"), "true",
"The response tab in the network details pane should be selected.");
is(tabpanel.querySelector("#response-content-info-header")
.hasAttribute("hidden"), true,
"The response info header should be hidden.");
is(tabpanel.querySelector("#response-content-json-box")
.hasAttribute("hidden"), true,
"The response content json box should be hidden.");
is(tabpanel.querySelector("#response-content-textarea-box")
.hasAttribute("hidden"), false,
"The response content textarea box should not be hidden.");
is(tabpanel.querySelector("#response-content-image-box")
.hasAttribute("hidden"), true,
"The response content image box should be hidden.");

View File

@ -144,7 +144,6 @@ function test() {
is(tabpanel.querySelector("#request-params-box")
.hasAttribute("hidden"), false,
"The request params box should not be hidden.");
is(tabpanel.querySelector("#request-post-data-textarea-box")
.hasAttribute("hidden"), true,
"The request post data textarea box should be hidden.");

View File

@ -19,8 +19,10 @@ const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html";
const CYRILLIC_URL = EXAMPLE_URL + "html_cyrillic-test-page.html";
const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
const JSON_LONG_URL = EXAMPLE_URL + "html_json-long-test-page.html";
const JSON_MALFORMED_URL = EXAMPLE_URL + "html_json-malformed-test-page.html";
const SORTING_URL = EXAMPLE_URL + "html_sorting-test-page.html";
const FILTERING_URL = EXAMPLE_URL + "html_filter-test-page.html";
const INFINITE_GET_URL = EXAMPLE_URL + "html_infinite-get-page.html";

View File

@ -0,0 +1,33 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>JSON malformed test</p>
<script type="text/javascript">
function get(aAddress, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(null);
}
function performRequests() {
get("sjs_content-type-test-server.sjs?fmt=json-malformed", function() {
// Done.
});
}
</script>
</body>
</html>

View File

@ -0,0 +1,34 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Network Monitor test page</title>
</head>
<body>
<p>POST raw test</p>
<script type="text/javascript">
function post(aAddress, aMessage, aCallback) {
var xhr = new XMLHttpRequest();
xhr.open("POST", aAddress, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
aCallback();
}
};
xhr.send(aMessage);
}
function performRequest() {
var rawData = "Content-Type: application/x-www-form-urlencoded\r\n\r\nfoo=bar&baz=123";
post("sjs_simple-test-server.sjs", rawData, function() {
// Done.
});
}
</script>
</body>
</html>

View File

@ -78,6 +78,13 @@ function handleRequest(request, response) {
response.finish();
break;
}
case "json-malformed": {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "text/json; charset=utf-8", false);
response.write("{ \"greeting\": \"Hello malformed JSON!\" },");
response.finish();
break;
}
case "font": {
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "font/woff", false);

View File

@ -408,7 +408,7 @@ ManifestParser.prototype = {
if (text == "CACHE MANIFEST") {
if (this.currentLine != 1) {
this._addError(this.currentLine, "cacheManifestOnlyFirstLine",
this._addError(this.currentLine, "cacheManifestOnlyFirstLine2",
this.currentLine);
}
continue;
@ -445,7 +445,7 @@ ManifestParser.prototype = {
if (text.indexOf("*") != -1) {
if (this.currSection != "NETWORK" || text.length != 1) {
this._addError(this.currentLine, "asteriskInWrongSection",
this._addError(this.currentLine, "asteriskInWrongSection2",
this.currSection, this.currentLine);
return;
}
@ -501,7 +501,7 @@ ManifestParser.prototype = {
let [ namespace, fallback ] = split;
if (namespace.indexOf("*") != -1) {
this._addError(this.currentLine, "fallbackAsterisk", this.currentLine);
this._addError(this.currentLine, "fallbackAsterisk2", this.currentLine);
}
if (/\s/.test(namespace)) {

View File

@ -2256,6 +2256,7 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
_onInit: function(aImmediateFlag) {
if (this._initialDescriptor.enumerable ||
this._nameString == "this" ||
this._nameString == "<return>" ||
this._nameString == "<exception>") {
this.ownerView._lazyAppend(aImmediateFlag, true, this._target);
this.ownerView._enumItems.push(this);
@ -2433,6 +2434,9 @@ ViewHelpers.create({ constructor: Variable, proto: Scope.prototype }, {
else if (name == "<exception>") {
this._target.setAttribute("exception", "");
}
else if (name == "<return>") {
this._target.setAttribute("return", "");
}
else if (name == "__proto__") {
this._target.setAttribute("proto", "");
}

View File

@ -18,10 +18,8 @@ function openRuleView()
// Highlight a node.
let node = content.document.getElementsByTagName("h1")[0];
inspector.selection.once("new-node", testFocus);
inspector.sidebar.once("ruleview-ready",
() => inspector.selection.setNode(doc.body));
inspector.sidebar.once("ruleview-ready", testFocus);
});
}

View File

@ -70,15 +70,15 @@ cacheDisabled=Your disk cache is disabled. Please set browser.cache.disk.enable
# the line number.
firstLineMustBeCacheManifest=The first line of the manifest must be "CACHE MANIFEST" at line %S.
# LOCALIZATION NOTE (cacheManifestOnlyFirstLine): the associated cache
# LOCALIZATION NOTE (cacheManifestOnlyFirstLine2): the associated cache
# manifest has "CACHE MANIFEST" on a line other than the first line.
# Parameters: %S is the line number where "CACHE MANIFEST" appears.
cacheManifestOnlyFirstLine="CACHE MANIFEST" is only valid on the first line at line %S.
cacheManifestOnlyFirstLine2="CACHE MANIFEST" is only valid on the first line but was found at line %S.
# LOCALIZATION NOTE (asteriskInWrongSection): the associated cache manifest
# LOCALIZATION NOTE (asteriskInWrongSection2): the associated cache manifest
# has an asterisk (*) in a section other than the NETWORK section. Parameters:
# %1$S is the section name, %2$S is the line number.
asteriskInWrongSection=Asterisk used as a wildcard in the %1$S section at line %2$S. A single line containing an asterisk is called the online whitelist wildcard flag and is only valid in the NETWORK section. Other uses of the * character are prohibited. The presence of this flag indicates that any URI not listed as cached is to be implicitly treated as being in the online whitelist namespaces. If the flag is not present then the blocking state indicates that URIs not listed explicitly in the manifest are to be treated as unavailable.
asteriskInWrongSection2=Asterisk (*) incorrectly used in the %1$S section at line %2$S. If a line in the NETWORK section contains only a single asterisk character, then any URI not listed in the manifest will be treated as if the URI was listed in the NETWORK section. Otherwice such URIs will be treated as unavailable. Other uses of the * character are prohibited.
# LOCALIZATION NOTE (escapeSpaces): the associated cache manifest has a space
# in a URI. Spaces must be replaced with %20. Parameters: %S is the line
@ -102,11 +102,11 @@ tooManyDotDotSlashes=Too many dot dot slash operators (../) at line %S.
# error occurs.
fallbackUseSpaces=Only two URIs separated by spaces are allowed in the FALLBACK section at line %S.
# LOCALIZATION NOTE (fallbackAsterisk): the associated cache manifest has a
# LOCALIZATION NOTE (fallbackAsterisk2): the associated cache manifest has a
# FALLBACK section that attempts to use an asterisk (*) as a wildcard. In this
# section the URI is simply a path prefix. Parameters: %S is the line number
# where this error occurs.
fallbackAsterisk=Asterisk (*) incorrectly used as a wildcard in a fallback namespace at line %S. Namespaces simply need to match a path prefix.
fallbackAsterisk2=Asterisk (*) incorrectly used in the FALLBACK section at line %S. URIs in the FALLBACK section simply need to match a prefix of the request URI.
# LOCALIZATION NOTE (settingsBadValue): the associated cache manifest has a
# SETTINGS section containing something other than the valid "prefer-online"

View File

@ -84,8 +84,10 @@
<!ENTITY updateTab.label "Update">
<!ENTITY updateApp.label "&brandShortName; updates:">
<!ENTITY updateAuto.label "Automatically install updates (recommended: improved security)">
<!ENTITY updateAuto.label "Automatically install updates from desktop &brandShortName;">
<!ENTITY updateAuto.accesskey "A">
<!ENTITY updateAutoMetro.label "Automatically update from desktop and Windows 8 style &brandShortName;">
<!ENTITY updateAutoMetro.accesskey "s">
<!ENTITY updateCheck.label "Check for updates, but let me choose whether to install them">
<!ENTITY updateCheck.accesskey "C">
<!ENTITY updateManual.label "Never check for updates (not recommended: security risk)">
@ -94,6 +96,8 @@
<!ENTITY updateAutoAddonWarn.label "Warn me if this will disable any of my add-ons">
<!ENTITY updateAutoAddonWarn.accesskey "W">
<!ENTITY updateAutoMetroWarn.label "(Windows 8 style &brandShortName; does not check add-on compatibility)">
<!ENTITY updateHistory.label "Show Update History">
<!ENTITY updateHistory.accesskey "p">

View File

@ -2,6 +2,9 @@
# 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/.
// Services = object with smart getters for common XPCOM services
Components.utils.import("resource://gre/modules/Services.jsm");
var gAppUpdater;
var AboutPanelUI = {
get _aboutVersionLabel() {
@ -162,11 +165,21 @@ appUpdater.prototype =
// true when updating is enabled.
get updateEnabled() {
let updatesEnabled = true;
try {
return Services.prefs.getBoolPref("app.update.enabled");
updatesEnabled = Services.prefs.getBoolPref("app.update.metro.enabled");
}
catch (e) { }
return true; // Firefox default is true
if (!updatesEnabled) {
return false;
}
try {
updatesEnabled = Services.prefs.getBoolPref("app.update.enabled")
}
catch (e) { }
return updatesEnabled;
},
// true when updating in background is enabled.
@ -224,6 +237,19 @@ appUpdater.prototype =
if (cancelQuit.data)
return;
// It's not possible for the Metro browser to restart itself.
// The Windows background process ensures only one instance exists.
// So start the update while the browser is open and close the browser
// right after.
try {
Components.classes["@mozilla.org/updates/update-processor;1"].
createInstance(Components.interfaces.nsIUpdateProcessor).
processUpdate(null);
} catch (e) {
// If there was an error just close down and the next startup
// will do this.
}
let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
getService(Components.interfaces.nsIAppStartup);
@ -233,8 +259,7 @@ appUpdater.prototype =
return;
}
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
Components.interfaces.nsIAppStartup.eRestart);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit);
return;
}

View File

@ -416,6 +416,10 @@ pref("app.update.auto", true);
// See chart in nsUpdateService.js source for more details
pref("app.update.mode", 0);
// Enables update checking in the Metro environment.
// add-on incompatibilities are ignored by updates in Metro.
pref("app.update.metro.enabled", true);
// If set to true, the Update Service will present no UI for any event.
pref("app.update.silent", true);

View File

@ -381,6 +381,17 @@ box.requests-menu-status[code^="5"] {
/* Response tabpanel */
#response-content-info-header {
background:
url(background-noise-toolbar.png),
linear-gradient(hsl(0,61%,40%), hsl(0,61%,31%)) repeat-x top left;
box-shadow:
inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
margin: 0;
padding: 5px 8px;
}
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;

View File

@ -494,7 +494,7 @@
/* Non enumerable, configurable and writable variables and properties */
.variable-or-property[proto] > .title > .name,
.variable-or-property[non-enumerable]:not([self]):not([exception]) > .title > .name {
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]) > .title > .name {
opacity: 0.5;
}
@ -531,6 +531,11 @@
text-shadow: 0 0 8px #fcc;
}
.variable-or-property[return]:not(:focus) > .title > .name {
color: #0a0;
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
content: "N";
display: inline-block;

View File

@ -381,6 +381,17 @@ box.requests-menu-status[code^="5"] {
/* Response tabpanel */
#response-content-info-header {
background:
url(background-noise-toolbar.png),
linear-gradient(hsl(0,61%,40%), hsl(0,61%,31%)) repeat-x top left;
box-shadow:
inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
margin: 0;
padding: 5px 8px;
}
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;

View File

@ -494,7 +494,7 @@
/* Non enumerable, configurable and writable variables and properties */
.variable-or-property[proto] > .title > .name,
.variable-or-property[non-enumerable]:not([self]):not([exception]) > .title > .name {
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]) > .title > .name {
opacity: 0.5;
}
@ -531,6 +531,11 @@
text-shadow: 0 0 8px #fcc;
}
.variable-or-property[return]:not(:focus) > .title > .name {
color: #0a0;
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
content: "N";
display: inline-block;

View File

@ -381,6 +381,17 @@ box.requests-menu-status[code^="5"] {
/* Response tabpanel */
#response-content-info-header {
background:
url(background-noise-toolbar.png),
linear-gradient(hsl(0,61%,40%), hsl(0,61%,31%)) repeat-x top left;
box-shadow:
inset 0 1px 0 hsla(210,40%,83%,.15),
inset 0 -1px 0 hsla(210,40%,83%,.05);
margin: 0;
padding: 5px 8px;
}
#response-content-image-box {
padding-top: 10px;
padding-bottom: 10px;

View File

@ -497,7 +497,7 @@
/* Non enumerable, configurable and writable variables and properties */
.variable-or-property[proto] > .title > .name,
.variable-or-property[non-enumerable]:not([self]):not([exception]) > .title > .name {
.variable-or-property[non-enumerable]:not([self]):not([exception]):not([return]) > .title > .name {
opacity: 0.5;
}
@ -534,6 +534,11 @@
text-shadow: 0 0 8px #fcc;
}
.variable-or-property[return]:not(:focus) > .title > .name {
color: #0a0;
text-shadow: 0 0 8px #cfc;
}
.variable-or-property[non-extensible]:not([non-writable]) > .title:after {
content: "N";
display: inline-block;

View File

@ -2239,6 +2239,10 @@
"kind": "boolean",
"description": "Updater: Whether or not updates are enabled"
},
"UPDATER_UPDATES_METRO_ENABLED": {
"kind": "boolean",
"description": "Updater: Whether or not Metro updates are enabled"
},
"UPDATER_UPDATES_AUTOMATIC": {
"kind": "boolean",
"description": "Updater: Whether or not updates are automatic"
@ -3316,6 +3320,30 @@
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'detach' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_BLACKBOX_MS": {
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'blackbox' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_BLACKBOX_MS": {
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'blackbox' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_UNBLACKBOX_MS": {
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took an 'ublackbox' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_UNBLACKBOX_MS": {
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took an 'unblackbox' request to go round trip."
},
"DEVTOOLS_OPTIONS_OPENED_BOOLEAN": {
"kind": "boolean",
"description": "How many times has the devtool's Options panel been opened?"

View File

@ -1565,11 +1565,51 @@ LongStringClient.prototype = {
*/
function SourceClient(aClient, aForm) {
this._form = aForm;
this._isBlackBoxed = aForm.isBlackBoxed;
this._client = aClient;
}
SourceClient.prototype = {
get _transport() { return this._client._transport; },
get _transport() this._client._transport,
get isBlackBoxed() this._isBlackBoxed,
get actor() this._form.actor,
get request() this._client.request,
/**
* Black box this SourceClient's source.
*
* @param aCallback Function
* The callback function called when we receive the response from the server.
*/
blackBox: DebuggerClient.requester({
type: "blackbox"
}, {
telemetry: "BLACKBOX",
after: function (aResponse) {
if (!aResponse.error) {
this._isBlackBoxed = true;
}
return aResponse;
}
}),
/**
* Un-black box this SourceClient's source.
*
* @param aCallback Function
* The callback function called when we receive the response from the server.
*/
unblackBox: DebuggerClient.requester({
type: "unblackbox"
}, {
telemetry: "UNBLACKBOX",
after: function (aResponse) {
if (!aResponse.error) {
this._isBlackBoxed = false;
}
return aResponse;
}
}),
/**
* Get a long string grip for this SourceClient's source.

View File

@ -327,45 +327,71 @@ ThreadActor.prototype = {
if (aRequest && aRequest.resumeLimit) {
// Bind these methods because some of the hooks are called with 'this'
// set to the current frame.
let pauseAndRespond = this._pauseAndRespond.bind(this);
let pauseAndRespond = (aFrame, onPacket=function (k) k) => {
this._pauseAndRespond(aFrame, { type: "resumeLimit" }, onPacket);
};
let createValueGrip = this.createValueGrip.bind(this);
let startFrame = this._youngestFrame;
let startFrame = this.youngestFrame;
let startLine;
if (this._youngestFrame.script) {
let offset = this._youngestFrame.offset;
startLine = this._youngestFrame.script.getOffsetLine(offset);
if (this.youngestFrame.script) {
let offset = this.youngestFrame.offset;
startLine = this.youngestFrame.script.getOffsetLine(offset);
}
// Define the JS hook functions for stepping.
let onEnterFrame = function TA_onEnterFrame(aFrame) {
return pauseAndRespond(aFrame, { type: "resumeLimit" });
let onEnterFrame = aFrame => {
if (this.sources.isBlackBoxed(aFrame.script.url)) {
return undefined;
}
return pauseAndRespond(aFrame);
};
let thread = this;
let onPop = function TA_onPop(aCompletion) {
// onPop is called with 'this' set to the current frame.
if (thread.sources.isBlackBoxed(this.script.url)) {
return undefined;
}
// Note that we're popping this frame; we need to watch for
// subsequent step events on its caller.
this.reportedPop = true;
return pauseAndRespond(this, { type: "resumeLimit" });
}
return pauseAndRespond(this, (aPacket) => {
aPacket.why.frameFinished = {};
if (!aCompletion) {
aPacket.why.frameFinished.terminated = true;
} else if (aCompletion.hasOwnProperty("return")) {
aPacket.why.frameFinished.return = createValueGrip(aCompletion.return);
} else if (aCompletion.hasOwnProperty("yield")) {
aPacket.why.frameFinished.return = createValueGrip(aCompletion.yield);
} else {
aPacket.why.frameFinished.throw = createValueGrip(aCompletion.throw);
}
return aPacket;
});
};
let onStep = function TA_onStep() {
// onStep is called with 'this' set to the current frame.
if (thread.sources.isBlackBoxed(this.script.url)) {
return undefined;
}
// If we've changed frame or line, then report that.
if (this !== startFrame ||
(this.script &&
this.script.getOffsetLine(this.offset) != startLine)) {
return pauseAndRespond(this, { type: "resumeLimit" });
return pauseAndRespond(this);
}
// Otherwise, let execution continue.
return undefined;
}
};
let steppingType = aRequest.resumeLimit.type;
if (["step", "next", "finish"].indexOf(steppingType) == -1) {
@ -430,7 +456,7 @@ ThreadActor.prototype = {
// save our frame now to be restored after eval returns.
// XXX: or we could just start using dbg.getNewestFrame() now that it
// works as expected.
let youngest = this._youngestFrame;
let youngest = this.youngestFrame;
// Put ourselves back in the running state and inform the client.
let resumedPacket = this._resumed();
@ -459,7 +485,7 @@ ThreadActor.prototype = {
let count = aRequest.count;
// Find the starting frame...
let frame = this._youngestFrame;
let frame = this.youngestFrame;
let i = 0;
while (frame && (i < start)) {
frame = frame.older;
@ -811,7 +837,7 @@ ThreadActor.prototype = {
*/
_requestFrame: function TA_requestFrame(aFrameID) {
if (!aFrameID) {
return this._youngestFrame;
return this.youngestFrame;
}
if (this._framePool.has(aFrameID)) {
@ -845,7 +871,7 @@ ThreadActor.prototype = {
// Save the pause frame (if any) as the youngest frame for
// stack viewing.
this._youngestFrame = aFrame;
this.youngestFrame = aFrame;
// Create the actor pool that will hold the pause actor and its
// children.
@ -908,7 +934,7 @@ ThreadActor.prototype = {
this._pausePool = null;
this._pauseActor = null;
this._youngestFrame = null;
this.youngestFrame = null;
return { from: this.actorID, type: "resumed" };
},
@ -1185,7 +1211,7 @@ ThreadActor.prototype = {
* The exception that was thrown in the debugger code.
*/
uncaughtExceptionHook: function TA_uncaughtExceptionHook(aException) {
dumpn("Got an exception:" + aException);
dumpn("Got an exception: " + aException.message + "\n" + aException.stack);
},
/**
@ -1196,6 +1222,9 @@ ThreadActor.prototype = {
* The stack frame that contained the debugger statement.
*/
onDebuggerStatement: function TA_onDebuggerStatement(aFrame) {
if (this.sources.isBlackBoxed(aFrame.script.url)) {
return undefined;
}
return this._pauseAndRespond(aFrame, { type: "debuggerStatement" });
},
@ -1209,6 +1238,9 @@ ThreadActor.prototype = {
* The exception that was thrown.
*/
onExceptionUnwind: function TA_onExceptionUnwind(aFrame, aValue) {
if (this.sources.isBlackBoxed(aFrame.script.url)) {
return undefined;
}
try {
let packet = this._paused(aFrame);
if (!packet) {
@ -1456,7 +1488,8 @@ SourceActor.prototype = {
form: function SA_form() {
return {
actor: this.actorID,
url: this._url
url: this._url,
isBlackBoxed: this.threadActor.sources.isBlackBoxed(this.url)
// TODO bug 637572: introductionScript
};
},
@ -1508,11 +1541,39 @@ SourceActor.prototype = {
"message": "Could not load the source for " + this._url + "."
};
});
},
/**
* Handler for the "blackbox" packet.
*/
onBlackBox: function SA_onBlackBox(aRequest) {
this.threadActor.sources.blackBox(this.url);
let packet = {
from: this.actorID
};
if (this.threadActor.state == "paused"
&& this.threadActor.youngestFrame
&& this.threadActor.youngestFrame.script.url == this.url) {
packet.pausedInSource = true;
}
return packet;
},
/**
* Handler for the "unblackbox" packet.
*/
onUnblackBox: function SA_onUnblackBox(aRequest) {
this.threadActor.sources.unblackBox(this.url);
return {
from: this.actorID
};
}
};
SourceActor.prototype.requestTypes = {
"source": SourceActor.prototype.onSource
"source": SourceActor.prototype.onSource,
"blackbox": SourceActor.prototype.onBlackBox,
"unblackbox": SourceActor.prototype.onUnblackBox
};
@ -2059,6 +2120,7 @@ FrameActor.prototype = {
if (this.frame.script) {
form.where = { url: this.frame.script.url,
line: this.frame.script.getOffsetLine(this.frame.offset) };
form.isBlackBoxed = this.threadActor.sources.isBlackBoxed(this.frame.script.url)
}
if (!this.frame.older) {
@ -2157,6 +2219,10 @@ BreakpointActor.prototype = {
* The stack frame that contained the breakpoint.
*/
hit: function BA_hit(aFrame) {
if (this.threadActor.sources.isBlackBoxed(this.location.url)) {
return undefined;
}
// TODO: add the rest of the breakpoints on that line (bug 676602).
let reason = { type: "breakpoint", actors: [ this.actorID ] };
return this.threadActor._pauseAndRespond(aFrame, reason, (aPacket) => {
@ -2494,8 +2560,8 @@ update(ChromeDebuggerActor.prototype, {
* Manages the sources for a thread. Handles source maps, locations in the
* sources, etc for ThreadActors.
*/
function ThreadSources(aThreadActor, aUseSourceMaps,
aAllowPredicate, aOnNewSource) {
function ThreadSources(aThreadActor, aUseSourceMaps, aAllowPredicate,
aOnNewSource) {
this._thread = aThreadActor;
this._useSourceMaps = aUseSourceMaps;
this._allow = aAllowPredicate;
@ -2513,6 +2579,12 @@ function ThreadSources(aThreadActor, aUseSourceMaps,
this._generatedUrlsByOriginalUrl = Object.create(null);
}
/**
* Must be a class property because it needs to persist across reloads, same as
* the breakpoint store.
*/
ThreadSources._blackBoxedSources = new Set();
ThreadSources.prototype = {
/**
* Return the source actor representing |aURL|, creating one if none
@ -2687,6 +2759,39 @@ ThreadSources.prototype = {
});
},
/**
* Returns true if URL for the given source is black boxed.
*
* @param aURL String
* The URL of the source which we are checking whether it is black
* boxed or not.
*/
isBlackBoxed: function TS_isBlackBoxed(aURL) {
return ThreadSources._blackBoxedSources.has(aURL);
},
/**
* Add the given source URL to the set of sources that are black boxed. If the
* thread is currently paused and we are black boxing the yougest frame's
* source, this will force a step.
*
* @param aURL String
* The URL of the source which we are black boxing.
*/
blackBox: function TS_blackBox(aURL) {
ThreadSources._blackBoxedSources.add(aURL);
},
/**
* Remove the given source URL to the set of sources that are black boxed.
*
* @param aURL String
* The URL of the source which we are no longer black boxing.
*/
unblackBox: function TS_unblackBox(aURL) {
ThreadSources._blackBoxedSources.delete(aURL);
},
/**
* Normalize multiple relative paths towards the base paths on the right.
*/

View File

@ -23,8 +23,7 @@ function allAppShellDOMWindows(aWindowType)
}
/**
* Return true if the top-level window |aWindow| is a "navigator:browser"
* window.
* Retrieve the window type of the top-level window |aWindow|.
*/
function appShellDOMWindowType(aWindow) {
/* This is what nsIWindowMediator's enumerator checks. */
@ -378,17 +377,7 @@ BrowserTabList.prototype._listenToMediatorIf = function(aShouldListen) {
BrowserTabList.prototype.onWindowTitleChange = () => { };
BrowserTabList.prototype.onOpenWindow = makeInfallible(function(aWindow) {
/*
* You can hardly do anything at all with a XUL window at this point; it
* doesn't even have its document yet. Wait until its document has
* loaded, and then see what we've got. This also avoids
* nsIWindowMediator enumeration from within listeners (bug 873589).
*/
aWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
aWindow.addEventListener("load", makeInfallible(handleLoad.bind(this)), false);
function handleLoad(aEvent) {
let handleLoad = makeInfallible(() => {
/* We don't want any further load events from this window. */
aWindow.removeEventListener("load", handleLoad, false);
@ -408,7 +397,18 @@ BrowserTabList.prototype.onOpenWindow = makeInfallible(function(aWindow) {
// document's initial tab, so we must notify our client of the new tab
// this will have.
this._notifyListChanged();
}
});
/*
* You can hardly do anything at all with a XUL window at this point; it
* doesn't even have its document yet. Wait until its document has
* loaded, and then see what we've got. This also avoids
* nsIWindowMediator enumeration from within listeners (bug 873589).
*/
aWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
aWindow.addEventListener("load", handleLoad, false);
}, "BrowserTabList.prototype.onOpenWindow");
BrowserTabList.prototype.onCloseWindow = makeInfallible(function(aWindow) {

View File

@ -0,0 +1,178 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test basic black boxing.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestTabAndResume(gClient, "test-black-box", function(aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", function () {
gThreadClient.setBreakpoint({
url: SOURCE_URL,
line: 2
}, function (aResponse) {
do_check_true(!aResponse.error, "Should be able to set breakpoint.");
gThreadClient.resume(test_black_box_default);
});
});
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
let arg = 15; // line 2 - Step in here
k(arg); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2 - Break here
function (n) { // line 3 - Step through `doStuff` to here
debugger; // line 5
} // line 6
); // line 7
} // line 8
+ "\n debugger;", // line 9
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_default() {
gThreadClient.getSources(function (aResponse) {
do_check_true(!aResponse.error, "Should be able to get sources.");
let sourceClient = gThreadClient.source(
aResponse.sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
do_check_true(!sourceClient.isBlackBoxed,
"By default the source is not black boxed.");
// Test that we can step into `doStuff` when we are not black boxed.
runTest(
function onSteppedLocation(aLocation) {
do_check_eq(aLocation.url, BLACK_BOXED_URL,
"Should step into `doStuff`.");
do_check_eq(aLocation.line, 2,
"Should step into `doStuff`.");
},
function onDebuggerStatementFrames(aFrames) {
do_check_true(!aFrames.some(f => f.isBlackBoxed));
},
test_black_boxing.bind(null, sourceClient)
);
});
}
function test_black_boxing(aSourceClient) {
aSourceClient.blackBox(function (aResponse) {
do_check_true(!aResponse.error, "Should not get an error black boxing.");
do_check_true(aSourceClient.isBlackBoxed,
"The source client should report itself as black boxed correctly.");
// Test that we step through `doStuff` when we are black boxed and its frame
// doesn't show up.
runTest(
function onSteppedLocation(aLocation) {
do_check_eq(aLocation.url, SOURCE_URL,
"Should step through `doStuff`.");
do_check_eq(aLocation.line, 3,
"Should step through `doStuff`.");
},
function onDebuggerStatementFrames(aFrames) {
for (let f of aFrames) {
if (f.where.url == BLACK_BOXED_URL) {
do_check_true(f.isBlackBoxed, "Should be black boxed");
} else {
do_check_true(!f.isBlackBoxed, "Should not be black boxed")
}
}
},
test_unblack_boxing.bind(null, aSourceClient)
);
});
}
function test_unblack_boxing(aSourceClient) {
aSourceClient.unblackBox(function (aResponse) {
do_check_true(!aResponse.error, "Should not get an error un-black boxing");
do_check_true(!aSourceClient.isBlackBoxed, "The source is not black boxed.");
// Test that we can step into `doStuff` again.
runTest(
function onSteppedLocation(aLocation) {
do_check_eq(aLocation.url, BLACK_BOXED_URL,
"Should step into `doStuff`.");
do_check_eq(aLocation.line, 2,
"Should step into `doStuff`.");
},
function onDebuggerStatementFrames(aFrames) {
do_check_true(!aFrames.some(f => f.isBlackBoxed));
},
finishClient.bind(null, gClient)
);
});
}
function runTest(aOnSteppedLocation, aOnDebuggerStatementFrames, aFinishedCallback) {
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "breakpoint");
gClient.addOneTimeListener("paused", function () {
gClient.addOneTimeListener("paused", function () {
getCurrentLocation(function (aLocation) {
aOnSteppedLocation(aLocation);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "debuggerStatement");
gThreadClient.getFrames(0, 100, function ({frames}) {
aOnDebuggerStatementFrames(frames);
// We hit the breakpoint once more on the way out
gClient.addOneTimeListener("paused", function () {
gThreadClient.resume(aFinishedCallback);
});
gThreadClient.resume();
});
});
gThreadClient.resume();
});
});
gThreadClient.stepIn();
});
gThreadClient.stepIn();
});
gDebuggee.runTest();
}
function getCurrentLocation(aCallback) {
gThreadClient.getFrames(0, 1, function ({frames, error}) {
do_check_true(!error, "Should not get an error: " + error);
let [{where}] = frames;
aCallback(where);
});
}

View File

@ -0,0 +1,104 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we don't hit breakpoints in black boxed sources, and that when we
* unblack box the source again, the breakpoint hasn't disappeared and we will
* hit it again.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestTabAndResume(gClient, "test-black-box", function(aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", function () {
gThreadClient.setBreakpoint({
url: BLACK_BOXED_URL,
line: 2
}, function (aResponse) {
do_check_true(!aResponse.error, "Should be able to set breakpoint.");
gThreadClient.resume(test_black_box_breakpoint);
});
});
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
let arg = 15; // line 2 - Break here
k(arg); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
debugger; // line 5
} // line 6
); // line 7
} // line 8
+ "\n debugger;", // line 9
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_breakpoint() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "debuggerStatement",
"We should pass over the breakpoint since the source is black boxed.");
gThreadClient.resume(test_unblack_box_breakpoint.bind(null, sourceClient));
});
gDebuggee.runTest();
});
});
}
function test_unblack_box_breakpoint(aSourceClient) {
aSourceClient.unblackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "breakpoint",
"We should hit the breakpoint again");
// We will hit the debugger statement on resume, so do this nastiness to skip over it.
gClient.addOneTimeListener(
"paused",
gThreadClient.resume.bind(
gThreadClient,
finishClient.bind(null, gClient)));
gThreadClient.resume();
});
gDebuggee.runTest();
});
}

View File

@ -0,0 +1,104 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we don't stop at debugger statements inside black boxed sources.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestTabAndResume(gClient, "test-black-box", function(aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", function () {
gThreadClient.setBreakpoint({
url: SOURCE_URL,
line: 4
}, function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gThreadClient.resume(test_black_box_dbg_statement);
});
});
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
debugger; // line 2 - Break here
k(100); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
Math.abs(n); // line 4 - Break here
} // line 5
); // line 6
} // line 7
+ "\n debugger;", // line 8
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_dbg_statement() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "breakpoint",
"We should pass over the debugger statement.");
gThreadClient.resume(test_unblack_box_dbg_statement.bind(null, sourceClient));
});
gDebuggee.runTest();
});
});
}
function test_unblack_box_dbg_statement(aSourceClient) {
aSourceClient.unblackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_eq(aPacket.why.type, "debuggerStatement",
"We should stop at the debugger statement again");
// We will hit the breakpoint on resume, so do this nastiness to skip over it.
gClient.addOneTimeListener(
"paused",
gThreadClient.resume.bind(
gThreadClient,
finishClient.bind(null, gClient)));
gThreadClient.resume();
});
gDebuggee.runTest();
});
}

View File

@ -0,0 +1,79 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test behavior of blackboxing sources we are currently paused in.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestTabAndResume(gClient, "test-black-box", function(aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", function () {
gThreadClient.setBreakpoint({
url: BLACK_BOXED_URL,
line: 2
}, function (aResponse) {
do_check_true(!aResponse.error, "Should be able to set breakpoint.");
test_black_box_paused();
});
});
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
debugger; // line 2
k(100); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
n; // line 4
} // line 5
); // line 6
} // line 7
+ "\n runTest();", // line 8
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_paused() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error, pausedInSource}) {
do_check_true(!error, "Should not get an error: " + error);
do_check_true(pausedInSource, "We should be notified that we are currently paused in this source");
finishClient(gClient);
});
});
}

View File

@ -0,0 +1,79 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test exceptions inside black boxed sources.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-black-box");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function() {
attachTestTabAndResume(gClient, "test-black-box", function(aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_black_box();
});
});
do_test_pending();
}
const BLACK_BOXED_URL = "http://example.com/blackboxme.js";
const SOURCE_URL = "http://example.com/source.js";
function test_black_box()
{
gClient.addOneTimeListener("paused", test_black_box_exception);
Components.utils.evalInSandbox(
"" + function doStuff(k) { // line 1
throw new Error("wu tang clan ain't nuthin' ta fuck wit"); // line 2
k(100); // line 3
}, // line 4
gDebuggee,
"1.8",
BLACK_BOXED_URL,
1
);
Components.utils.evalInSandbox(
"" + function runTest() { // line 1
doStuff( // line 2
function (n) { // line 3
debugger; // line 4
} // line 5
); // line 6
} // line 7
+ "\ndebugger;\n" // line 8
+ "runTest()", // line 9
gDebuggee,
"1.8",
SOURCE_URL,
1
);
}
function test_black_box_exception() {
gThreadClient.getSources(function ({error, sources}) {
do_check_true(!error, "Should not get an error: " + error);
let sourceClient = gThreadClient.source(sources.filter(s => s.url == BLACK_BOXED_URL)[0]);
sourceClient.blackBox(function ({error}) {
do_check_true(!error, "Should not get an error: " + error);
gThreadClient.pauseOnExceptions(true);
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
do_check_neq(aPacket.frame.where.url, BLACK_BOXED_URL,
"We shouldn't pause while in the black boxed source.");
finishClient(gClient);
});
gThreadClient.resume();
});
});
}

View File

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check that stepping out of a function returns the right return value.
*/
var gDebuggee;
var gClient;
var gThreadClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = addTestGlobal("test-stack");
gClient = new DebuggerClient(DebuggerServer.connectPipe());
gClient.connect(function () {
attachTestTabAndResume(gClient, "test-stack", function (aResponse, aTabClient, aThreadClient) {
gThreadClient = aThreadClient;
test_simple_stepping();
});
});
do_test_pending();
}
function test_simple_stepping()
{
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the return value is 10.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 4);
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.why.frameFinished.return, 10);
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the return value is undefined.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 7);
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.why.frameFinished.return.type, "undefined");
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
// Check that the exception was thrown.
do_check_eq(aPacket.type, "paused");
do_check_eq(aPacket.frame.where.line, gDebuggee.line0 + 12);
do_check_eq(aPacket.why.type, "resumeLimit");
do_check_eq(aPacket.why.frameFinished.throw, "ah");
gThreadClient.resume(function () {
finishClient(gClient);
});
});
gThreadClient.stepOut();
});
gThreadClient.resume();
});
gThreadClient.stepOut();
});
gThreadClient.resume();
});
gThreadClient.stepOut();
});
gDebuggee.eval("var line0 = Error().lineNumber;\n" +
"function f() {\n" + // line0 + 1
" debugger;\n" + // line0 + 2
" var a = 10;\n" + // line0 + 3
" return a;\n" + // line0 + 4
"}\n" + // line0 + 5
"function g() {\n" + // line0 + 6
" debugger;\n" + // line0 + 7
"}\n" + // line0 + 8
"function h() {\n" + // line0 + 9
" debugger;\n" + // line0 + 10
" throw 'ah';\n" + // line0 + 11
" return 2;\n" + // line0 + 12
"}\n" + // line0 + 13
"f();\n" + // line0 + 14
"g();\n" + // line0 + 15
"h();\n"); // line0 + 16
}

View File

@ -11,6 +11,11 @@ reason = bug 821285
[test_dbgglobal.js]
[test_dbgclient_debuggerstatement.js]
[test_attach.js]
[test_blackboxing-01.js]
[test_blackboxing-02.js]
[test_blackboxing-03.js]
[test_blackboxing-04.js]
[test_blackboxing-05.js]
[test_frameactor-01.js]
[test_frameactor-02.js]
[test_frameactor-03.js]
@ -104,6 +109,7 @@ reason = bug 820380
[test_stepping-03.js]
[test_stepping-04.js]
[test_stepping-05.js]
[test_stepping-06.js]
[test_framebindings-01.js]
[test_framebindings-02.js]
[test_framebindings-03.js]

View File

@ -769,12 +769,7 @@ IsUnpromptedElevation(BOOL &isUnpromptedElevation)
// Hand off focus rights to the out-of-process activation server. Without
// this the metro interface won't launch.
hr = CoAllowSetForegroundWindow(activateMgr, NULL);
if (FAILED(hr)) {
activateMgr->Release();
CoUninitialize();
return hr;
}
CoAllowSetForegroundWindow(activateMgr, NULL);
// Launch default browser in Metro
DWORD processID;

View File

@ -454,6 +454,10 @@ interface nsIUpdateProcessor : nsISupports
/**
* Processes the update which has been downloaded.
* This happens without restarting the application.
* On Windows, this can also be used for switching to an applied
* update request.
* @param update The update being applied, or null if this is a switch
* to updated application request. Must be non-null on GONK.
*/
void processUpdate(in nsIUpdate update);
};

View File

@ -32,6 +32,7 @@ const PREF_APP_UPDATE_CERT_ERRORS = "app.update.cert.errors";
const PREF_APP_UPDATE_CERT_MAXERRORS = "app.update.cert.maxErrors";
const PREF_APP_UPDATE_CERT_REQUIREBUILTIN = "app.update.cert.requireBuiltIn";
const PREF_APP_UPDATE_ENABLED = "app.update.enabled";
const PREF_APP_UPDATE_METRO_ENABLED = "app.update.metro.enabled";
const PREF_APP_UPDATE_IDLETIME = "app.update.idletime";
const PREF_APP_UPDATE_INCOMPATIBLE_MODE = "app.update.incompatible.mode";
const PREF_APP_UPDATE_INTERVAL = "app.update.interval";
@ -642,6 +643,37 @@ XPCOMUtils.defineLazyGetter(this, "gCanStageUpdates", function aus_gCanStageUpda
return true;
});
XPCOMUtils.defineLazyGetter(this, "gIsMetro", function aus_gIsMetro() {
#ifdef XP_WIN
#ifdef MOZ_METRO
try {
let metroUtils = Cc["@mozilla.org/windows-metroutils;1"].
createInstance(Ci.nsIWinMetroUtils);
return metroUtils && metroUtils.immersive;
} catch (e) {}
#endif
#endif
return false;
});
XPCOMUtils.defineLazyGetter(this, "gMetroUpdatesEnabled", function aus_gMetroUpdatesEnabled() {
#ifdef XP_WIN
#ifdef MOZ_METRO
if (gIsMetro) {
let metroUpdate = getPref("getBoolPref", PREF_APP_UPDATE_METRO_ENABLED, true);
if (!metroUpdate) {
LOG("gMetroUpdatesEnabled - unable to automatically check for metro" +
" updates, disabled by pref");
return false;
}
}
#endif
#endif
return true;
});
XPCOMUtils.defineLazyGetter(this, "gCanCheckForUpdates", function aus_gCanCheckForUpdates() {
// If the administrator has locked the app update functionality
// OFF - this is not just a user setting, so disable the manual
@ -653,6 +685,10 @@ XPCOMUtils.defineLazyGetter(this, "gCanCheckForUpdates", function aus_gCanCheckF
return false;
}
if (!gMetroUpdatesEnabled) {
return false;
}
// If we don't know the binary platform we're updating, we can't update.
if (!gABI) {
LOG("gCanCheckForUpdates - unable to check for updates, unknown ABI");
@ -2025,6 +2061,8 @@ UpdateService.prototype = {
// version.
this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_ENABLED,
"UPDATER_UPDATES_ENABLED");
this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_METRO_ENABLED,
"UPDATER_UPDATES_METRO_ENABLED");
this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_AUTO,
"UPDATER_UPDATES_AUTOMATIC");
this._sendBoolPrefTelemetryPing(PREF_APP_UPDATE_STAGE_ENABLED,
@ -2395,6 +2433,10 @@ UpdateService.prototype = {
return;
}
if (!gMetroUpdatesEnabled) {
return;
}
if (!gCanApplyUpdates) {
LOG("UpdateService:_selectAndInstallUpdate - the user is unable to " +
"apply updates... prompting");
@ -2432,14 +2474,18 @@ UpdateService.prototype = {
LOG("UpdateService:_selectAndInstallUpdate - prompting because the " +
"update snippet specified showPrompt");
this._showPrompt(update);
return;
if (!gIsMetro) {
return;
}
}
if (!getPref("getBoolPref", PREF_APP_UPDATE_AUTO, true)) {
LOG("UpdateService:_selectAndInstallUpdate - prompting because silent " +
"install is disabled");
this._showPrompt(update);
return;
if (!gIsMetro) {
return;
}
}
if (getPref("getIntPref", PREF_APP_UPDATE_MODE, 1) == 0) {
@ -3364,6 +3410,10 @@ Checker.prototype = {
*/
_enabled: true,
get enabled() {
if (!gMetroUpdatesEnabled) {
return false;
}
return getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true) &&
gCanCheckForUpdates && this._enabled;
},

View File

@ -167,10 +167,11 @@ var gCloseWindowTimeoutCounter = 0;
// The following vars are for restoring previous preference values (if present)
// when the test finishes.
var gAppUpdateEnabled; // app.update.enabled
var gAppUpdateURLDefault; // app.update.url (default prefbranch)
var gAppUpdateURL; // app.update.url.override
var gExtUpdateURL; // extensions.update.url
var gAppUpdateEnabled; // app.update.enabled
var gAppUpdateMetroEnabled; // app.update.metro.enabled
var gAppUpdateURLDefault; // app.update.url (default prefbranch)
var gAppUpdateURL; // app.update.url.override
var gExtUpdateURL; // extensions.update.url
var gTestCounter = -1;
var gWin;
@ -809,6 +810,11 @@ function setupPrefs() {
}
Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true)
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_METRO_ENABLED)) {
gAppUpdateMetroEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_METRO_ENABLED);
}
Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, true)
if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_UPDATE_URL)) {
gExtUpdateURL = Services.prefs.getCharPref(PREF_EXTENSIONS_UPDATE_URL);
}
@ -845,6 +851,13 @@ function resetPrefs() {
Services.prefs.clearUserPref(PREF_APP_UPDATE_ENABLED);
}
if (gAppUpdateMetroEnabled !== undefined) {
Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, gAppUpdateMetroEnabled);
}
else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_METRO_ENABLED)) {
Services.prefs.clearUserPref(PREF_APP_UPDATE_METRO_ENABLED);
}
if (gExtUpdateURL !== undefined) {
Services.prefs.setCharPref(PREF_EXTENSIONS_UPDATE_URL, gExtUpdateURL);
}

View File

@ -23,6 +23,7 @@ const PREF_APP_UPDATE_CERT_MAXERRORS = "app.update.cert.maxErrors";
const PREF_APP_UPDATE_CERT_REQUIREBUILTIN = "app.update.cert.requireBuiltIn";
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
const PREF_APP_UPDATE_ENABLED = "app.update.enabled";
const PREF_APP_UPDATE_METRO_ENABLED = "app.update.metro.enabled";
const PREF_APP_UPDATE_IDLETIME = "app.update.idletime";
const PREF_APP_UPDATE_LOG = "app.update.log";
const PREF_APP_UPDATE_NEVER_BRANCH = "app.update.never.";

View File

@ -358,6 +358,7 @@ function cleanUp() {
*/
function setDefaultPrefs() {
Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, true);
// Don't display UI for a successful installation. Some apps may not set this
// pref to false like Firefox does.
Services.prefs.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, false);

View File

@ -58,6 +58,10 @@
#define PROGRESS_EXECUTE_SIZE 75.0f
#define PROGRESS_FINISH_SIZE 5.0f
// Amount of time in ms to wait for the parent process to close
#define PARENT_WAIT 5000
#define IMMERSIVE_PARENT_WAIT 15000
#if defined(XP_MACOSX)
// These functions are defined in launchchild_osx.mm
void LaunchChild(int argc, char **argv);
@ -1677,6 +1681,23 @@ PatchIfFile::Finish(int status)
#include "nsWindowsHelpers.h"
#include "uachelper.h"
#include "pathhash.h"
#ifdef MOZ_METRO
/**
* Determines if the update came from an Immersive browser
* @return true if the update came from an immersive browser
*/
bool
IsUpdateFromMetro(int argc, NS_tchar **argv)
{
for (int i = 0; i < argc; i++) {
if (!wcsicmp(L"-ServerName:DefaultBrowserServer", argv[i])) {
return true;
}
}
return false;
}
#endif
#endif
static void
@ -1706,11 +1727,9 @@ LaunchCallbackApp(const NS_tchar *workingDir,
#if defined(MOZ_METRO)
// If our callback application is the default metro browser, then
// launch it now.
for (int i = 0; i < argc; i++) {
if (!wcsicmp(L"-ServerName:DefaultBrowserServer", argv[i])) {
LaunchDefaultMetroBrowser();
return;
}
if (IsUpdateFromMetro(argc, argv)) {
LaunchDefaultMetroBrowser();
return;
}
#endif
WinLaunchChild(argv[0], argc, argv, NULL);
@ -2466,9 +2485,15 @@ int NS_main(int argc, NS_tchar **argv)
// Otherwise, wait for the parent process to exit before starting the
// update.
if (parent) {
DWORD result = WaitForSingleObject(parent, 5000);
bool updateFromMetro = false;
#ifdef MOZ_METRO
updateFromMetro = IsUpdateFromMetro(argc, argv);
#endif
DWORD waitTime = updateFromMetro ?
IMMERSIVE_PARENT_WAIT : PARENT_WAIT;
DWORD result = WaitForSingleObject(parent, waitTime);
CloseHandle(parent);
if (result != WAIT_OBJECT_0)
if (result != WAIT_OBJECT_0 && !updateFromMetro)
return 1;
}
}

View File

@ -1034,8 +1034,6 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
int argc;
char **argv;
NS_ENSURE_ARG_POINTER(aUpdate);
nsAutoCString binPath;
nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton();
if (dirProvider) { // Normal code path
@ -1132,6 +1130,8 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
mInfo.mAppVersion = appVersion;
#if defined(MOZ_WIDGET_GONK)
NS_ENSURE_ARG_POINTER(aUpdate);
bool isOSUpdate;
if (NS_SUCCEEDED(aUpdate->GetIsOSUpdate(&isOSUpdate)) &&
isOSUpdate) {
@ -1214,7 +1214,7 @@ nsUpdateProcessor::UpdateDone()
nsCOMPtr<nsIUpdateManager> um =
do_GetService("@mozilla.org/updates/update-manager;1");
if (um) {
if (um && mUpdate) {
um->RefreshUpdateStatus(mUpdate);
}