Merge fx-team to m-c. a=merge
@ -571,8 +571,13 @@ var ctrlTab = {
|
|||||||
* All Tabs menu
|
* All Tabs menu
|
||||||
*/
|
*/
|
||||||
var allTabs = {
|
var allTabs = {
|
||||||
get toolbarButton() document.getElementById("alltabs-button"),
|
get toolbarButton() {
|
||||||
get canOpen() isElementVisible(this.toolbarButton),
|
return document.getElementById("alltabs-button");
|
||||||
|
},
|
||||||
|
|
||||||
|
get canOpen() {
|
||||||
|
return isElementVisible(this.toolbarButton);
|
||||||
|
},
|
||||||
|
|
||||||
open: function allTabs_open() {
|
open: function allTabs_open() {
|
||||||
if (this.canOpen) {
|
if (this.canOpen) {
|
||||||
|
@ -317,7 +317,9 @@
|
|||||||
hidden="true"
|
hidden="true"
|
||||||
label="&bidiSwitchPageDirectionItem.label;"
|
label="&bidiSwitchPageDirectionItem.label;"
|
||||||
accesskey="&bidiSwitchPageDirectionItem.accesskey;"
|
accesskey="&bidiSwitchPageDirectionItem.accesskey;"
|
||||||
oncommand="SwitchDocumentDirection(window.content)"/>
|
oncommand="gBrowser.selectedBrowser
|
||||||
|
.messageManager
|
||||||
|
.sendAsyncMessage('SwitchDocumentDirection');"/>
|
||||||
</menupopup>
|
</menupopup>
|
||||||
</menu>
|
</menu>
|
||||||
|
|
||||||
|
@ -6489,17 +6489,6 @@ function AddKeywordForSearchField() {
|
|||||||
}, window);
|
}, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SwitchDocumentDirection(aWindow) {
|
|
||||||
// document.dir can also be "auto", in which case it won't change
|
|
||||||
if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
|
|
||||||
aWindow.document.dir = "rtl";
|
|
||||||
} else if (aWindow.document.dir == "rtl") {
|
|
||||||
aWindow.document.dir = "ltr";
|
|
||||||
}
|
|
||||||
for (var run = 0; run < aWindow.frames.length; run++)
|
|
||||||
SwitchDocumentDirection(aWindow.frames[run]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertFromUnicode(charset, str)
|
function convertFromUnicode(charset, str)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
@ -1005,12 +1005,11 @@ nsContextMenu.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
viewImageDesc: function(e) {
|
viewImageDesc: function(e) {
|
||||||
var doc = this.target.ownerDocument;
|
|
||||||
urlSecurityCheck(this.imageDescURL,
|
urlSecurityCheck(this.imageDescURL,
|
||||||
this.browser.contentPrincipal,
|
this.browser.contentPrincipal,
|
||||||
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
||||||
openUILink(this.imageDescURL, e, { disallowInheritPrincipal: true,
|
openUILink(this.imageDescURL, e, { disallowInheritPrincipal: true,
|
||||||
referrerURI: doc.documentURIObject });
|
referrerURI: gContextMenuContentData.documentURIObject });
|
||||||
},
|
},
|
||||||
|
|
||||||
viewFrameInfo: function() {
|
viewFrameInfo: function() {
|
||||||
@ -1080,9 +1079,8 @@ nsContextMenu.prototype = {
|
|||||||
urlSecurityCheck(this.bgImageURL,
|
urlSecurityCheck(this.bgImageURL,
|
||||||
this.browser.contentPrincipal,
|
this.browser.contentPrincipal,
|
||||||
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
|
||||||
var doc = this.target.ownerDocument;
|
|
||||||
openUILink(this.bgImageURL, e, { disallowInheritPrincipal: true,
|
openUILink(this.bgImageURL, e, { disallowInheritPrincipal: true,
|
||||||
referrerURI: doc.documentURIObject });
|
referrerURI: gContextMenuContentData.documentURIObject });
|
||||||
},
|
},
|
||||||
|
|
||||||
disableSetDesktopBackground: function() {
|
disableSetDesktopBackground: function() {
|
||||||
@ -1379,10 +1377,10 @@ nsContextMenu.prototype = {
|
|||||||
// Let's try to unescape it using a character set
|
// Let's try to unescape it using a character set
|
||||||
// in case the address is not ASCII.
|
// in case the address is not ASCII.
|
||||||
try {
|
try {
|
||||||
var characterSet = this.target.ownerDocument.characterSet;
|
|
||||||
const textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
|
const textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
|
||||||
getService(Ci.nsITextToSubURI);
|
getService(Ci.nsITextToSubURI);
|
||||||
addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
|
addresses = textToSubURI.unEscapeURIForUI(gContextMenuContentData.charSet,
|
||||||
|
addresses);
|
||||||
}
|
}
|
||||||
catch(ex) {
|
catch(ex) {
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
@ -1651,7 +1649,7 @@ nsContextMenu.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
switchPageDirection: function CM_switchPageDirection() {
|
switchPageDirection: function CM_switchPageDirection() {
|
||||||
SwitchDocumentDirection(this.browser.contentWindowAsCPOW);
|
this.browser.messageManager.sendAsyncMessage("SwitchDocumentDirection");
|
||||||
},
|
},
|
||||||
|
|
||||||
mediaCommand : function CM_mediaCommand(command, data) {
|
mediaCommand : function CM_mediaCommand(command, data) {
|
||||||
|
@ -12,6 +12,7 @@ support-files =
|
|||||||
browser_bug678392-2.html
|
browser_bug678392-2.html
|
||||||
browser_bug970746.xhtml
|
browser_bug970746.xhtml
|
||||||
browser_fxa_oauth.html
|
browser_fxa_oauth.html
|
||||||
|
browser_fxa_oauth_with_keys.html
|
||||||
browser_fxa_profile_channel.html
|
browser_fxa_profile_channel.html
|
||||||
browser_registerProtocolHandler_notification.html
|
browser_registerProtocolHandler_notification.html
|
||||||
browser_ssl_error_reports_content.js
|
browser_ssl_error_reports_content.js
|
||||||
|
@ -17,11 +17,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsOAuthClient",
|
|||||||
|
|
||||||
const HTTP_PATH = "http://example.com";
|
const HTTP_PATH = "http://example.com";
|
||||||
const HTTP_ENDPOINT = "/browser/browser/base/content/test/general/browser_fxa_oauth.html";
|
const HTTP_ENDPOINT = "/browser/browser/base/content/test/general/browser_fxa_oauth.html";
|
||||||
|
const HTTP_ENDPOINT_WITH_KEYS = "/browser/browser/base/content/test/general/browser_fxa_oauth_with_keys.html";
|
||||||
|
|
||||||
let gTests = [
|
let gTests = [
|
||||||
{
|
{
|
||||||
desc: "FxA OAuth - should open a new tab, complete OAuth flow",
|
desc: "FxA OAuth - should open a new tab, complete OAuth flow",
|
||||||
run: function* () {
|
run: function () {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
let tabOpened = false;
|
let tabOpened = false;
|
||||||
let properUrl = "http://example.com/browser/browser/base/content/test/general/browser_fxa_oauth.html";
|
let properUrl = "http://example.com/browser/browser/base/content/test/general/browser_fxa_oauth.html";
|
||||||
@ -71,6 +72,169 @@ let gTests = [
|
|||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
client.onError = reject;
|
||||||
|
|
||||||
|
client.launchWebFlow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "FxA OAuth - should receive an error when there's a state mismatch",
|
||||||
|
run: function () {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
let tabOpened = false;
|
||||||
|
|
||||||
|
waitForTab(function (tab) {
|
||||||
|
Assert.ok("Tab successfully opened");
|
||||||
|
|
||||||
|
// It should have passed in the expected non-matching state value.
|
||||||
|
let queryString = gBrowser.currentURI.spec.split('?')[1];
|
||||||
|
Assert.ok(queryString.indexOf('state=different-state') >= 0);
|
||||||
|
|
||||||
|
tabOpened = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let client = new FxAccountsOAuthClient({
|
||||||
|
parameters: {
|
||||||
|
state: "different-state",
|
||||||
|
client_id: "client_id",
|
||||||
|
oauth_uri: HTTP_PATH,
|
||||||
|
content_uri: HTTP_PATH,
|
||||||
|
},
|
||||||
|
authorizationEndpoint: HTTP_ENDPOINT
|
||||||
|
});
|
||||||
|
|
||||||
|
client.onComplete = reject;
|
||||||
|
|
||||||
|
client.onError = function(err) {
|
||||||
|
Assert.ok(tabOpened);
|
||||||
|
Assert.equal(err.message, "OAuth flow failed. State doesn't match");
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
client.launchWebFlow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "FxA OAuth - should be able to request keys during OAuth flow",
|
||||||
|
run: function () {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
let tabOpened = false;
|
||||||
|
|
||||||
|
waitForTab(function (tab) {
|
||||||
|
Assert.ok("Tab successfully opened");
|
||||||
|
|
||||||
|
// It should have asked for keys.
|
||||||
|
let queryString = gBrowser.currentURI.spec.split('?')[1];
|
||||||
|
Assert.ok(queryString.indexOf('keys=true') >= 0);
|
||||||
|
|
||||||
|
tabOpened = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let client = new FxAccountsOAuthClient({
|
||||||
|
parameters: {
|
||||||
|
state: "state",
|
||||||
|
client_id: "client_id",
|
||||||
|
oauth_uri: HTTP_PATH,
|
||||||
|
content_uri: HTTP_PATH,
|
||||||
|
keys: true,
|
||||||
|
},
|
||||||
|
authorizationEndpoint: HTTP_ENDPOINT_WITH_KEYS
|
||||||
|
});
|
||||||
|
|
||||||
|
client.onComplete = function(tokenData, keys) {
|
||||||
|
Assert.ok(tabOpened);
|
||||||
|
Assert.equal(tokenData.code, "code1");
|
||||||
|
Assert.equal(tokenData.state, "state");
|
||||||
|
Assert.equal(keys.kAr, "kAr");
|
||||||
|
Assert.equal(keys.kBr, "kBr");
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
client.onError = reject;
|
||||||
|
|
||||||
|
client.launchWebFlow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "FxA OAuth - should not receive keys if not explicitly requested",
|
||||||
|
run: function () {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
let tabOpened = false;
|
||||||
|
|
||||||
|
waitForTab(function (tab) {
|
||||||
|
Assert.ok("Tab successfully opened");
|
||||||
|
|
||||||
|
// It should not have asked for keys.
|
||||||
|
let queryString = gBrowser.currentURI.spec.split('?')[1];
|
||||||
|
Assert.ok(queryString.indexOf('keys=true') == -1);
|
||||||
|
|
||||||
|
tabOpened = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let client = new FxAccountsOAuthClient({
|
||||||
|
parameters: {
|
||||||
|
state: "state",
|
||||||
|
client_id: "client_id",
|
||||||
|
oauth_uri: HTTP_PATH,
|
||||||
|
content_uri: HTTP_PATH
|
||||||
|
},
|
||||||
|
// This endpoint will cause the completion message to contain keys.
|
||||||
|
authorizationEndpoint: HTTP_ENDPOINT_WITH_KEYS
|
||||||
|
});
|
||||||
|
|
||||||
|
client.onComplete = function(tokenData, keys) {
|
||||||
|
Assert.ok(tabOpened);
|
||||||
|
Assert.equal(tokenData.code, "code1");
|
||||||
|
Assert.equal(tokenData.state, "state");
|
||||||
|
Assert.strictEqual(keys, undefined);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
client.onError = reject;
|
||||||
|
|
||||||
|
client.launchWebFlow();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "FxA OAuth - should receive an error if keys could not be obtained",
|
||||||
|
run: function () {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
let tabOpened = false;
|
||||||
|
|
||||||
|
waitForTab(function (tab) {
|
||||||
|
Assert.ok("Tab successfully opened");
|
||||||
|
|
||||||
|
// It should have asked for keys.
|
||||||
|
let queryString = gBrowser.currentURI.spec.split('?')[1];
|
||||||
|
Assert.ok(queryString.indexOf('keys=true') >= 0);
|
||||||
|
|
||||||
|
tabOpened = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
let client = new FxAccountsOAuthClient({
|
||||||
|
parameters: {
|
||||||
|
state: "state",
|
||||||
|
client_id: "client_id",
|
||||||
|
oauth_uri: HTTP_PATH,
|
||||||
|
content_uri: HTTP_PATH,
|
||||||
|
keys: true,
|
||||||
|
},
|
||||||
|
// This endpoint will cause the completion message not to contain keys.
|
||||||
|
authorizationEndpoint: HTTP_ENDPOINT
|
||||||
|
});
|
||||||
|
|
||||||
|
client.onComplete = reject;
|
||||||
|
|
||||||
|
client.onError = function(err) {
|
||||||
|
Assert.ok(tabOpened);
|
||||||
|
Assert.equal(err.message, "OAuth flow failed. Keys were not returned");
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
client.launchWebFlow();
|
client.launchWebFlow();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>fxa_oauth_test</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
window.onload = function(){
|
||||||
|
var event = new window.CustomEvent("WebChannelMessageToChrome", {
|
||||||
|
detail: {
|
||||||
|
id: "oauth_client_id",
|
||||||
|
message: {
|
||||||
|
command: "oauth_complete",
|
||||||
|
data: {
|
||||||
|
state: "state",
|
||||||
|
code: "code1",
|
||||||
|
closeWindow: "signin",
|
||||||
|
keys: { kAr: 'kAr', kBr: 'kBr' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
window.dispatchEvent(event);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -964,6 +964,7 @@ let MozLoopServiceInternal = {
|
|||||||
this.promiseFxAOAuthClient().then(
|
this.promiseFxAOAuthClient().then(
|
||||||
client => {
|
client => {
|
||||||
client.onComplete = this._fxAOAuthComplete.bind(this, deferred);
|
client.onComplete = this._fxAOAuthComplete.bind(this, deferred);
|
||||||
|
client.onError = this._fxAOAuthError.bind(this, deferred);
|
||||||
client.launchWebFlow();
|
client.launchWebFlow();
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
@ -1003,18 +1004,24 @@ let MozLoopServiceInternal = {
|
|||||||
/**
|
/**
|
||||||
* Called once gFxAOAuthClient fires onComplete.
|
* Called once gFxAOAuthClient fires onComplete.
|
||||||
*
|
*
|
||||||
* @param {Deferred} deferred used to resolve or reject the gFxAOAuthClientPromise
|
* @param {Deferred} deferred used to resolve the gFxAOAuthClientPromise
|
||||||
* @param {Object} result (with code and state)
|
* @param {Object} result (with code and state)
|
||||||
*/
|
*/
|
||||||
_fxAOAuthComplete: function(deferred, result) {
|
_fxAOAuthComplete: function(deferred, result) {
|
||||||
gFxAOAuthClientPromise = null;
|
gFxAOAuthClientPromise = null;
|
||||||
|
|
||||||
// Note: The state was already verified in FxAccountsOAuthClient.
|
// Note: The state was already verified in FxAccountsOAuthClient.
|
||||||
if (result) {
|
deferred.resolve(result);
|
||||||
deferred.resolve(result);
|
},
|
||||||
} else {
|
|
||||||
deferred.reject("Invalid token data");
|
/**
|
||||||
}
|
* Called if gFxAOAuthClient fires onError.
|
||||||
|
*
|
||||||
|
* @param {Deferred} deferred used to reject the gFxAOAuthClientPromise
|
||||||
|
* @param {Object} error object returned by FxAOAuthClient
|
||||||
|
*/
|
||||||
|
_fxAOAuthError: function(deferred, err) {
|
||||||
|
gFxAOAuthClientPromise = null;
|
||||||
|
deferred.reject(err);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Object.freeze(MozLoopServiceInternal);
|
Object.freeze(MozLoopServiceInternal);
|
||||||
|
@ -133,8 +133,7 @@
|
|||||||
completedefaultindex="true"
|
completedefaultindex="true"
|
||||||
tabscrolling="true"
|
tabscrolling="true"
|
||||||
showcommentcolumn="true"
|
showcommentcolumn="true"
|
||||||
placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"
|
placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"/>
|
||||||
maxlength="1000"/>
|
|
||||||
<button id="editBMPanel_tagsSelectorExpander"
|
<button id="editBMPanel_tagsSelectorExpander"
|
||||||
class="expander-down"
|
class="expander-down"
|
||||||
tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
|
tooltiptext="&editBookmarkOverlay.tagsExpanderDown.tooltip;"
|
||||||
|
@ -3,6 +3,8 @@ let gHandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.n
|
|||||||
|
|
||||||
Services.prefs.setBoolPref("browser.preferences.inContent", true);
|
Services.prefs.setBoolPref("browser.preferences.inContent", true);
|
||||||
|
|
||||||
|
SimpleTest.requestCompleteLog();
|
||||||
|
|
||||||
function setupFakeHandler() {
|
function setupFakeHandler() {
|
||||||
let info = gMimeSvc.getFromTypeAndExtension("text/plain", "foo.txt");
|
let info = gMimeSvc.getFromTypeAndExtension("text/plain", "foo.txt");
|
||||||
ok(info.possibleLocalHandlers.length, "Should have at least one known handler");
|
ok(info.possibleLocalHandlers.length, "Should have at least one known handler");
|
||||||
|
@ -10,7 +10,7 @@ let gSanitizeDialog = Object.freeze({
|
|||||||
for (let element of customWidthElements) {
|
for (let element of customWidthElements) {
|
||||||
element.style.width = element.getAttribute(isInSubdialog ? "subdialogWidth" : "dialogWidth");
|
element.style.width = element.getAttribute(isInSubdialog ? "subdialogWidth" : "dialogWidth");
|
||||||
}
|
}
|
||||||
onClearHistoryChanged();
|
this.onClearHistoryChanged();
|
||||||
},
|
},
|
||||||
|
|
||||||
onClearHistoryChanged: function () {
|
onClearHistoryChanged: function () {
|
||||||
|
@ -27,6 +27,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
|
|||||||
"resource://gre/modules/devtools/dbg-client.jsm");
|
"resource://gre/modules/devtools/dbg-client.jsm");
|
||||||
|
|
||||||
const EventEmitter = devtools.require("devtools/toolkit/event-emitter");
|
const EventEmitter = devtools.require("devtools/toolkit/event-emitter");
|
||||||
|
const Telemetry = devtools.require("devtools/shared/telemetry");
|
||||||
|
|
||||||
|
const TABS_OPEN_PEAK_HISTOGRAM = "DEVTOOLS_TABS_OPEN_PEAK_LINEAR";
|
||||||
|
const TABS_OPEN_AVG_HISTOGRAM = "DEVTOOLS_TABS_OPEN_AVERAGE_LINEAR";
|
||||||
|
const TABS_PINNED_PEAK_HISTOGRAM = "DEVTOOLS_TABS_PINNED_PEAK_EXPONENTIAL";
|
||||||
|
const TABS_PINNED_AVG_HISTOGRAM = "DEVTOOLS_TABS_PINNED_AVERAGE_EXPONENTIAL";
|
||||||
|
|
||||||
const FORBIDDEN_IDS = new Set(["toolbox", ""]);
|
const FORBIDDEN_IDS = new Set(["toolbox", ""]);
|
||||||
const MAX_ORDINAL = 99;
|
const MAX_ORDINAL = 99;
|
||||||
|
|
||||||
@ -467,6 +474,23 @@ DevTools.prototype = {
|
|||||||
return toolbox.destroy().then(() => true);
|
return toolbox.destroy().then(() => true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_pingTelemetry: function() {
|
||||||
|
let mean = function(arr) {
|
||||||
|
if (arr.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let total = arr.reduce((a, b) => a + b);
|
||||||
|
return Math.ceil(total / arr.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
let tabStats = gDevToolsBrowser._tabStats;
|
||||||
|
this._telemetry.log(TABS_OPEN_PEAK_HISTOGRAM, tabStats.peakOpen);
|
||||||
|
this._telemetry.log(TABS_OPEN_AVG_HISTOGRAM, mean(tabStats.histOpen));
|
||||||
|
this._telemetry.log(TABS_PINNED_PEAK_HISTOGRAM, tabStats.peakPinned);
|
||||||
|
this._telemetry.log(TABS_PINNED_AVG_HISTOGRAM, mean(tabStats.histPinned));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to tear down a tools provider.
|
* Called to tear down a tools provider.
|
||||||
*/
|
*/
|
||||||
@ -487,6 +511,9 @@ DevTools.prototype = {
|
|||||||
this.unregisterTool(key, true);
|
this.unregisterTool(key, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._pingTelemetry();
|
||||||
|
this._telemetry = null;
|
||||||
|
|
||||||
// Cleaning down the toolboxes: i.e.
|
// Cleaning down the toolboxes: i.e.
|
||||||
// for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
|
// for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
|
||||||
// Is taken care of by the gDevToolsBrowser.forgetBrowserWindow
|
// Is taken care of by the gDevToolsBrowser.forgetBrowserWindow
|
||||||
@ -522,6 +549,13 @@ let gDevToolsBrowser = {
|
|||||||
*/
|
*/
|
||||||
_trackedBrowserWindows: new Set(),
|
_trackedBrowserWindows: new Set(),
|
||||||
|
|
||||||
|
_tabStats: {
|
||||||
|
peakOpen: 0,
|
||||||
|
peakPinned: 0,
|
||||||
|
histOpen: [],
|
||||||
|
histPinned: []
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function is for the benefit of Tools:DevToolbox in
|
* This function is for the benefit of Tools:DevToolbox in
|
||||||
* browser/base/content/browser-sets.inc and should not be used outside
|
* browser/base/content/browser-sets.inc and should not be used outside
|
||||||
@ -819,9 +853,12 @@ let gDevToolsBrowser = {
|
|||||||
broadcaster.removeAttribute("key");
|
broadcaster.removeAttribute("key");
|
||||||
}
|
}
|
||||||
|
|
||||||
let tabContainer = win.document.getElementById("tabbrowser-tabs")
|
let tabContainer = win.document.getElementById("tabbrowser-tabs");
|
||||||
tabContainer.addEventListener("TabSelect",
|
tabContainer.addEventListener("TabSelect", this, false);
|
||||||
gDevToolsBrowser._updateMenuCheckbox, false);
|
tabContainer.addEventListener("TabOpen", this, false);
|
||||||
|
tabContainer.addEventListener("TabClose", this, false);
|
||||||
|
tabContainer.addEventListener("TabPinned", this, false);
|
||||||
|
tabContainer.addEventListener("TabUnpinned", this, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1253,9 +1290,40 @@ let gDevToolsBrowser = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let tabContainer = win.document.getElementById("tabbrowser-tabs")
|
let tabContainer = win.document.getElementById("tabbrowser-tabs");
|
||||||
tabContainer.removeEventListener("TabSelect",
|
tabContainer.removeEventListener("TabSelect", this, false);
|
||||||
gDevToolsBrowser._updateMenuCheckbox, false);
|
tabContainer.removeEventListener("TabOpen", this, false);
|
||||||
|
tabContainer.removeEventListener("TabClose", this, false);
|
||||||
|
tabContainer.removeEventListener("TabPinned", this, false);
|
||||||
|
tabContainer.removeEventListener("TabUnpinned", this, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEvent: function(event) {
|
||||||
|
switch (event.type) {
|
||||||
|
case "TabOpen":
|
||||||
|
case "TabClose":
|
||||||
|
case "TabPinned":
|
||||||
|
case "TabUnpinned":
|
||||||
|
let open = 0;
|
||||||
|
let pinned = 0;
|
||||||
|
|
||||||
|
for (let win of this._trackedBrowserWindows) {
|
||||||
|
let tabContainer = win.gBrowser.tabContainer;
|
||||||
|
let numPinnedTabs = tabContainer.tabbrowser._numPinnedTabs;
|
||||||
|
let numTabs = tabContainer.itemCount - numPinnedTabs;
|
||||||
|
|
||||||
|
open += numTabs;
|
||||||
|
pinned += numPinnedTabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._tabStats.histOpen.push(open);
|
||||||
|
this._tabStats.histPinned.push(pinned);
|
||||||
|
this._tabStats.peakOpen = Math.max(open, this._tabStats.peakOpen);
|
||||||
|
this._tabStats.peakPinned = Math.max(pinned, this._tabStats.peakPinned);
|
||||||
|
break;
|
||||||
|
case "TabSelect":
|
||||||
|
gDevToolsBrowser._updateMenuCheckbox();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,6 +10,9 @@ const SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsoleEnabled";
|
|||||||
const SPLITCONSOLE_HEIGHT_PREF = "devtools.toolbox.splitconsoleHeight";
|
const SPLITCONSOLE_HEIGHT_PREF = "devtools.toolbox.splitconsoleHeight";
|
||||||
const MIN_ZOOM = 0.5;
|
const MIN_ZOOM = 0.5;
|
||||||
const MAX_ZOOM = 2;
|
const MAX_ZOOM = 2;
|
||||||
|
const OS_HISTOGRAM = "DEVTOOLS_OS_ENUMERATED_PER_USER";
|
||||||
|
const OS_IS_64_BITS = "DEVTOOLS_OS_IS_64_BITS_PER_USER";
|
||||||
|
const SCREENSIZE_HISTOGRAM = "DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER";
|
||||||
|
|
||||||
let {Cc, Ci, Cu} = require("chrome");
|
let {Cc, Ci, Cu} = require("chrome");
|
||||||
let {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
let {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||||
@ -49,6 +52,19 @@ loader.lazyGetter(this, "Selection", () => require("devtools/framework/selection
|
|||||||
loader.lazyGetter(this, "InspectorFront", () => require("devtools/server/actors/inspector").InspectorFront);
|
loader.lazyGetter(this, "InspectorFront", () => require("devtools/server/actors/inspector").InspectorFront);
|
||||||
loader.lazyRequireGetter(this, "DevToolsUtils", "devtools/toolkit/DevToolsUtils");
|
loader.lazyRequireGetter(this, "DevToolsUtils", "devtools/toolkit/DevToolsUtils");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "screenManager", () => {
|
||||||
|
return Cc["@mozilla.org/gfx/screenmanager;1"].getService(Ci.nsIScreenManager);
|
||||||
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "oscpu", () => {
|
||||||
|
return Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||||
|
.getService(Ci.nsIHttpProtocolHandler).oscpu;
|
||||||
|
});
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyGetter(this, "is64Bit", () => {
|
||||||
|
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).is64Bit;
|
||||||
|
});
|
||||||
|
|
||||||
// White-list buttons that can be toggled to prevent adding prefs for
|
// White-list buttons that can be toggled to prevent adding prefs for
|
||||||
// addons that have manually inserted toolbarbuttons into DOM.
|
// addons that have manually inserted toolbarbuttons into DOM.
|
||||||
// (By default, supported target is only local tab)
|
// (By default, supported target is only local tab)
|
||||||
@ -334,7 +350,7 @@ Toolbox.prototype = {
|
|||||||
|
|
||||||
let buttonsPromise = this._buildButtons();
|
let buttonsPromise = this._buildButtons();
|
||||||
|
|
||||||
this._telemetry.toolOpened("toolbox");
|
this._pingTelemetry();
|
||||||
|
|
||||||
this.selectTool(this._defaultToolId).then(panel => {
|
this.selectTool(this._defaultToolId).then(panel => {
|
||||||
|
|
||||||
@ -359,7 +375,7 @@ Toolbox.prototype = {
|
|||||||
// Load the toolbox-level actor fronts and utilities now
|
// Load the toolbox-level actor fronts and utilities now
|
||||||
this._target.makeRemote().then(() => {
|
this._target.makeRemote().then(() => {
|
||||||
iframe.setAttribute("src", this._URL);
|
iframe.setAttribute("src", this._URL);
|
||||||
iframe.setAttribute("aria-label", toolboxStrings("toolbox.label"))
|
iframe.setAttribute("aria-label", toolboxStrings("toolbox.label"));
|
||||||
let domHelper = new DOMHelpers(iframe.contentWindow);
|
let domHelper = new DOMHelpers(iframe.contentWindow);
|
||||||
domHelper.onceDOMReady(domReady);
|
domHelper.onceDOMReady(domReady);
|
||||||
});
|
});
|
||||||
@ -368,6 +384,16 @@ Toolbox.prototype = {
|
|||||||
}).then(null, console.error.bind(console));
|
}).then(null, console.error.bind(console));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_pingTelemetry: function() {
|
||||||
|
this._telemetry.toolOpened("toolbox");
|
||||||
|
|
||||||
|
this._telemetry.logOncePerBrowserVersion(OS_HISTOGRAM,
|
||||||
|
this._getOsCpu());
|
||||||
|
this._telemetry.logOncePerBrowserVersion(OS_IS_64_BITS, is64Bit ? 1 : 0);
|
||||||
|
this._telemetry.logOncePerBrowserVersion(SCREENSIZE_HISTOGRAM,
|
||||||
|
this._getScreenDimensions());
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because our panels are lazy loaded this is a good place to watch for
|
* Because our panels are lazy loaded this is a good place to watch for
|
||||||
* "pref-changed" events.
|
* "pref-changed" events.
|
||||||
@ -1575,6 +1601,41 @@ Toolbox.prototype = {
|
|||||||
return this.doc.getElementById("toolbox-notificationbox");
|
return this.doc.getElementById("toolbox-notificationbox");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getScreenDimensions: function() {
|
||||||
|
let width = {};
|
||||||
|
let height = {};
|
||||||
|
|
||||||
|
screenManager.primaryScreen.GetRect({}, {}, width, height);
|
||||||
|
let dims = width.value + "x" + height.value;
|
||||||
|
|
||||||
|
if (width.value < 800 || height.value < 600) return 0;
|
||||||
|
if (dims === "800x600") return 1;
|
||||||
|
if (dims === "1024x768") return 2;
|
||||||
|
if (dims === "1280x800") return 3;
|
||||||
|
if (dims === "1280x1024") return 4;
|
||||||
|
if (dims === "1366x768") return 5;
|
||||||
|
if (dims === "1440x900") return 6;
|
||||||
|
if (dims === "1920x1080") return 7;
|
||||||
|
if (dims === "2560×1440") return 8;
|
||||||
|
if (dims === "2560×1600") return 9;
|
||||||
|
if (dims === "2880x1800") return 10;
|
||||||
|
if (width.value > 2880 || height.value > 1800) return 12;
|
||||||
|
|
||||||
|
return 11; // Other dimension such as a VM.
|
||||||
|
},
|
||||||
|
|
||||||
|
_getOsCpu: function() {
|
||||||
|
if (oscpu.contains("NT 5.1") || oscpu.contains("NT 5.2")) return 0;
|
||||||
|
if (oscpu.contains("NT 6.0")) return 1;
|
||||||
|
if (oscpu.contains("NT 6.1")) return 2;
|
||||||
|
if (oscpu.contains("NT 6.2")) return 3;
|
||||||
|
if (oscpu.contains("NT 6.3")) return 4;
|
||||||
|
if (oscpu.contains("OS X")) return 5;
|
||||||
|
if (oscpu.contains("Linux")) return 6;
|
||||||
|
|
||||||
|
return 12; // Other OS.
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the current host, and remove event listeners from its frame.
|
* Destroy the current host, and remove event listeners from its frame.
|
||||||
*
|
*
|
||||||
|
@ -139,7 +139,6 @@ function initNetMonitor(aUrl, aWindow) {
|
|||||||
let tab = yield addTab(aUrl);
|
let tab = yield addTab(aUrl);
|
||||||
info("Net tab added successfully: " + aUrl);
|
info("Net tab added successfully: " + aUrl);
|
||||||
|
|
||||||
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
|
||||||
let target = TargetFactory.forTab(tab);
|
let target = TargetFactory.forTab(tab);
|
||||||
|
|
||||||
yield target.makeRemote();
|
yield target.makeRemote();
|
||||||
@ -151,6 +150,7 @@ function initNetMonitor(aUrl, aWindow) {
|
|||||||
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
|
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
|
||||||
info("Netork monitor pane shown successfully.");
|
info("Netork monitor pane shown successfully.");
|
||||||
|
|
||||||
|
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||||
let monitor = toolbox.getCurrentPanel();
|
let monitor = toolbox.getCurrentPanel();
|
||||||
return [tab, debuggee, monitor];
|
return [tab, debuggee, monitor];
|
||||||
});
|
});
|
||||||
|
@ -322,20 +322,23 @@ PerformanceFront.prototype = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the timeline actor, if necessary.
|
* Starts recording allocations in the memory actor, if necessary.
|
||||||
*/
|
*/
|
||||||
_startMemory: Task.async(function *(options) {
|
_startMemory: Task.async(function *(options) {
|
||||||
if (!options.withAllocations) {
|
if (!options.withAllocations) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
yield this._request("memory", "attach");
|
yield this._request("memory", "attach");
|
||||||
let memoryStartTime = yield this._request("memory", "startRecordingAllocations", options);
|
let memoryStartTime = yield this._request("memory", "startRecordingAllocations", {
|
||||||
|
probability: options.allocationsSampleProbability,
|
||||||
|
maxLogLength: options.allocationsMaxLogLength
|
||||||
|
});
|
||||||
yield this._pullAllocationSites();
|
yield this._pullAllocationSites();
|
||||||
return memoryStartTime;
|
return memoryStartTime;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the timeline actor, if necessary.
|
* Stops recording allocations in the memory actor, if necessary.
|
||||||
*/
|
*/
|
||||||
_stopMemory: Task.async(function *(options) {
|
_stopMemory: Task.async(function *(options) {
|
||||||
if (!options.withAllocations) {
|
if (!options.withAllocations) {
|
||||||
|
@ -24,7 +24,9 @@ const RecordingModel = function (options={}) {
|
|||||||
this._configuration = {
|
this._configuration = {
|
||||||
withTicks: options.withTicks || false,
|
withTicks: options.withTicks || false,
|
||||||
withMemory: options.withMemory || false,
|
withMemory: options.withMemory || false,
|
||||||
withAllocations: options.withAllocations || false
|
withAllocations: options.withAllocations || false,
|
||||||
|
allocationsSampleProbability: options.allocationsSampleProbability || 0,
|
||||||
|
allocationsMaxLogLength: options.allocationsMaxLogLength || 0
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,18 +82,15 @@ RecordingModel.prototype = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts recording with the PerformanceFront.
|
* Starts recording with the PerformanceFront.
|
||||||
*
|
|
||||||
* @param object options
|
|
||||||
* @see PerformanceFront.prototype.startRecording
|
|
||||||
*/
|
*/
|
||||||
startRecording: Task.async(function *(options = {}) {
|
startRecording: Task.async(function *() {
|
||||||
// Times must come from the actor in order to be self-consistent.
|
// Times must come from the actor in order to be self-consistent.
|
||||||
// However, we also want to update the view with the elapsed time
|
// However, we also want to update the view with the elapsed time
|
||||||
// even when the actor is not generating data. To do this we get
|
// even when the actor is not generating data. To do this we get
|
||||||
// the local time and use it to compute a reasonable elapsed time.
|
// the local time and use it to compute a reasonable elapsed time.
|
||||||
this._localStartTime = this._performance.now();
|
this._localStartTime = this._performance.now();
|
||||||
|
|
||||||
let info = yield this._front.startRecording(options);
|
let info = yield this._front.startRecording(this.getConfiguration());
|
||||||
this._profilerStartTime = info.profilerStartTime;
|
this._profilerStartTime = info.profilerStartTime;
|
||||||
this._timelineStartTime = info.timelineStartTime;
|
this._timelineStartTime = info.timelineStartTime;
|
||||||
this._memoryStartTime = info.memoryStartTime;
|
this._memoryStartTime = info.memoryStartTime;
|
||||||
|
@ -261,16 +261,16 @@ let PerformanceController = {
|
|||||||
* when the front has started to record.
|
* when the front has started to record.
|
||||||
*/
|
*/
|
||||||
startRecording: Task.async(function *() {
|
startRecording: Task.async(function *() {
|
||||||
let withMemory = this.getOption("enable-memory");
|
let recording = this._createRecording({
|
||||||
let withTicks = this.getOption("enable-framerate");
|
withMemory: this.getOption("enable-memory"),
|
||||||
let withAllocations = this.getOption("enable-memory");
|
withTicks: this.getOption("enable-framerate"),
|
||||||
let probability = this.getPref("memory-sample-probability");
|
withAllocations: this.getOption("enable-memory"),
|
||||||
let maxLogLength = this.getPref("memory-max-log-length");
|
allocationsSampleProbability: this.getPref("memory-sample-probability"),
|
||||||
|
allocationsMaxLogLength: this.getPref("memory-max-log-length")
|
||||||
let recording = this._createRecording({ withMemory, withTicks, withAllocations, probability, maxLogLength });
|
});
|
||||||
|
|
||||||
this.emit(EVENTS.RECORDING_WILL_START, recording);
|
this.emit(EVENTS.RECORDING_WILL_START, recording);
|
||||||
yield recording.startRecording({ withMemory, withTicks, withAllocations, probability, maxLogLength });
|
yield recording.startRecording();
|
||||||
this.emit(EVENTS.RECORDING_STARTED, recording);
|
this.emit(EVENTS.RECORDING_STARTED, recording);
|
||||||
|
|
||||||
this.setCurrentRecording(recording);
|
this.setCurrentRecording(recording);
|
||||||
@ -342,12 +342,10 @@ let PerformanceController = {
|
|||||||
* The newly created recording model.
|
* The newly created recording model.
|
||||||
*/
|
*/
|
||||||
_createRecording: function (options={}) {
|
_createRecording: function (options={}) {
|
||||||
let { withMemory, withTicks, withAllocations } = options;
|
let recording = new RecordingModel(Heritage.extend(options, {
|
||||||
let front = gFront;
|
front: gFront,
|
||||||
|
performance: window.performance
|
||||||
let recording = new RecordingModel(
|
}));
|
||||||
{ front, performance, withMemory, withTicks, withAllocations });
|
|
||||||
|
|
||||||
this._recordings.push(recording);
|
this._recordings.push(recording);
|
||||||
return recording;
|
return recording;
|
||||||
},
|
},
|
||||||
|
@ -25,7 +25,9 @@ function spawnTest () {
|
|||||||
} = yield front.startRecording({
|
} = yield front.startRecording({
|
||||||
withTicks: true,
|
withTicks: true,
|
||||||
withMemory: true,
|
withMemory: true,
|
||||||
withAllocations: true
|
withAllocations: true,
|
||||||
|
allocationsSampleProbability: +Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF),
|
||||||
|
allocationsMaxLogLength: Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF)
|
||||||
});
|
});
|
||||||
|
|
||||||
ok(typeof profilerStartTime === "number",
|
ok(typeof profilerStartTime === "number",
|
||||||
|
@ -24,7 +24,9 @@ function spawnTest () {
|
|||||||
} = yield front.startRecording({
|
} = yield front.startRecording({
|
||||||
withTicks: true,
|
withTicks: true,
|
||||||
withMemory: true,
|
withMemory: true,
|
||||||
withAllocations: true
|
withAllocations: true,
|
||||||
|
allocationsSampleProbability: +Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF),
|
||||||
|
allocationsMaxLogLength: Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF)
|
||||||
});
|
});
|
||||||
|
|
||||||
ok(typeof profilerStartTime === "number",
|
ok(typeof profilerStartTime === "number",
|
||||||
|
@ -10,17 +10,23 @@ let WAIT_TIME = 1000;
|
|||||||
function spawnTest () {
|
function spawnTest () {
|
||||||
let { target, front } = yield initBackend(SIMPLE_URL);
|
let { target, front } = yield initBackend(SIMPLE_URL);
|
||||||
|
|
||||||
let count = 0;
|
|
||||||
let counter = () => count++;
|
|
||||||
|
|
||||||
let {
|
let {
|
||||||
profilerStartTime,
|
profilerStartTime,
|
||||||
timelineStartTime,
|
timelineStartTime,
|
||||||
memoryStartTime
|
memoryStartTime
|
||||||
} = yield front.startRecording({
|
} = yield front.startRecording({
|
||||||
withAllocations: true
|
withAllocations: true,
|
||||||
|
allocationsSampleProbability: +Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF),
|
||||||
|
allocationsMaxLogLength: Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let allocationsCount = 0;
|
||||||
|
let allocationsCounter = () => allocationsCount++;
|
||||||
|
|
||||||
|
// Record allocation events to ensure it's called more than once
|
||||||
|
// so we know it's polling
|
||||||
|
front.on("allocations", allocationsCounter);
|
||||||
|
|
||||||
ok(typeof profilerStartTime === "number",
|
ok(typeof profilerStartTime === "number",
|
||||||
"The front.startRecording() emits a profiler start time.");
|
"The front.startRecording() emits a profiler start time.");
|
||||||
ok(typeof timelineStartTime === "number",
|
ok(typeof timelineStartTime === "number",
|
||||||
@ -28,13 +34,9 @@ function spawnTest () {
|
|||||||
ok(typeof memoryStartTime === "number",
|
ok(typeof memoryStartTime === "number",
|
||||||
"The front.startRecording() emits a memory start time.");
|
"The front.startRecording() emits a memory start time.");
|
||||||
|
|
||||||
// Record allocation events to ensure it's called more than once
|
|
||||||
// so we know it's polling
|
|
||||||
front.on("allocations", counter);
|
|
||||||
|
|
||||||
yield Promise.all([
|
yield Promise.all([
|
||||||
busyWait(WAIT_TIME),
|
busyWait(WAIT_TIME),
|
||||||
waitUntil(() => count > 1)
|
waitUntil(() => allocationsCount > 1)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@ -45,7 +47,7 @@ function spawnTest () {
|
|||||||
withAllocations: true
|
withAllocations: true
|
||||||
});
|
});
|
||||||
|
|
||||||
front.off("allocations", counter);
|
front.off("allocations", allocationsCounter);
|
||||||
|
|
||||||
ok(typeof profilerEndTime === "number",
|
ok(typeof profilerEndTime === "number",
|
||||||
"The front.stopRecording() emits a profiler end time.");
|
"The front.stopRecording() emits a profiler end time.");
|
||||||
@ -62,7 +64,7 @@ function spawnTest () {
|
|||||||
"The memoryEndTime is after memoryStartTime.");
|
"The memoryEndTime is after memoryStartTime.");
|
||||||
|
|
||||||
is((yield front._request("memory", "getState")), "detached",
|
is((yield front._request("memory", "getState")), "detached",
|
||||||
"memory actor is detached when stopping recording with allocations");
|
"Memory actor is detached when stopping recording with allocations.");
|
||||||
|
|
||||||
yield removeTab(target.tab);
|
yield removeTab(target.tab);
|
||||||
finish();
|
finish();
|
||||||
|
@ -10,11 +10,11 @@ function spawnTest () {
|
|||||||
let { EVENTS, PerformanceController, $, gFront } = panel.panelWin;
|
let { EVENTS, PerformanceController, $, gFront } = panel.panelWin;
|
||||||
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
Services.prefs.setBoolPref(MEMORY_PREF, true);
|
||||||
|
|
||||||
let originalProbability = Services.prefs.getCharPref("devtools.performance.memory.sample-probability");
|
let originalProbability = Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF);
|
||||||
let originalLogLength = Services.prefs.getIntPref("devtools.performance.memory.max-log-length");
|
let originalLogLength = Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF);
|
||||||
|
|
||||||
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", "0.213");
|
Services.prefs.setCharPref(MEMORY_SAMPLE_PROB_PREF, "0.213");
|
||||||
Services.prefs.setIntPref("devtools.performance.memory.max-log-length", 777777);
|
Services.prefs.setIntPref(MEMORY_MAX_LOG_LEN_PREF, 777777);
|
||||||
|
|
||||||
yield startRecording(panel);
|
yield startRecording(panel);
|
||||||
|
|
||||||
@ -26,8 +26,8 @@ function spawnTest () {
|
|||||||
is(maxLogLength, 777777, "allocations max log length option is set on memory actor");
|
is(maxLogLength, 777777, "allocations max log length option is set on memory actor");
|
||||||
|
|
||||||
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
||||||
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", originalProbability);
|
Services.prefs.setCharPref(MEMORY_SAMPLE_PROB_PREF, originalProbability);
|
||||||
Services.prefs.setIntPref("devtools.performance.memory.max-log-length", originalLogLength);
|
Services.prefs.setIntPref(MEMORY_MAX_LOG_LEN_PREF, originalLogLength);
|
||||||
yield teardown(panel);
|
yield teardown(panel);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,12 @@ const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-u
|
|||||||
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/performance/test/";
|
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/performance/test/";
|
||||||
const SIMPLE_URL = EXAMPLE_URL + "doc_simple-test.html";
|
const SIMPLE_URL = EXAMPLE_URL + "doc_simple-test.html";
|
||||||
|
|
||||||
|
const MEMORY_SAMPLE_PROB_PREF = "devtools.performance.memory.sample-probability";
|
||||||
|
const MEMORY_MAX_LOG_LEN_PREF = "devtools.performance.memory.max-log-length";
|
||||||
|
|
||||||
const FRAMERATE_PREF = "devtools.performance.ui.enable-framerate";
|
const FRAMERATE_PREF = "devtools.performance.ui.enable-framerate";
|
||||||
const MEMORY_PREF = "devtools.performance.ui.enable-memory";
|
const MEMORY_PREF = "devtools.performance.ui.enable-memory";
|
||||||
|
|
||||||
const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
|
const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
|
||||||
const IDLE_PREF = "devtools.performance.ui.show-idle-blocks";
|
const IDLE_PREF = "devtools.performance.ui.show-idle-blocks";
|
||||||
const INVERT_PREF = "devtools.performance.ui.invert-call-tree";
|
const INVERT_PREF = "devtools.performance.ui.invert-call-tree";
|
||||||
|
@ -9,6 +9,8 @@ const { Services } = Cu.import("resource://gre/modules/Services.jsm");
|
|||||||
const { require } =
|
const { require } =
|
||||||
Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
||||||
const QR = require("devtools/toolkit/qrcode/index");
|
const QR = require("devtools/toolkit/qrcode/index");
|
||||||
|
const PROPERTIES = "chrome://browser/locale/devtools/webide.properties";
|
||||||
|
const Strings = Services.strings.createBundle(PROPERTIES);
|
||||||
|
|
||||||
window.addEventListener("load", function onLoad() {
|
window.addEventListener("load", function onLoad() {
|
||||||
window.removeEventListener("load", onLoad);
|
window.removeEventListener("load", onLoad);
|
||||||
@ -31,6 +33,10 @@ function createQR(oob) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createToken(oob) {
|
function createToken(oob) {
|
||||||
|
let spacedCert = oob.sha256.replace(/:/g, " ").toLowerCase();
|
||||||
|
let certText = Strings.formatStringFromName("wifi_auth_cert",
|
||||||
|
[spacedCert], 1);
|
||||||
|
document.querySelector("#cert").textContent = certText;
|
||||||
let token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k;
|
let token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k;
|
||||||
document.querySelector("#token pre").textContent = token;
|
document.querySelector("#token pre").textContent = token;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
<h3 id="header">&wifi_auth_header;</h3>
|
<h3 id="header">&wifi_auth_header;</h3>
|
||||||
<div id="scan-request">&wifi_auth_scan_request;</div>
|
<div id="scan-request">&wifi_auth_scan_request;</div>
|
||||||
|
<div id="cert"></div>
|
||||||
|
|
||||||
<div id="qr-code">
|
<div id="qr-code">
|
||||||
<div id="qr-code-wrapper">
|
<div id="qr-code-wrapper">
|
||||||
|
@ -433,6 +433,7 @@ let AppManager = exports.AppManager = {
|
|||||||
// Fx <37 exposes chrome tab actors on RootActor
|
// Fx <37 exposes chrome tab actors on RootActor
|
||||||
// Fx >=37 exposes a dedicated actor via attachProcess request
|
// Fx >=37 exposes a dedicated actor via attachProcess request
|
||||||
return this.connection.client &&
|
return this.connection.client &&
|
||||||
|
this.connection.client.mainRoot &&
|
||||||
this.connection.client.mainRoot.traits.allowChromeProcess ||
|
this.connection.client.mainRoot.traits.allowChromeProcess ||
|
||||||
(this._listTabsResponse &&
|
(this._listTabsResponse &&
|
||||||
this._listTabsResponse.consoleActor);
|
this._listTabsResponse.consoleActor);
|
||||||
|
@ -77,3 +77,9 @@ status_unknown=UNKNOWN
|
|||||||
|
|
||||||
# Device preferences and settings
|
# Device preferences and settings
|
||||||
device_reset_default=Reset to default
|
device_reset_default=Reset to default
|
||||||
|
|
||||||
|
# WiFi Auth
|
||||||
|
# LOCALIZATION NOTE (wifi_auth_cert): Part of the dialog that instructs the
|
||||||
|
# user to transfer an authentication token to the server.
|
||||||
|
# %1$S: The client's cert fingerprint
|
||||||
|
wifi_auth_cert=My Cert: %1$S
|
||||||
|
@ -53,6 +53,8 @@ webrtcIndicator.sharingWindowWithNTabs.menuitem = Sharing a Window with #1 tab;S
|
|||||||
# LOCALIZATION NOTE (webrtcIndicator.sharingBrowserWithNTabs.menuitem):
|
# LOCALIZATION NOTE (webrtcIndicator.sharingBrowserWithNTabs.menuitem):
|
||||||
# Semicolon-separated list of plural forms. See:
|
# Semicolon-separated list of plural forms. See:
|
||||||
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||||
|
# This message is shown when the contents of a tab is shared during a WebRTC
|
||||||
|
# session, which currently is only possible with Loop/Hello.
|
||||||
webrtcIndicator.sharingBrowserWithNTabs.menuitem = Sharing a Tab with #1 tab;Sharing Tabs with #1 tabs
|
webrtcIndicator.sharingBrowserWithNTabs.menuitem = Sharing a Tab with #1 tab;Sharing Tabs with #1 tabs
|
||||||
# LOCALIZATION NOTE (webrtcIndicator.controlSharingOn.menuitem):
|
# LOCALIZATION NOTE (webrtcIndicator.controlSharingOn.menuitem):
|
||||||
# %S is the title of the tab using the share.
|
# %S is the title of the tab using the share.
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
@ -727,9 +727,11 @@ static const dom::ConstantSpec gWinProperties[] =
|
|||||||
// CreateFile attributes
|
// CreateFile attributes
|
||||||
INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
|
INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
|
||||||
INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
|
INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
|
||||||
|
INT_CONSTANT(FILE_ATTRIBUTE_HIDDEN),
|
||||||
INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
|
INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
|
||||||
INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
|
INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
|
||||||
INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
|
INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
|
||||||
|
INT_CONSTANT(FILE_ATTRIBUTE_SYSTEM),
|
||||||
INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
|
INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
|
||||||
INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
|
INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
|
||||||
|
|
||||||
|
@ -68,6 +68,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=987230
|
|||||||
let x = aOffsetX + win.mozInnerScreenX + rect.left;
|
let x = aOffsetX + win.mozInnerScreenX + rect.left;
|
||||||
let y = aOffsetY + win.mozInnerScreenY + rect.top;
|
let y = aOffsetY + win.mozInnerScreenY + rect.top;
|
||||||
|
|
||||||
|
info("Sending mousedown+up for offsets: " + aOffsetX + ", " + aOffsetY +
|
||||||
|
"; innerscreen: " + win.mozInnerScreenX + ", " + win.mozInnerScreenY +
|
||||||
|
"; rect: " + rect.left + ", " + rect.top + ".");
|
||||||
|
info("Resulting x, y, scale: " + x + ", " + y + ", " + scale);
|
||||||
|
info("Final params: " + (x * scale) + ", " + (y * scale));
|
||||||
utils.sendNativeMouseEvent(x * scale, y * scale, mouseDown, 0, null);
|
utils.sendNativeMouseEvent(x * scale, y * scale, mouseDown, 0, null);
|
||||||
utils.sendNativeMouseEvent(x * scale, y * scale, mouseUp, 0, null);
|
utils.sendNativeMouseEvent(x * scale, y * scale, mouseUp, 0, null);
|
||||||
}
|
}
|
||||||
@ -85,6 +90,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=987230
|
|||||||
let outsideOfFrameX = (window.mozInnerScreenX + frameRect.width + 100) * scale;
|
let outsideOfFrameX = (window.mozInnerScreenX + frameRect.width + 100) * scale;
|
||||||
let outsideOfFrameY = Math.max(0, window.mozInnerScreenY - 100) * scale;
|
let outsideOfFrameY = Math.max(0, window.mozInnerScreenY - 100) * scale;
|
||||||
|
|
||||||
|
info("Mousemove: " + outsideOfFrameX + ", " + outsideOfFrameY +
|
||||||
|
" (from innerscreen " + window.mozInnerScreenX + ", " + window.mozInnerScreenY +
|
||||||
|
" and rect width " + frameRect.width + " and scale " + scale + ")");
|
||||||
utils.sendNativeMouseEvent(outsideOfFrameX, outsideOfFrameY, mouseMove, 0, null);
|
utils.sendNativeMouseEvent(outsideOfFrameX, outsideOfFrameY, mouseMove, 0, null);
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1042,7 @@ pref("dom.webcomponents.enabled", false);
|
|||||||
pref("javascript.enabled", true);
|
pref("javascript.enabled", true);
|
||||||
pref("javascript.options.strict", false);
|
pref("javascript.options.strict", false);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
pref("javascript.options.strict.debug", true);
|
pref("javascript.options.strict.debug", false);
|
||||||
#endif
|
#endif
|
||||||
pref("javascript.options.baselinejit", true);
|
pref("javascript.options.baselinejit", true);
|
||||||
pref("javascript.options.ion", true);
|
pref("javascript.options.ion", true);
|
||||||
|
@ -37,6 +37,9 @@ Cu.importGlobalProperties(["URL"]);
|
|||||||
* Optional. A colon-separated list of scopes that the user has authorized
|
* Optional. A colon-separated list of scopes that the user has authorized
|
||||||
* @param {String} [options.parameters.action]
|
* @param {String} [options.parameters.action]
|
||||||
* Optional. If provided, should be either signup or signin.
|
* Optional. If provided, should be either signup or signin.
|
||||||
|
* @param {Boolean} [options.parameters.keys]
|
||||||
|
* Optional. If true then relier-specific encryption keys will be
|
||||||
|
* available in the second argument to onComplete.
|
||||||
* @param [authorizationEndpoint] {String}
|
* @param [authorizationEndpoint] {String}
|
||||||
* Optional authorization endpoint for the OAuth server
|
* Optional authorization endpoint for the OAuth server
|
||||||
* @constructor
|
* @constructor
|
||||||
@ -60,16 +63,26 @@ this.FxAccountsOAuthClient = function(options) {
|
|||||||
params.append("scope", this.parameters.scope || "");
|
params.append("scope", this.parameters.scope || "");
|
||||||
params.append("action", this.parameters.action || "signin");
|
params.append("action", this.parameters.action || "signin");
|
||||||
params.append("webChannelId", this._webChannelId);
|
params.append("webChannelId", this._webChannelId);
|
||||||
|
if (this.parameters.keys) {
|
||||||
|
params.append("keys", "true");
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.FxAccountsOAuthClient.prototype = {
|
this.FxAccountsOAuthClient.prototype = {
|
||||||
/**
|
/**
|
||||||
* Function that gets called once the OAuth flow is complete.
|
* Function that gets called once the OAuth flow is complete.
|
||||||
* The callback will receive null as it's argument if there is a state mismatch or an object with
|
* The callback will receive an object with code and state properties.
|
||||||
* code and state properties otherwise.
|
* If the keys parameter was specified and true, the callback will receive
|
||||||
|
* a second argument with kAr and kBr properties.
|
||||||
*/
|
*/
|
||||||
onComplete: null,
|
onComplete: null,
|
||||||
|
/**
|
||||||
|
* Function that gets called if there is an error during the OAuth flow,
|
||||||
|
* for example due to a state mismatch.
|
||||||
|
* The callback will receive an Error object as its argument.
|
||||||
|
*/
|
||||||
|
onError: null,
|
||||||
/**
|
/**
|
||||||
* Configuration object that stores all OAuth parameters.
|
* Configuration object that stores all OAuth parameters.
|
||||||
*/
|
*/
|
||||||
@ -116,6 +129,7 @@ this.FxAccountsOAuthClient.prototype = {
|
|||||||
*/
|
*/
|
||||||
tearDown: function() {
|
tearDown: function() {
|
||||||
this.onComplete = null;
|
this.onComplete = null;
|
||||||
|
this.onError = null;
|
||||||
this._complete = true;
|
this._complete = true;
|
||||||
this._channel.stopListening();
|
this._channel.stopListening();
|
||||||
this._channel = null;
|
this._channel = null;
|
||||||
@ -160,21 +174,37 @@ this.FxAccountsOAuthClient.prototype = {
|
|||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "oauth_complete":
|
case "oauth_complete":
|
||||||
// validate the state parameter and call onComplete
|
// validate the returned state and call onComplete or onError
|
||||||
let result = null;
|
let result = null;
|
||||||
if (this.parameters.state === data.state) {
|
let err = null;
|
||||||
|
|
||||||
|
if (this.parameters.state !== data.state) {
|
||||||
|
err = new Error("OAuth flow failed. State doesn't match");
|
||||||
|
} else if (this.parameters.keys && !data.keys) {
|
||||||
|
err = new Error("OAuth flow failed. Keys were not returned");
|
||||||
|
} else {
|
||||||
result = {
|
result = {
|
||||||
code: data.code,
|
code: data.code,
|
||||||
state: data.state
|
state: data.state
|
||||||
};
|
};
|
||||||
log.debug("OAuth flow completed.");
|
|
||||||
} else {
|
|
||||||
log.debug("OAuth flow failed. State doesn't match");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.onComplete) {
|
if (err) {
|
||||||
this.onComplete(result);
|
log.debug(err.message);
|
||||||
|
if (this.onError) {
|
||||||
|
this.onError(err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.debug("OAuth flow completed.");
|
||||||
|
if (this.onComplete) {
|
||||||
|
if (this.parameters.keys) {
|
||||||
|
this.onComplete(result, data.keys);
|
||||||
|
} else {
|
||||||
|
this.onComplete(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// onComplete will be called for this client only once
|
// onComplete will be called for this client only once
|
||||||
// calling onComplete again will result in a failure of the OAuth flow
|
// calling onComplete again will result in a failure of the OAuth flow
|
||||||
this.tearDown();
|
this.tearDown();
|
||||||
|
@ -69,26 +69,24 @@ this.BrowserTestUtils = {
|
|||||||
* Resolves with the new window once it is loaded.
|
* Resolves with the new window once it is loaded.
|
||||||
*/
|
*/
|
||||||
openNewBrowserWindow(options) {
|
openNewBrowserWindow(options) {
|
||||||
return new Promise(resolve => {
|
let argString = Cc["@mozilla.org/supports-string;1"].
|
||||||
let argString = Cc["@mozilla.org/supports-string;1"].
|
createInstance(Ci.nsISupportsString);
|
||||||
createInstance(Ci.nsISupportsString);
|
argString.data = "";
|
||||||
argString.data = "";
|
let features = "chrome,dialog=no,all";
|
||||||
let features = "chrome,dialog=no,all";
|
|
||||||
|
|
||||||
if (options && options.private || false) {
|
if (options && options.private || false) {
|
||||||
features += ",private";
|
features += ",private";
|
||||||
}
|
}
|
||||||
|
|
||||||
let win = Services.ww.openWindow(
|
let win = Services.ww.openWindow(
|
||||||
null, Services.prefs.getCharPref("browser.chromeURL"), "_blank",
|
null, Services.prefs.getCharPref("browser.chromeURL"), "_blank",
|
||||||
features, argString);
|
features, argString);
|
||||||
|
|
||||||
// Wait for browser-delayed-startup-finished notification, it indicates
|
// Wait for browser-delayed-startup-finished notification, it indicates
|
||||||
// that the window has loaded completely and is ready to be used for
|
// that the window has loaded completely and is ready to be used for
|
||||||
// testing.
|
// testing.
|
||||||
TestUtils.topicObserved("browser-delayed-startup-finished", win).then(
|
return TestUtils.topicObserved("browser-delayed-startup-finished",
|
||||||
() => resolve(win));
|
subject => subject == win).then(() => win);
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,20 +32,34 @@ this.TestUtils = {
|
|||||||
*
|
*
|
||||||
* @param {string} topic
|
* @param {string} topic
|
||||||
* The topic to observe.
|
* The topic to observe.
|
||||||
* @param {*} subject
|
* @param {function} checkFn [optional]
|
||||||
* A value to check the notification subject against. Only a
|
* Called with (subject, data) as arguments, should return true if the
|
||||||
* notification with a matching subject will cause the promise to
|
* notification is the expected one, or false if it should be ignored
|
||||||
* resolve.
|
* and listening should continue. If not specified, the first
|
||||||
|
* notification for the specified topic resolves the returned promise.
|
||||||
|
*
|
||||||
|
* @note Because this function is intended for testing, any error in checkFn
|
||||||
|
* will cause the returned promise to be rejected instead of waiting for
|
||||||
|
* the next notification, since this is probably a bug in the test.
|
||||||
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
* Resolves with the data provided when the topic has been observed.
|
* @resolves The array [subject, data] from the observed notification.
|
||||||
*/
|
*/
|
||||||
topicObserved(topic, subject=null) {
|
topicObserved(topic, checkFn) {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve, reject) => {
|
||||||
Services.obs.addObserver(function observer(observedSubject, topic, data) {
|
Services.obs.addObserver(function observer(subject, topic, data) {
|
||||||
if (subject !== null && subject !== observedSubject) { return; }
|
try {
|
||||||
|
try {
|
||||||
Services.obs.removeObserver(observer, topic);
|
if (checkFn && !checkFn(subject, data)) {
|
||||||
resolve(data);
|
return;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Services.obs.removeObserver(observer, topic);
|
||||||
|
}
|
||||||
|
resolve([subject, data]);
|
||||||
|
} catch (ex) {
|
||||||
|
reject(ex);
|
||||||
|
}
|
||||||
}, topic, false);
|
}, topic, false);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -210,7 +210,8 @@ exports.Error = OSError;
|
|||||||
*/
|
*/
|
||||||
let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
|
let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
|
||||||
winBirthDate,
|
winBirthDate,
|
||||||
lastAccessDate, lastWriteDate) {
|
lastAccessDate, lastWriteDate,
|
||||||
|
winAttributes) {
|
||||||
this._path = path;
|
this._path = path;
|
||||||
this._isDir = isDir;
|
this._isDir = isDir;
|
||||||
this._isSymLink = isSymLink;
|
this._isSymLink = isSymLink;
|
||||||
@ -218,6 +219,7 @@ let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
|
|||||||
this._winBirthDate = winBirthDate;
|
this._winBirthDate = winBirthDate;
|
||||||
this._lastAccessDate = lastAccessDate;
|
this._lastAccessDate = lastAccessDate;
|
||||||
this._lastModificationDate = lastWriteDate;
|
this._lastModificationDate = lastWriteDate;
|
||||||
|
this._winAttributes = winAttributes;
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractInfo.prototype = {
|
AbstractInfo.prototype = {
|
||||||
@ -285,6 +287,15 @@ AbstractInfo.prototype = {
|
|||||||
*/
|
*/
|
||||||
get lastModificationDate() {
|
get lastModificationDate() {
|
||||||
return this._lastModificationDate;
|
return this._lastModificationDate;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* The Object with following boolean properties of this file.
|
||||||
|
* {readOnly, system, hidden}
|
||||||
|
*
|
||||||
|
* @type {object}
|
||||||
|
*/
|
||||||
|
get winAttributes() {
|
||||||
|
return this._winAttributes;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
exports.AbstractInfo = AbstractInfo;
|
exports.AbstractInfo = AbstractInfo;
|
||||||
|
@ -236,10 +236,19 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the file's access permission bits.
|
* Set the file's access permission bits.
|
||||||
* Not implemented for Windows (bug 1022816).
|
|
||||||
*/
|
*/
|
||||||
File.prototype.setPermissions = function setPermissions(options = {}) {
|
File.prototype.setPermissions = function setPermissions(options = {}) {
|
||||||
// do nothing
|
if (!("winAttributes" in options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let oldAttributes = WinFile.GetFileAttributes(this._path);
|
||||||
|
if (oldAttributes == Const.INVALID_FILE_ATTRIBUTES) {
|
||||||
|
throw new File.Error("setPermissions", ctypes.winLastError, this._path);
|
||||||
|
}
|
||||||
|
let newAttributes = toFileAttributes(options.winAttributes, oldAttributes);
|
||||||
|
throw_on_zero("setPermissions",
|
||||||
|
WinFile.SetFileAttributes(this._path, newAttributes),
|
||||||
|
this._path);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -904,9 +913,14 @@
|
|||||||
|
|
||||||
let value = ctypes.UInt64.join(stat.nFileSizeHigh, stat.nFileSizeLow);
|
let value = ctypes.UInt64.join(stat.nFileSizeHigh, stat.nFileSizeLow);
|
||||||
let size = Type.uint64_t.importFromC(value);
|
let size = Type.uint64_t.importFromC(value);
|
||||||
|
let winAttributes = {
|
||||||
|
readOnly: !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_READONLY),
|
||||||
|
system: !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_SYSTEM),
|
||||||
|
hidden: !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_HIDDEN),
|
||||||
|
};
|
||||||
|
|
||||||
SysAll.AbstractInfo.call(this, path, isDir, isSymLink, size,
|
SysAll.AbstractInfo.call(this, path, isDir, isSymLink, size,
|
||||||
winBirthDate, lastAccessDate, lastWriteDate);
|
winBirthDate, lastAccessDate, lastWriteDate, winAttributes);
|
||||||
};
|
};
|
||||||
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
|
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
|
||||||
|
|
||||||
@ -963,10 +977,19 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the file's access permission bits.
|
* Set the file's access permission bits.
|
||||||
* Not implemented for Windows (bug 1022816).
|
|
||||||
*/
|
*/
|
||||||
File.setPermissions = function setPermissions(path, options = {}) {
|
File.setPermissions = function setPermissions(path, options = {}) {
|
||||||
// do nothing
|
if (!("winAttributes" in options)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let oldAttributes = WinFile.GetFileAttributes(path);
|
||||||
|
if (oldAttributes == Const.INVALID_FILE_ATTRIBUTES) {
|
||||||
|
throw new File.Error("setPermissions", ctypes.winLastError, path);
|
||||||
|
}
|
||||||
|
let newAttributes = toFileAttributes(options.winAttributes, oldAttributes);
|
||||||
|
throw_on_zero("setPermissions",
|
||||||
|
WinFile.SetFileAttributes(path, newAttributes),
|
||||||
|
path);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1175,6 +1198,34 @@
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper used by both versions of setPermissions
|
||||||
|
*/
|
||||||
|
function toFileAttributes(winAttributes, oldDwAttrs) {
|
||||||
|
if ("readOnly" in winAttributes) {
|
||||||
|
if (winAttributes.readOnly) {
|
||||||
|
oldDwAttrs |= Const.FILE_ATTRIBUTE_READONLY;
|
||||||
|
} else {
|
||||||
|
oldDwAttrs &= ~Const.FILE_ATTRIBUTE_READONLY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("system" in winAttributes) {
|
||||||
|
if (winAttributes.system) {
|
||||||
|
oldDwAttrs |= Const.FILE_ATTRIBUTE_SYSTEM;
|
||||||
|
} else {
|
||||||
|
oldDwAttrs &= ~Const.FILE_ATTRIBUTE_SYSTEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("hidden" in winAttributes) {
|
||||||
|
if (winAttributes.hidden) {
|
||||||
|
oldDwAttrs |= Const.FILE_ATTRIBUTE_HIDDEN;
|
||||||
|
} else {
|
||||||
|
oldDwAttrs &= ~Const.FILE_ATTRIBUTE_HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oldDwAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
File.Win = exports.OS.Win.File;
|
File.Win = exports.OS.Win.File;
|
||||||
File.Error = SysAll.Error;
|
File.Error = SysAll.Error;
|
||||||
exports.OS.File = File;
|
exports.OS.File = File;
|
||||||
|
@ -0,0 +1,114 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test to ensure that OS.File.setPermissions and
|
||||||
|
* OS.File.prototype.setPermissions are all working correctly.
|
||||||
|
* (see bug 1022816)
|
||||||
|
* The manifest tests on Windows.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Sequence of setPermission parameters.
|
||||||
|
let testSequence = [
|
||||||
|
[ { winAttributes: { readOnly: true, system: true, hidden: true } },
|
||||||
|
{ readOnly: true, system: true, hidden: true } ],
|
||||||
|
[ { winAttributes: { readOnly: false } },
|
||||||
|
{ readOnly: false, system: true, hidden: true } ],
|
||||||
|
[ { winAttributes: { system: false } },
|
||||||
|
{ readOnly: false, system: false, hidden: true } ],
|
||||||
|
[ { winAttributes: { hidden: false } },
|
||||||
|
{ readOnly: false, system: false, hidden: false } ],
|
||||||
|
[ { winAttributes: {readOnly: true, system: false, hidden: false} },
|
||||||
|
{ readOnly: true, system: false, hidden: false } ],
|
||||||
|
[ { winAttributes: {readOnly: false, system: true, hidden: false} },
|
||||||
|
{ readOnly: false, system: true, hidden: false } ],
|
||||||
|
[ { winAttributes: {readOnly: false, system: false, hidden: true} },
|
||||||
|
{ readOnly: false, system: false, hidden: true } ],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Test application to paths.
|
||||||
|
add_task(function* test_path_setPermissions() {
|
||||||
|
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||||
|
"test_osfile_win_async_setPermissions_path.tmp");
|
||||||
|
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (let [options, attributesExpected] of testSequence) {
|
||||||
|
if (options !== null) {
|
||||||
|
do_print("Setting permissions to " + JSON.stringify(options));
|
||||||
|
yield OS.File.setPermissions(path, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
let stat = yield OS.File.stat(path);
|
||||||
|
do_print("Got stat winAttributes: " + JSON.stringify(stat.winAttributes));
|
||||||
|
|
||||||
|
do_check_eq(stat.winAttributes.readOnly, attributesExpected.readOnly);
|
||||||
|
do_check_eq(stat.winAttributes.system, attributesExpected.system);
|
||||||
|
do_check_eq(stat.winAttributes.hidden, attributesExpected.hidden);
|
||||||
|
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
yield OS.File.remove(path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test application to open files.
|
||||||
|
add_task(function* test_file_setPermissions() {
|
||||||
|
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||||
|
"test_osfile_win_async_setPermissions_file.tmp");
|
||||||
|
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||||
|
|
||||||
|
try {
|
||||||
|
let fd = yield OS.File.open(path, { write: true });
|
||||||
|
try {
|
||||||
|
for (let [options, attributesExpected] of testSequence) {
|
||||||
|
if (options !== null) {
|
||||||
|
do_print("Setting permissions to " + JSON.stringify(options));
|
||||||
|
yield fd.setPermissions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
let stat = yield fd.stat();
|
||||||
|
do_print("Got stat winAttributes: " + JSON.stringify(stat.winAttributes));
|
||||||
|
do_check_eq(stat.winAttributes.readOnly, attributesExpected.readOnly);
|
||||||
|
do_check_eq(stat.winAttributes.system, attributesExpected.system);
|
||||||
|
do_check_eq(stat.winAttributes.hidden, attributesExpected.hidden);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
yield fd.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
yield OS.File.remove(path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test application to Check setPermissions on a non-existant file path.
|
||||||
|
add_task(function* test_non_existant_file_path_setPermissions() {
|
||||||
|
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||||
|
"test_osfile_win_async_setPermissions_path.tmp");
|
||||||
|
Assert.rejects(OS.File.setPermissions(path, {winAttributes: {readOnly: true}}),
|
||||||
|
/The system cannot find the file specified/,
|
||||||
|
"setPermissions failed as expected on a non-existant file path");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test application to Check setPermissions on a invalid file handle.
|
||||||
|
add_task(function* test_closed_file_handle_setPermissions() {
|
||||||
|
let path = OS.Path.join(OS.Constants.Path.tmpDir,
|
||||||
|
"test_osfile_win_async_setPermissions_path.tmp");
|
||||||
|
yield OS.File.writeAtomic(path, new Uint8Array(1));
|
||||||
|
|
||||||
|
try {
|
||||||
|
let fd = yield OS.File.open(path, { write: true });
|
||||||
|
yield fd.close();
|
||||||
|
Assert.rejects(fd.setPermissions(path, {winAttributes: {readOnly: true}}),
|
||||||
|
/The handle is invalid/,
|
||||||
|
"setPermissions failed as expected on a invalid file handle");
|
||||||
|
} finally {
|
||||||
|
yield OS.File.remove(path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
run_next_test();
|
||||||
|
}
|
@ -46,3 +46,7 @@ support-files =
|
|||||||
# filesystem backing /mnt/sdcard (not worth trying to fix).
|
# filesystem backing /mnt/sdcard (not worth trying to fix).
|
||||||
[test_osfile_async_setPermissions.js]
|
[test_osfile_async_setPermissions.js]
|
||||||
skip-if = os == "win" || os == "android"
|
skip-if = os == "win" || os == "android"
|
||||||
|
|
||||||
|
# Windows test
|
||||||
|
[test_osfile_win_async_setPermissions.js]
|
||||||
|
skip-if = os != "win"
|
||||||
|
@ -6546,6 +6546,52 @@
|
|||||||
"kind": "boolean",
|
"kind": "boolean",
|
||||||
"description": "Was WebIDE's debug button used during this runtime connection?"
|
"description": "Was WebIDE's debug button used during this runtime connection?"
|
||||||
},
|
},
|
||||||
|
"DEVTOOLS_OS_ENUMERATED_PER_USER": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "enumerated",
|
||||||
|
"n_values": 13,
|
||||||
|
"description": "OS of DevTools user (0:Windows XP, 1:Windows Vista, 2:Windows 7, 3:Windows 8, 4:Windows 8.1, 5:OSX, 6:Linux 7:reserved, 8:reserved, 9:reserved, 10:reserved, 11:reserved, 12:other)"
|
||||||
|
},
|
||||||
|
"DEVTOOLS_OS_IS_64_BITS_PER_USER": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "enumerated",
|
||||||
|
"n_values": 3,
|
||||||
|
"description": "OS bit size of DevTools user (0:32bit, 1:64bit, 2:128bit)"
|
||||||
|
},
|
||||||
|
"DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "enumerated",
|
||||||
|
"n_values": 13,
|
||||||
|
"description": "Screen resolution of DevTools user (0:lower, 1:800x600, 2:1024x768, 3:1280x800, 4:1280x1024, 5:1366x768, 6:1440x900, 7:1920x1080, 8:2560×1440, 9:2560×1600, 10:2880x1800, 11:other, 12:higher)"
|
||||||
|
},
|
||||||
|
"DEVTOOLS_TABS_OPEN_PEAK_LINEAR": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "linear",
|
||||||
|
"high": "101",
|
||||||
|
"n_buckets": 100,
|
||||||
|
"description": "The peak number of open tabs in all windows for a session for devtools users."
|
||||||
|
},
|
||||||
|
"DEVTOOLS_TABS_OPEN_AVERAGE_EXPONENTIAL": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "exponential",
|
||||||
|
"high": "101",
|
||||||
|
"n_buckets": "100",
|
||||||
|
"description": "The mean number of open tabs in all windows for a session for devtools users."
|
||||||
|
},
|
||||||
|
"DEVTOOLS_TABS_PINNED_PEAK_EXPONENTIAL": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "exponential",
|
||||||
|
"high": "101",
|
||||||
|
"n_buckets": "100",
|
||||||
|
"description": "The peak number of pinned tabs (app tabs) in all windows for a session for devtools users."
|
||||||
|
},
|
||||||
|
"DEVTOOLS_TABS_PINNED_AVERAGE_LINEAR": {
|
||||||
|
"expires_in_version": "never",
|
||||||
|
"kind": "linear",
|
||||||
|
"high": "101",
|
||||||
|
"n_buckets": "100",
|
||||||
|
"description": "The mean number of pinned tabs (app tabs) in all windows for a session for devtools users."
|
||||||
|
},
|
||||||
"BROWSER_IS_USER_DEFAULT": {
|
"BROWSER_IS_USER_DEFAULT": {
|
||||||
"expires_in_version": "never",
|
"expires_in_version": "never",
|
||||||
"kind": "boolean",
|
"kind": "boolean",
|
||||||
|
@ -540,3 +540,19 @@ let Printing = {
|
|||||||
}
|
}
|
||||||
Printing.init();
|
Printing.init();
|
||||||
|
|
||||||
|
function SwitchDocumentDirection(aWindow) {
|
||||||
|
// document.dir can also be "auto", in which case it won't change
|
||||||
|
if (aWindow.document.dir == "ltr" || aWindow.document.dir == "") {
|
||||||
|
aWindow.document.dir = "rtl";
|
||||||
|
} else if (aWindow.document.dir == "rtl") {
|
||||||
|
aWindow.document.dir = "ltr";
|
||||||
|
}
|
||||||
|
for (let run = 0; run < aWindow.frames.length; run++) {
|
||||||
|
SwitchDocumentDirection(aWindow.frames[run]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addMessageListener("SwitchDocumentDirection", () => {
|
||||||
|
SwitchDocumentDirection(content.window);
|
||||||
|
});
|
||||||
|
|
||||||
|
@ -909,6 +909,17 @@ nsXULAppInfo::GetAccessibilityIsUIA(bool* aResult)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NS_IMETHODIMP
|
||||||
|
nsXULAppInfo::GetIs64Bit(bool* aResult)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_64BIT_BUILD
|
||||||
|
*aResult = true;
|
||||||
|
#else
|
||||||
|
*aResult = false;
|
||||||
|
#endif
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
nsXULAppInfo::EnsureContentProcess()
|
nsXULAppInfo::EnsureContentProcess()
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ bool BrowserTabsRemoteAutostart();
|
|||||||
* stable/frozen, please contact Benjamin Smedberg.
|
* stable/frozen, please contact Benjamin Smedberg.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[scriptable, uuid(fb861ca6-426f-4edf-844e-bbabec9bbc1a)]
|
[scriptable, uuid(5754b56e-f392-426d-aec0-3ba7c49aff32)]
|
||||||
interface nsIXULRuntime : nsISupports
|
interface nsIXULRuntime : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -109,6 +109,11 @@ interface nsIXULRuntime : nsISupports
|
|||||||
*/
|
*/
|
||||||
readonly attribute boolean accessibilityIsUIA;
|
readonly attribute boolean accessibilityIsUIA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the current Firefox build is 64-bit.
|
||||||
|
*/
|
||||||
|
readonly attribute boolean is64Bit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal the apprunner to invalidate caches on the next restart.
|
* Signal the apprunner to invalidate caches on the next restart.
|
||||||
* This will cause components to be autoregistered and all
|
* This will cause components to be autoregistered and all
|
||||||
|