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
*/
var allTabs = {
get toolbarButton() document.getElementById("alltabs-button"),
get canOpen() isElementVisible(this.toolbarButton),
get toolbarButton() {
return document.getElementById("alltabs-button");
},
get canOpen() {
return isElementVisible(this.toolbarButton);
},
open: function allTabs_open() {
if (this.canOpen) {

View File

@ -317,7 +317,9 @@
hidden="true"
label="&bidiSwitchPageDirectionItem.label;"
accesskey="&bidiSwitchPageDirectionItem.accesskey;"
oncommand="SwitchDocumentDirection(window.content)"/>
oncommand="gBrowser.selectedBrowser
.messageManager
.sendAsyncMessage('SwitchDocumentDirection');"/>
</menupopup>
</menu>

View File

@ -6489,17 +6489,6 @@ function AddKeywordForSearchField() {
}, 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)
{
try {

View File

@ -1005,12 +1005,11 @@ nsContextMenu.prototype = {
},
viewImageDesc: function(e) {
var doc = this.target.ownerDocument;
urlSecurityCheck(this.imageDescURL,
this.browser.contentPrincipal,
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
openUILink(this.imageDescURL, e, { disallowInheritPrincipal: true,
referrerURI: doc.documentURIObject });
referrerURI: gContextMenuContentData.documentURIObject });
},
viewFrameInfo: function() {
@ -1080,9 +1079,8 @@ nsContextMenu.prototype = {
urlSecurityCheck(this.bgImageURL,
this.browser.contentPrincipal,
Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT);
var doc = this.target.ownerDocument;
openUILink(this.bgImageURL, e, { disallowInheritPrincipal: true,
referrerURI: doc.documentURIObject });
referrerURI: gContextMenuContentData.documentURIObject });
},
disableSetDesktopBackground: function() {
@ -1379,10 +1377,10 @@ nsContextMenu.prototype = {
// Let's try to unescape it using a character set
// in case the address is not ASCII.
try {
var characterSet = this.target.ownerDocument.characterSet;
const textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
getService(Ci.nsITextToSubURI);
addresses = textToSubURI.unEscapeURIForUI(characterSet, addresses);
addresses = textToSubURI.unEscapeURIForUI(gContextMenuContentData.charSet,
addresses);
}
catch(ex) {
// Do nothing.
@ -1651,7 +1649,7 @@ nsContextMenu.prototype = {
},
switchPageDirection: function CM_switchPageDirection() {
SwitchDocumentDirection(this.browser.contentWindowAsCPOW);
this.browser.messageManager.sendAsyncMessage("SwitchDocumentDirection");
},
mediaCommand : function CM_mediaCommand(command, data) {

View File

@ -12,6 +12,7 @@ support-files =
browser_bug678392-2.html
browser_bug970746.xhtml
browser_fxa_oauth.html
browser_fxa_oauth_with_keys.html
browser_fxa_profile_channel.html
browser_registerProtocolHandler_notification.html
browser_ssl_error_reports_content.js

View File

@ -17,11 +17,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsOAuthClient",
const HTTP_PATH = "http://example.com";
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 = [
{
desc: "FxA OAuth - should open a new tab, complete OAuth flow",
run: function* () {
run: function () {
return new Promise(function(resolve, reject) {
let tabOpened = false;
let properUrl = "http://example.com/browser/browser/base/content/test/general/browser_fxa_oauth.html";
@ -71,6 +72,169 @@ let gTests = [
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();
});
}

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(
client => {
client.onComplete = this._fxAOAuthComplete.bind(this, deferred);
client.onError = this._fxAOAuthError.bind(this, deferred);
client.launchWebFlow();
},
error => {
@ -1003,18 +1004,24 @@ let MozLoopServiceInternal = {
/**
* 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)
*/
_fxAOAuthComplete: function(deferred, result) {
gFxAOAuthClientPromise = null;
// Note: The state was already verified in FxAccountsOAuthClient.
if (result) {
deferred.resolve(result);
} else {
deferred.reject("Invalid token data");
}
deferred.resolve(result);
},
/**
* 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);

View File

@ -133,8 +133,7 @@
completedefaultindex="true"
tabscrolling="true"
showcommentcolumn="true"
placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"
maxlength="1000"/>
placeholder="&editBookmarkOverlay.tagsEmptyDesc.label;"/>
<button id="editBMPanel_tagsSelectorExpander"
class="expander-down"
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);
SimpleTest.requestCompleteLog();
function setupFakeHandler() {
let info = gMimeSvc.getFromTypeAndExtension("text/plain", "foo.txt");
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) {
element.style.width = element.getAttribute(isInSubdialog ? "subdialogWidth" : "dialogWidth");
}
onClearHistoryChanged();
this.onClearHistoryChanged();
},
onClearHistoryChanged: function () {

View File

@ -27,6 +27,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
"resource://gre/modules/devtools/dbg-client.jsm");
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 MAX_ORDINAL = 99;
@ -467,6 +474,23 @@ DevTools.prototype = {
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.
*/
@ -487,6 +511,9 @@ DevTools.prototype = {
this.unregisterTool(key, true);
}
this._pingTelemetry();
this._telemetry = null;
// Cleaning down the toolboxes: i.e.
// for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
// Is taken care of by the gDevToolsBrowser.forgetBrowserWindow
@ -522,6 +549,13 @@ let gDevToolsBrowser = {
*/
_trackedBrowserWindows: new Set(),
_tabStats: {
peakOpen: 0,
peakPinned: 0,
histOpen: [],
histPinned: []
},
/**
* This function is for the benefit of Tools:DevToolbox in
* browser/base/content/browser-sets.inc and should not be used outside
@ -819,9 +853,12 @@ let gDevToolsBrowser = {
broadcaster.removeAttribute("key");
}
let tabContainer = win.document.getElementById("tabbrowser-tabs")
tabContainer.addEventListener("TabSelect",
gDevToolsBrowser._updateMenuCheckbox, false);
let tabContainer = win.document.getElementById("tabbrowser-tabs");
tabContainer.addEventListener("TabSelect", this, 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")
tabContainer.removeEventListener("TabSelect",
gDevToolsBrowser._updateMenuCheckbox, false);
let tabContainer = win.document.getElementById("tabbrowser-tabs");
tabContainer.removeEventListener("TabSelect", this, 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 MIN_ZOOM = 0.5;
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 {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.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
// addons that have manually inserted toolbarbuttons into DOM.
// (By default, supported target is only local tab)
@ -334,7 +350,7 @@ Toolbox.prototype = {
let buttonsPromise = this._buildButtons();
this._telemetry.toolOpened("toolbox");
this._pingTelemetry();
this.selectTool(this._defaultToolId).then(panel => {
@ -359,7 +375,7 @@ Toolbox.prototype = {
// Load the toolbox-level actor fronts and utilities now
this._target.makeRemote().then(() => {
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);
domHelper.onceDOMReady(domReady);
});
@ -368,6 +384,16 @@ Toolbox.prototype = {
}).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
* "pref-changed" events.
@ -1575,6 +1601,41 @@ Toolbox.prototype = {
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.
*

View File

@ -139,7 +139,6 @@ function initNetMonitor(aUrl, aWindow) {
let tab = yield addTab(aUrl);
info("Net tab added successfully: " + aUrl);
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
let target = TargetFactory.forTab(tab);
yield target.makeRemote();
@ -151,6 +150,7 @@ function initNetMonitor(aUrl, aWindow) {
let toolbox = yield gDevTools.showToolbox(target, "netmonitor");
info("Netork monitor pane shown successfully.");
let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;
let monitor = toolbox.getCurrentPanel();
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) {
if (!options.withAllocations) {
return 0;
}
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();
return memoryStartTime;
}),
/**
* Stops the timeline actor, if necessary.
* Stops recording allocations in the memory actor, if necessary.
*/
_stopMemory: Task.async(function *(options) {
if (!options.withAllocations) {

View File

@ -24,7 +24,9 @@ const RecordingModel = function (options={}) {
this._configuration = {
withTicks: options.withTicks || 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.
*
* @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.
// 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
// the local time and use it to compute a reasonable elapsed time.
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._timelineStartTime = info.timelineStartTime;
this._memoryStartTime = info.memoryStartTime;

View File

@ -261,16 +261,16 @@ let PerformanceController = {
* when the front has started to record.
*/
startRecording: Task.async(function *() {
let withMemory = this.getOption("enable-memory");
let withTicks = this.getOption("enable-framerate");
let withAllocations = this.getOption("enable-memory");
let probability = this.getPref("memory-sample-probability");
let maxLogLength = this.getPref("memory-max-log-length");
let recording = this._createRecording({ withMemory, withTicks, withAllocations, probability, maxLogLength });
let recording = this._createRecording({
withMemory: this.getOption("enable-memory"),
withTicks: this.getOption("enable-framerate"),
withAllocations: this.getOption("enable-memory"),
allocationsSampleProbability: this.getPref("memory-sample-probability"),
allocationsMaxLogLength: this.getPref("memory-max-log-length")
});
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.setCurrentRecording(recording);
@ -342,12 +342,10 @@ let PerformanceController = {
* The newly created recording model.
*/
_createRecording: function (options={}) {
let { withMemory, withTicks, withAllocations } = options;
let front = gFront;
let recording = new RecordingModel(
{ front, performance, withMemory, withTicks, withAllocations });
let recording = new RecordingModel(Heritage.extend(options, {
front: gFront,
performance: window.performance
}));
this._recordings.push(recording);
return recording;
},

View File

@ -25,7 +25,9 @@ function spawnTest () {
} = yield front.startRecording({
withTicks: 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",

View File

@ -24,7 +24,9 @@ function spawnTest () {
} = yield front.startRecording({
withTicks: 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",

View File

@ -10,17 +10,23 @@ let WAIT_TIME = 1000;
function spawnTest () {
let { target, front } = yield initBackend(SIMPLE_URL);
let count = 0;
let counter = () => count++;
let {
profilerStartTime,
timelineStartTime,
memoryStartTime
} = 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",
"The front.startRecording() emits a profiler start time.");
ok(typeof timelineStartTime === "number",
@ -28,13 +34,9 @@ function spawnTest () {
ok(typeof memoryStartTime === "number",
"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([
busyWait(WAIT_TIME),
waitUntil(() => count > 1)
waitUntil(() => allocationsCount > 1)
]);
let {
@ -45,7 +47,7 @@ function spawnTest () {
withAllocations: true
});
front.off("allocations", counter);
front.off("allocations", allocationsCounter);
ok(typeof profilerEndTime === "number",
"The front.stopRecording() emits a profiler end time.");
@ -62,7 +64,7 @@ function spawnTest () {
"The memoryEndTime is after memoryStartTime.");
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);
finish();

View File

@ -10,11 +10,11 @@ function spawnTest () {
let { EVENTS, PerformanceController, $, gFront } = panel.panelWin;
Services.prefs.setBoolPref(MEMORY_PREF, true);
let originalProbability = Services.prefs.getCharPref("devtools.performance.memory.sample-probability");
let originalLogLength = Services.prefs.getIntPref("devtools.performance.memory.max-log-length");
let originalProbability = Services.prefs.getCharPref(MEMORY_SAMPLE_PROB_PREF);
let originalLogLength = Services.prefs.getIntPref(MEMORY_MAX_LOG_LEN_PREF);
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", "0.213");
Services.prefs.setIntPref("devtools.performance.memory.max-log-length", 777777);
Services.prefs.setCharPref(MEMORY_SAMPLE_PROB_PREF, "0.213");
Services.prefs.setIntPref(MEMORY_MAX_LOG_LEN_PREF, 777777);
yield startRecording(panel);
@ -26,8 +26,8 @@ function spawnTest () {
is(maxLogLength, 777777, "allocations max log length option is set on memory actor");
Services.prefs.setBoolPref(MEMORY_PREF, false);
Services.prefs.setCharPref("devtools.performance.memory.sample-probability", originalProbability);
Services.prefs.setIntPref("devtools.performance.memory.max-log-length", originalLogLength);
Services.prefs.setCharPref(MEMORY_SAMPLE_PROB_PREF, originalProbability);
Services.prefs.setIntPref(MEMORY_MAX_LOG_LEN_PREF, originalLogLength);
yield teardown(panel);
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 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 MEMORY_PREF = "devtools.performance.ui.enable-memory";
const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
const IDLE_PREF = "devtools.performance.ui.show-idle-blocks";
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 } =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
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.removeEventListener("load", onLoad);
@ -31,6 +33,10 @@ function createQR(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;
document.querySelector("#token pre").textContent = token;
}

View File

@ -24,6 +24,7 @@
<h3 id="header">&wifi_auth_header;</h3>
<div id="scan-request">&wifi_auth_scan_request;</div>
<div id="cert"></div>
<div id="qr-code">
<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 a dedicated actor via attachProcess request
return this.connection.client &&
this.connection.client.mainRoot &&
this.connection.client.mainRoot.traits.allowChromeProcess ||
(this._listTabsResponse &&
this._listTabsResponse.consoleActor);

View File

@ -77,3 +77,9 @@ status_unknown=UNKNOWN
# Device preferences and settings
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):
# Semicolon-separated list of plural forms. See:
# 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
# LOCALIZATION NOTE (webrtcIndicator.controlSharingOn.menuitem):
# %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
INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
INT_CONSTANT(FILE_ATTRIBUTE_HIDDEN),
INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
INT_CONSTANT(FILE_ATTRIBUTE_SYSTEM),
INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
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 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, 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 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);
SimpleTest.finish();
}

View File

@ -1042,7 +1042,7 @@ pref("dom.webcomponents.enabled", false);
pref("javascript.enabled", true);
pref("javascript.options.strict", false);
#ifdef DEBUG
pref("javascript.options.strict.debug", true);
pref("javascript.options.strict.debug", false);
#endif
pref("javascript.options.baselinejit", 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
* @param {String} [options.parameters.action]
* 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}
* Optional authorization endpoint for the OAuth server
* @constructor
@ -60,16 +63,26 @@ this.FxAccountsOAuthClient = function(options) {
params.append("scope", this.parameters.scope || "");
params.append("action", this.parameters.action || "signin");
params.append("webChannelId", this._webChannelId);
if (this.parameters.keys) {
params.append("keys", "true");
}
};
this.FxAccountsOAuthClient.prototype = {
/**
* 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
* code and state properties otherwise.
* The callback will receive an object with code and state properties.
* If the keys parameter was specified and true, the callback will receive
* a second argument with kAr and kBr properties.
*/
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.
*/
@ -116,6 +129,7 @@ this.FxAccountsOAuthClient.prototype = {
*/
tearDown: function() {
this.onComplete = null;
this.onError = null;
this._complete = true;
this._channel.stopListening();
this._channel = null;
@ -160,21 +174,37 @@ this.FxAccountsOAuthClient.prototype = {
switch (command) {
case "oauth_complete":
// validate the state parameter and call onComplete
// validate the returned state and call onComplete or onError
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 = {
code: data.code,
state: data.state
};
log.debug("OAuth flow completed.");
} else {
log.debug("OAuth flow failed. State doesn't match");
}
if (this.onComplete) {
this.onComplete(result);
if (err) {
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
// calling onComplete again will result in a failure of the OAuth flow
this.tearDown();

View File

@ -69,26 +69,24 @@ this.BrowserTestUtils = {
* Resolves with the new window once it is loaded.
*/
openNewBrowserWindow(options) {
return new Promise(resolve => {
let argString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
argString.data = "";
let features = "chrome,dialog=no,all";
let argString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
argString.data = "";
let features = "chrome,dialog=no,all";
if (options && options.private || false) {
features += ",private";
}
if (options && options.private || false) {
features += ",private";
}
let win = Services.ww.openWindow(
null, Services.prefs.getCharPref("browser.chromeURL"), "_blank",
features, argString);
let win = Services.ww.openWindow(
null, Services.prefs.getCharPref("browser.chromeURL"), "_blank",
features, argString);
// Wait for browser-delayed-startup-finished notification, it indicates
// that the window has loaded completely and is ready to be used for
// testing.
TestUtils.topicObserved("browser-delayed-startup-finished", win).then(
() => resolve(win));
});
// Wait for browser-delayed-startup-finished notification, it indicates
// that the window has loaded completely and is ready to be used for
// testing.
return TestUtils.topicObserved("browser-delayed-startup-finished",
subject => subject == win).then(() => win);
},
/**

View File

@ -32,20 +32,34 @@ this.TestUtils = {
*
* @param {string} topic
* The topic to observe.
* @param {*} subject
* A value to check the notification subject against. Only a
* notification with a matching subject will cause the promise to
* resolve.
* @param {function} checkFn [optional]
* Called with (subject, data) as arguments, should return true if the
* notification is the expected one, or false if it should be ignored
* 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}
* Resolves with the data provided when the topic has been observed.
* @resolves The array [subject, data] from the observed notification.
*/
topicObserved(topic, subject=null) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(observedSubject, topic, data) {
if (subject !== null && subject !== observedSubject) { return; }
Services.obs.removeObserver(observer, topic);
resolve(data);
topicObserved(topic, checkFn) {
return new Promise((resolve, reject) => {
Services.obs.addObserver(function observer(subject, topic, data) {
try {
try {
if (checkFn && !checkFn(subject, data)) {
return;
}
} finally {
Services.obs.removeObserver(observer, topic);
}
resolve([subject, data]);
} catch (ex) {
reject(ex);
}
}, topic, false);
});
},

View File

@ -210,7 +210,8 @@ exports.Error = OSError;
*/
let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
winBirthDate,
lastAccessDate, lastWriteDate) {
lastAccessDate, lastWriteDate,
winAttributes) {
this._path = path;
this._isDir = isDir;
this._isSymLink = isSymLink;
@ -218,6 +219,7 @@ let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
this._winBirthDate = winBirthDate;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastWriteDate;
this._winAttributes = winAttributes;
};
AbstractInfo.prototype = {
@ -285,6 +287,15 @@ AbstractInfo.prototype = {
*/
get 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;

View File

@ -236,10 +236,19 @@
/**
* Set the file's access permission bits.
* Not implemented for Windows (bug 1022816).
*/
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 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,
winBirthDate, lastAccessDate, lastWriteDate);
winBirthDate, lastAccessDate, lastWriteDate, winAttributes);
};
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
@ -963,10 +977,19 @@
/**
* Set the file's access permission bits.
* Not implemented for Windows (bug 1022816).
*/
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;
}
/**
* 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.Error = SysAll.Error;
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).
[test_osfile_async_setPermissions.js]
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",
"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": {
"expires_in_version": "never",
"kind": "boolean",

View File

@ -540,3 +540,19 @@ let Printing = {
}
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;
}
NS_IMETHODIMP
nsXULAppInfo::GetIs64Bit(bool* aResult)
{
#ifdef HAVE_64BIT_BUILD
*aResult = true;
#else
*aResult = false;
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::EnsureContentProcess()
{

View File

@ -23,7 +23,7 @@ bool BrowserTabsRemoteAutostart();
* stable/frozen, please contact Benjamin Smedberg.
*/
[scriptable, uuid(fb861ca6-426f-4edf-844e-bbabec9bbc1a)]
[scriptable, uuid(5754b56e-f392-426d-aec0-3ba7c49aff32)]
interface nsIXULRuntime : nsISupports
{
/**
@ -109,6 +109,11 @@ interface nsIXULRuntime : nsISupports
*/
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.
* This will cause components to be autoregistered and all