Merge fx-team to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-03-13 16:09:58 -04:00
commit 125d500a93
54 changed files with 790 additions and 129 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}); });
} }

View File

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

View File

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

View File

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

View File

@ -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");

View File

@ -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 () {

View File

@ -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();
}
}, },
/** /**

View File

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

View File

@ -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];
}); });

View File

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

View File

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

View File

@ -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;
}, },

View File

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

View File

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

View File

@ -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();

View File

@ -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();
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

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

View File

@ -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();
} }

View File

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

View File

@ -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();

View File

@ -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);
});
}, },
/** /**

View File

@ -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);
}); });
}, },

View File

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

View File

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

View 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();
}

View File

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

View File

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

View File

@ -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);
});

View File

@ -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()
{ {

View File

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