Merge inbound to central, a=merge

MozReview-Commit-ID: 9NFjSEt96iT
This commit is contained in:
Wes Kocher 2017-08-02 17:11:51 -07:00
commit baf6cddc4c
186 changed files with 3849 additions and 3702 deletions
addon-sdk
browser
devtools
docshell/base
dom
editor/libeditor
gfx/layers
hal

@ -8,63 +8,10 @@
HAS_MISC_RULE = True
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
JETPACK_PACKAGE_MANIFESTS += ['source/test/jetpack-package.ini',
'source/test/leak/jetpack-package.ini']
JETPACK_ADDON_MANIFESTS += ['source/test/addons/jetpack-addon.ini']
JETPACK_PACKAGE_MANIFESTS += ['source/test/jetpack-package.ini']
DIRS += ['source/test/fixtures']
addons = [
'addon-manager',
'author-email',
'child_process',
'chrome',
'content-permissions',
'content-script-messages-latency',
'contributors',
'curly-id',
'developers',
'e10s-content',
'e10s-l10n',
'e10s-remote',
'e10s-tabs',
'e10s',
'embedded-webextension',
'l10n-properties',
'l10n',
'layout-change',
'main',
'name-in-numbers-plus',
'name-in-numbers',
'packaging',
'packed',
'page-mod-debugger-post',
'page-mod-debugger-pre',
'page-worker',
'places',
'predefined-id-with-at',
'preferences-branch',
'private-browsing-supported',
'remote',
'require',
'self',
'simple-prefs-l10n',
'simple-prefs-regression',
'simple-prefs',
'standard-id',
'tab-close-on-startup',
'toolkit-require-reload',
'translators',
'unsafe-content-script',
]
addons = ['%s.xpi' % f for f in addons]
GENERATED_FILES += addons
TEST_HARNESS_FILES.testing.mochitest['jetpack-addon']['addon-sdk'].source.test.addons += [
'!%s' % f for f in addons
]
EXTRA_JS_MODULES.sdk += [
'source/app-extension/bootstrap.js',
]

@ -1,182 +1,12 @@
[DEFAULT]
support-files =
buffers/**
commonjs-test-adapter/**
context-menu/**
event/**
fixtures.js
fixtures/**
fixtures/native-addon-test.xpi
fixtures/native-overrides-test.xpi
framescript-manager/**
framescript-util/**
lib/**
loader/**
modules/**
page-mod/**
path/**
private-browsing/**
querystring/**
sidebar/**
tabs/**
test-context-menu.html
traits/**
util.js
windows/**
zip/**
generated-files =
fixtures/native-addon-test.xpi
fixtures/native-overrides-test.xpi
[test-addon-bootstrap.js]
[test-addon-extras.js]
[test-addon-installer.js]
[test-addon-window.js]
[test-api-utils.js]
[test-array.js]
[test-base64.js]
[test-bootstrap.js]
[test-browser-events.js]
[test-buffer.js]
[test-byte-streams.js]
[test-child_process.js]
[test-chrome.js]
[test-clipboard.js]
subsuite = clipboard
[test-collection.js]
[test-commonjs-test-adapter.js]
[test-content-events.js]
[test-content-script.js]
[test-content-sync-worker.js]
[test-content-worker.js]
[test-context-menu.js]
skip-if = asan # Bug 1333359
[test-context-menu@2.js]
[test-cuddlefish.js]
# Cuddlefish loader is unsupported
skip-if = true
[test-deprecate.js]
[test-dev-panel.js]
[test-diffpatcher.js]
[test-dispatcher.js]
[test-disposable.js]
[test-dom.js]
[test-environment.js]
[test-event-core.js]
[test-event-dom.js]
[test-event-target.js]
[test-event-utils.js]
[test-file.js]
[test-frame-utils.js]
[test-framescript-manager.js]
[test-framescript-util.js]
[test-fs.js]
[test-functional.js]
[test-globals.js]
[test-heritage.js]
[test-hidden-frame.js]
[test-host-events.js]
[test-hotkeys.js]
[test-httpd.js]
[test-indexed-db.js]
[test-jetpack-id.js]
[test-keyboard-observer.js]
[test-keyboard-utils.js]
[test-l10n-locale.js]
[test-l10n-plural-rules.js]
[test-lang-type.js]
[test-libxul.js]
[test-list.js]
[test-loader.js]
[test-match-pattern.js]
[test-method.js]
[test-module.js]
[test-modules.js]
[test-mozilla-toolkit-versioning.js]
[test-mpl2-license-header.js]
skip-if = true
[test-namespace.js]
[test-native-loader.js]
[test-native-options.js]
[test-net-url.js]
[test-node-os.js]
[test-notifications.js]
[test-object.js]
[test-observers.js]
[test-page-mod-debug.js]
[test-page-mod.js]
[test-page-worker.js]
[test-panel.js]
skip-if = asan # Bug 1333359
[test-passwords-utils.js]
[test-passwords.js]
[test-path.js]
[test-plain-text-console.js]
[test-preferences-service.js]
[test-preferences-target.js]
[test-private-browsing.js]
[test-promise.js]
[test-querystring.js]
[test-reference.js]
[test-request.js]
[test-require.js]
[test-rules.js]
[test-sandbox.js]
[test-selection.js]
[test-self.js]
[test-sequence.js]
[test-set-exports.js]
[test-shared-require.js]
[test-simple-prefs.js]
[test-simple-storage.js]
[test-system-events.js]
[test-system-input-output.js]
[test-system-runtime.js]
[test-system-startup.js]
[test-system.js]
[test-tab-events.js]
[test-tab-observer.js]
[test-tab-utils.js]
[test-tab.js]
[test-tabs-common.js]
[test-tabs.js]
[test-test-addon-file.js]
[test-test-assert.js]
[test-test-loader.js]
[test-test-memory.js]
[test-test-utils-async.js]
[test-test-utils-generator.js]
[test-test-utils-sync.js]
[test-test-utils.js]
[test-text-streams.js]
[test-timer.js]
[test-traceback.js]
[test-ui-action-button.js]
skip-if = debug || asan # Bug 1208727
[test-ui-frame.js]
[test-ui-id.js]
[test-ui-sidebar-private-browsing.js]
[test-ui-sidebar.js]
[test-ui-toggle-button.js]
[test-ui-toolbar.js]
[test-unit-test-finder.js]
[test-unit-test.js]
[test-unload.js]
[test-unsupported-skip.js]
# Bug 1037235
skip-if = true
[test-uri-resource.js]
[test-url.js]
[test-uuid.js]
[test-weak-set.js]
[test-window-events.js]
[test-window-observer.js]
[test-window-utils-private-browsing.js]
[test-window-utils.js]
[test-window-utils2.js]
[test-windows-common.js]
skip-if = asan # bug 1333357
[test-windows.js]
[test-xhr.js]
[test-xpcom.js]
[test-xul-app.js]

@ -6,10 +6,7 @@ support-files =
data.json
invalid.json
[browser_sdk_loader_sdk_modules.js]
[browser_sdk_loader_sdk_gui_modules.js]
skip-if = e10s # Bug 1315042
[browser_sdk_loader_jsm_modules.js]
[browser_sdk_loader_js_modules.js]
[browser_sdk_loader_json.js]
[browser_sdk_loader_chrome.js]
[browser_sdk_loader_chrome_in_sdk.js]

@ -4499,7 +4499,7 @@ var XULBrowserWindow = {
LinkTargetDisplay.update();
},
showTooltip(x, y, tooltip, direction) {
showTooltip(x, y, tooltip, direction, browser) {
if (Cc["@mozilla.org/widget/dragservice;1"].getService(Ci.nsIDragService).
getCurrentSession()) {
return;
@ -4511,8 +4511,7 @@ var XULBrowserWindow = {
elt.label = tooltip;
elt.style.direction = direction;
let anchor = gBrowser.selectedBrowser;
elt.openPopupAtScreen(anchor.boxObject.screenX + x, anchor.boxObject.screenY + y, false, null);
elt.openPopupAtScreen(browser.boxObject.screenX + x, browser.boxObject.screenY + y, false, null);
},
hideTooltip() {

@ -74,6 +74,7 @@ const startupPhases = {
"resource://gre/modules/NewTabUtils.jsm",
"resource://gre/modules/PageThumbs.jsm",
"resource://gre/modules/Promise.jsm", // imported by devtools during _delayedStartup
"resource://gre/modules/Preferences.jsm",
]),
services: new Set([
"@mozilla.org/browser/search-service;1",

@ -23,5 +23,6 @@ LOCAL_INCLUDES += [
'../dirprovider',
'../feeds',
'../migration',
'../sessionstore',
'../shell',
]

@ -24,6 +24,7 @@
#include "nsFeedSniffer.h"
#include "AboutRedirector.h"
#include "nsIAboutModule.h"
#include "nsSessionStoreUtils.h"
#include "nsNetCID.h"
@ -60,6 +61,9 @@ NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSessionStoreUtils)
NS_DEFINE_NAMED_CID(NS_SESSIONSTOREUTILS_CID);
static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
{ &kNS_BROWSERDIRECTORYPROVIDER_CID, false, nullptr, DirectoryProviderConstructor },
#if defined(XP_WIN)
@ -74,6 +78,7 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
#elif defined(XP_MACOSX)
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsMacShellServiceConstructor },
#endif
{ &kNS_SESSIONSTOREUTILS_CID, false, nullptr, nsSessionStoreUtilsConstructor },
{ nullptr }
};
@ -85,6 +90,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
#endif
{ NS_FEEDSNIFFER_CONTRACTID, &kNS_FEEDSNIFFER_CID },
{ NS_SESSIONSTOREUTILS_CONTRACTID, &kNS_SESSIONSTOREUTILS_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "socialerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },

@ -7,6 +7,7 @@
this.EXPORTED_SYMBOLS = ["ContentRestore"];
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
@ -25,6 +26,33 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
XPCOMUtils.defineLazyModuleGetter(this, "Utils",
"resource://gre/modules/sessionstore/Utils.jsm");
const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
.getService(Ci.nsISessionStoreUtils);
/**
* Restores frame tree |data|, starting at the given root |frame|. As the
* function recurses into descendant frames it will call cb(frame, data) for
* each frame it encounters, starting with the given root.
*/
function restoreFrameTreeData(frame, data, cb) {
// Restore data for the root frame.
// The callback can abort by returning false.
if (cb(frame, data) === false) {
return;
}
if (!data.hasOwnProperty("children")) {
return;
}
// Recurse into child frames.
ssu.forEachNonDynamicChildFrame(frame, (subframe, index) => {
if (data.children[index]) {
restoreFrameTreeData(subframe, data.children[index], cb);
}
});
}
/**
* This module implements the content side of session restoration. The chrome
* side is handled by SessionStore.jsm. The functions in this module are called
@ -294,8 +322,20 @@ ContentRestoreInternal.prototype = {
let window = this.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
FormData.restoreTree(window, formdata);
ScrollPosition.restoreTree(window, scrollPositions);
// Restore form data.
restoreFrameTreeData(window, formdata, (frame, data) => {
// restore() will return false, and thus abort restoration for the
// current |frame| and its descendants, if |data.url| is given but
// doesn't match the loaded document's URL.
return FormData.restore(frame, data);
});
// Restore scroll data.
restoreFrameTreeData(window, scrollPositions, (frame, data) => {
if (data.scroll) {
ScrollPosition.restore(frame, data.scroll);
}
});
},
/**

@ -1,248 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["FrameTree"];
const Cu = Components.utils;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
const EXPORTED_METHODS = ["addObserver", "contains", "map", "forEach"];
/**
* A FrameTree represents all frames that were reachable when the document
* was loaded. We use this information to ignore frames when collecting
* sessionstore data as we can't currently restore anything for frames that
* have been created dynamically after or at the load event.
*
* @constructor
*/
function FrameTree(chromeGlobal) {
let internal = new FrameTreeInternal(chromeGlobal);
let external = {};
for (let method of EXPORTED_METHODS) {
external[method] = internal[method].bind(internal);
}
return Object.freeze(external);
}
/**
* The internal frame tree API that the public one points to.
*
* @constructor
*/
function FrameTreeInternal(chromeGlobal) {
// A WeakMap that uses frames (DOMWindows) as keys and their initial indices
// in their parents' child lists as values. Suppose we have a root frame with
// three subframes i.e. a page with three iframes. The WeakMap would have
// four entries and look as follows:
//
// root -> 0
// subframe1 -> 0
// subframe2 -> 1
// subframe3 -> 2
//
// Should one of the subframes disappear we will stop collecting data for it
// as |this._frames.has(frame) == false|. All other subframes will maintain
// their initial indices to ensure we can restore frame data appropriately.
this._frames = new WeakMap();
// The Set of observers that will be notified when the frame changes.
this._observers = new Set();
// The chrome global we use to retrieve the current DOMWindow.
this._chromeGlobal = chromeGlobal;
// Register a web progress listener to be notified about new page loads.
let docShell = chromeGlobal.docShell;
let ifreq = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
let webProgress = ifreq.getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
}
FrameTreeInternal.prototype = {
// Returns the docShell's current global.
get content() {
return this._chromeGlobal.content;
},
/**
* Adds a given observer |obs| to the set of observers that will be notified
* when the frame tree is reset (when a new document starts loading) or
* recollected (when a document finishes loading).
*
* @param obs (object)
*/
addObserver(obs) {
this._observers.add(obs);
},
/**
* Notifies all observers that implement the given |method|.
*
* @param method (string)
*/
notifyObservers(method) {
for (let obs of this._observers) {
if (obs.hasOwnProperty(method)) {
obs[method]();
}
}
},
/**
* Checks whether a given |frame| is contained in the collected frame tree.
* If it is not, this indicates that we should not collect data for it.
*
* @param frame (nsIDOMWindow)
* @return bool
*/
contains(frame) {
return this._frames.has(frame);
},
/**
* Recursively applies the given function |cb| to the stored frame tree. Use
* this method to collect sessionstore data for all reachable frames stored
* in the frame tree.
*
* If a given function |cb| returns a value, it must be an object. It may
* however return "null" to indicate that there is no data to be stored for
* the given frame.
*
* The object returned by |cb| cannot have any property named "children" as
* that is used to store information about subframes in the tree returned
* by |map()| and might be overridden.
*
* @param cb (function)
* @return object
*/
map(cb) {
let frames = this._frames;
function walk(frame) {
let obj = cb(frame) || {};
if (frames.has(frame)) {
let children = [];
Array.forEach(frame.frames, subframe => {
// Don't collect any data if the frame is not contained in the
// initial frame tree. It's a dynamic frame added later.
if (!frames.has(subframe)) {
return;
}
// Retrieve the frame's original position in its parent's child list.
let index = frames.get(subframe);
// Recursively collect data for the current subframe.
let result = walk(subframe, cb);
if (result && Object.keys(result).length) {
children[index] = result;
}
});
if (children.length) {
obj.children = children;
}
}
return Object.keys(obj).length ? obj : null;
}
return walk(this.content);
},
/**
* Applies the given function |cb| to all frames stored in the tree. Use this
* method if |map()| doesn't suit your needs and you want more control over
* how data is collected.
*
* @param cb (function)
* This callback receives the current frame as the only argument.
*/
forEach(cb) {
let frames = this._frames;
function walk(frame) {
cb(frame);
if (!frames.has(frame)) {
return;
}
Array.forEach(frame.frames, subframe => {
if (frames.has(subframe)) {
cb(subframe);
}
});
}
walk(this.content);
},
/**
* Stores a given |frame| and its children in the frame tree.
*
* @param frame (nsIDOMWindow)
* @param index (int)
* The index in the given frame's parent's child list.
*/
collect(frame, index = 0) {
// Mark the given frame as contained in the frame tree.
this._frames.set(frame, index);
// Mark the given frame's subframes as contained in the tree.
Array.forEach(frame.frames, this.collect, this);
},
/**
* @see nsIWebProgressListener.onStateChange
*
* We want to be notified about:
* - new documents that start loading to clear the current frame tree;
* - completed document loads to recollect reachable frames.
*/
onStateChange(webProgress, request, stateFlags, status) {
// Ignore state changes for subframes because we're only interested in the
// top-document starting or stopping its load. We thus only care about any
// changes to the root of the frame tree, not to any of its nodes/leafs.
if (!webProgress.isTopLevel || webProgress.DOMWindow != this.content) {
return;
}
// onStateChange will be fired when loading the initial about:blank URI for
// a browser, which we don't actually care about. This is particularly for
// the case of unrestored background tabs, where the content has not yet
// been restored: we don't want to accidentally send any updates to the
// parent when the about:blank placeholder page has loaded.
if (!this._chromeGlobal.docShell.hasLoadedNonBlankURI) {
return;
}
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
// Clear the list of frames until we can recollect it.
this._frames = new WeakMap();
// Notify observers that the frame tree has been reset.
this.notifyObservers("onFrameTreeReset");
} else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
// The document and its resources have finished loading.
this.collect(webProgress.DOMWindow);
// Notify observers that the frame tree has been reset.
this.notifyObservers("onFrameTreeCollected");
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference])
};

@ -7,6 +7,7 @@
this.EXPORTED_SYMBOLS = ["SessionStorage"];
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource://gre/modules/Services.jsm");
@ -15,6 +16,9 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/Console.jsm");
const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
.createInstance(Ci.nsISessionStoreUtils);
// A bound to the size of data to store for DOM Storage.
const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
@ -54,22 +58,36 @@ this.SessionStorage = Object.freeze({
},
});
/**
* Calls the given callback |cb|, passing |frame| and each of its descendants.
*/
function forEachNonDynamicChildFrame(frame, cb) {
// Call for current frame.
cb(frame);
// Call the callback recursively for each descendant.
ssu.forEachNonDynamicChildFrame(frame, subframe => {
return forEachNonDynamicChildFrame(subframe, cb);
});
}
var SessionStorageInternal = {
/**
* Reads all session storage data from the given docShell.
* @param docShell
* A tab's docshell (containing the sessionStorage)
* @param frameTree
* The docShell's FrameTree instance.
* @param content
* A tab's global, i.e. the root frame we want to collect for.
* @return Returns a nested object that will have hosts as keys and per-origin
* session storage data as strings. For example:
* {"https://example.com^userContextId=1": {"key": "value", "my_number": "123"}}
*/
collect(docShell, frameTree) {
collect(content) {
let data = {};
let visitedOrigins = new Set();
let docShell = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
frameTree.forEach(frame => {
forEachNonDynamicChildFrame(content, frame => {
let principal = getPrincipalForFrame(docShell, frame);
if (!principal) {
return;

@ -34,13 +34,13 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
"resource:///modules/sessionstore/SessionStorage.jsm");
Cu.import("resource:///modules/sessionstore/FrameTree.jsm", this);
var gFrameTree = new FrameTree(this);
Cu.import("resource:///modules/sessionstore/ContentRestore.jsm", this);
XPCOMUtils.defineLazyGetter(this, "gContentRestore",
() => { return new ContentRestore(this) });
const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
.getService(Ci.nsISessionStoreUtils);
// The current epoch.
var gCurrentEpoch = 0;
@ -72,6 +72,98 @@ function createLazy(fn) {
};
}
/**
* A function that will recursively call |cb| to collected data for all
* non-dynamic frames in the current frame/docShell tree.
*/
function mapFrameTree(callback) {
return (function map(frame, cb) {
// Collect data for the current frame.
let obj = cb(frame) || {};
let children = [];
// Recurse into child frames.
ssu.forEachNonDynamicChildFrame(frame, (subframe, index) => {
let result = map(subframe, cb);
if (result && Object.keys(result).length) {
children[index] = result;
}
});
if (children.length) {
obj.children = children;
}
return Object.keys(obj).length ? obj : null;
})(content, callback);
}
/**
* Listens for state change notifcations from webProgress and notifies each
* registered observer for either the start of a page load, or its completion.
*/
var StateChangeNotifier = {
init() {
this._observers = new Set();
let ifreq = docShell.QueryInterface(Ci.nsIInterfaceRequestor);
let webProgress = ifreq.getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
},
/**
* Adds a given observer |obs| to the set of observers that will be notified
* when when a new document starts or finishes loading.
*
* @param obs (object)
*/
addObserver(obs) {
this._observers.add(obs);
},
/**
* Notifies all observers that implement the given |method|.
*
* @param method (string)
*/
notifyObservers(method) {
for (let obs of this._observers) {
if (obs.hasOwnProperty(method)) {
obs[method]();
}
}
},
/**
* @see nsIWebProgressListener.onStateChange
*/
onStateChange(webProgress, request, stateFlags, status) {
// Ignore state changes for subframes because we're only interested in the
// top-document starting or stopping its load.
if (!webProgress.isTopLevel || webProgress.DOMWindow != content) {
return;
}
// onStateChange will be fired when loading the initial about:blank URI for
// a browser, which we don't actually care about. This is particularly for
// the case of unrestored background tabs, where the content has not yet
// been restored: we don't want to accidentally send any updates to the
// parent when the about:blank placeholder page has loaded.
if (!docShell.hasLoadedNonBlankURI) {
return;
}
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
this.notifyObservers("onPageLoadStarted");
} else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
this.notifyObservers("onPageLoadCompleted");
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference])
};
/**
* Listens for and handles content events that we need for the
* session store service to be notified of state changes in content.
@ -79,7 +171,7 @@ function createLazy(fn) {
var EventListener = {
init() {
addEventListener("load", this, true);
addEventListener("load", ssu.createDynamicFrameEventFilter(this), true);
},
handleEvent(event) {
@ -248,10 +340,10 @@ var MessageListener = {
*/
var SessionHistoryListener = {
init() {
// The frame tree observer is needed to handle initial subframe loads.
// The state change observer is needed to handle initial subframe loads.
// It will redundantly invalidate with the SHistoryListener in some cases
// but these invalidations are very cheap.
gFrameTree.addObserver(this);
StateChangeNotifier.addObserver(this);
// By adding the SHistoryListener immediately, we will unfortunately be
// notified of every history entry as the tab is restored. We don't bother
@ -329,11 +421,11 @@ var SessionHistoryListener = {
this.collect();
},
onFrameTreeCollected() {
onPageLoadCompleted() {
this.collect();
},
onFrameTreeReset() {
onPageLoadStarted() {
this.collect();
},
@ -402,30 +494,24 @@ var SessionHistoryListener = {
*/
var ScrollPositionListener = {
init() {
addEventListener("scroll", this);
gFrameTree.addObserver(this);
addEventListener("scroll", ssu.createDynamicFrameEventFilter(this));
StateChangeNotifier.addObserver(this);
},
handleEvent(event) {
let frame = event.target.defaultView;
// Don't collect scroll data for frames created at or after the load event
// as SessionStore can't restore scroll data for those.
if (gFrameTree.contains(frame)) {
MessageQueue.push("scroll", () => this.collect());
}
},
onFrameTreeCollected() {
handleEvent() {
MessageQueue.push("scroll", () => this.collect());
},
onFrameTreeReset() {
onPageLoadCompleted() {
MessageQueue.push("scroll", () => this.collect());
},
onPageLoadStarted() {
MessageQueue.push("scroll", () => null);
},
collect() {
return gFrameTree.map(ScrollPosition.collect);
return mapFrameTree(ScrollPosition.collect);
}
};
@ -448,26 +534,20 @@ var ScrollPositionListener = {
*/
var FormDataListener = {
init() {
addEventListener("input", this, true);
gFrameTree.addObserver(this);
addEventListener("input", ssu.createDynamicFrameEventFilter(this), true);
StateChangeNotifier.addObserver(this);
},
handleEvent(event) {
let frame = event.target.ownerGlobal;
// Don't collect form data for frames created at or after the load event
// as SessionStore can't restore form data for those.
if (gFrameTree.contains(frame)) {
MessageQueue.push("formdata", () => this.collect());
}
handleEvent() {
MessageQueue.push("formdata", () => this.collect());
},
onFrameTreeReset() {
onPageLoadStarted() {
MessageQueue.push("formdata", () => null);
},
collect() {
return gFrameTree.map(FormData.collect);
return mapFrameTree(FormData.collect);
}
};
@ -488,13 +568,10 @@ var DocShellCapabilitiesListener = {
_latestCapabilities: "",
init() {
gFrameTree.addObserver(this);
StateChangeNotifier.addObserver(this);
},
/**
* onFrameTreeReset() is called as soon as we start loading a page.
*/
onFrameTreeReset() {
onPageLoadStarted() {
// The order of docShell capabilities cannot change while we're running
// so calling join() without sorting before is totally sufficient.
let caps = DocShellCapabilities.collect(docShell).join(",");
@ -518,25 +595,20 @@ var DocShellCapabilitiesListener = {
*/
var SessionStorageListener = {
init() {
addEventListener("MozSessionStorageChanged", this, true);
let filter = ssu.createDynamicFrameEventFilter(this);
addEventListener("MozSessionStorageChanged", filter, true);
Services.obs.addObserver(this, "browser:purge-domain-data");
gFrameTree.addObserver(this);
StateChangeNotifier.addObserver(this);
},
uninit() {
Services.obs.removeObserver(this, "browser:purge-domain-data");
},
handleEvent(event) {
if (gFrameTree.contains(event.target)) {
this.collectFromEvent(event);
}
},
observe() {
// Collect data on the next tick so that any other observer
// that needs to purge data can do its work first.
setTimeout(() => this.collect(), 0);
setTimeoutWithTarget(() => this.collect(), 0, tabEventTarget);
},
// We don't want to send all the session storage data for all the frames
@ -550,7 +622,7 @@ var SessionStorageListener = {
this._changes = undefined;
},
collectFromEvent(event) {
handleEvent(event) {
if (!docShell) {
return;
}
@ -598,16 +670,14 @@ var SessionStorageListener = {
// messages.
this.resetChanges();
MessageQueue.push("storage", () => {
return SessionStorage.collect(docShell, gFrameTree);
});
MessageQueue.push("storage", () => SessionStorage.collect(content));
},
onFrameTreeCollected() {
onPageLoadCompleted() {
this.collect();
},
onFrameTreeReset() {
onPageLoadStarted() {
this.collect();
}
};
@ -733,7 +803,8 @@ var MessageQueue = {
if (!this._timeout && !this._timeoutDisabled) {
// Wait a little before sending the message to batch multiple changes.
this._timeout = setTimeout(() => this.send(), this.BATCH_DELAY_MS);
this._timeout = setTimeoutWithTarget(
() => this.send(), this.BATCH_DELAY_MS, tabEventTarget);
}
},
@ -795,6 +866,7 @@ var MessageQueue = {
},
};
StateChangeNotifier.init();
EventListener.init();
MessageListener.init();
FormDataListener.init();
@ -849,7 +921,7 @@ addEventListener("unload", () => {
// Remove progress listeners.
gContentRestore.resetRestore();
// We don't need to take care of any gFrameTree observers as the gFrameTree
// We don't need to take care of any StateChangeNotifier observers as they
// will die with the content script. The same goes for the privacy transition
// observer that will die with the docShell when the tab is closed.
});

@ -12,6 +12,7 @@ JAR_MANIFESTS += ['jar.mn']
XPIDL_SOURCES += [
'nsISessionStartup.idl',
'nsISessionStore.idl',
'nsISessionStoreUtils.idl',
]
XPIDL_MODULE = 'sessionstore'
@ -25,7 +26,6 @@ EXTRA_COMPONENTS += [
EXTRA_JS_MODULES.sessionstore = [
'ContentRestore.jsm',
'DocShellCapabilities.jsm',
'FrameTree.jsm',
'GlobalState.jsm',
'PrivacyFilter.jsm',
'RecentlyClosedTabsAndWindowsMenuUtils.jsm',
@ -45,5 +45,11 @@ EXTRA_JS_MODULES.sessionstore = [
'TabStateFlusher.jsm',
]
UNIFIED_SOURCES += [
'nsSessionStoreUtils.cpp',
]
FINAL_LIBRARY = 'browsercomps'
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Session Restore')

@ -0,0 +1,46 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface mozIDOMWindowProxy;
interface nsIDOMEventListener;
/**
* A callback passed to nsISessionStoreUtils.forEachNonDynamicChildFrame().
*/
[function, scriptable, uuid(8199ebf7-76c0-43d6-bcbe-913dd3de3ebf)]
interface nsISessionStoreUtilsFrameCallback : nsISupports
{
/**
* handleFrame() will be called once for each non-dynamic child frame of the
* given parent |frame|. The second argument is the |index| of the frame in
* the list of all child frames.
*/
void handleFrame(in mozIDOMWindowProxy frame, in unsigned long index);
};
/**
* SessionStore utility functions implemented in C++ for performance reasons.
*/
[scriptable, uuid(2be448ef-c783-45de-a0df-442bccbb4532)]
interface nsISessionStoreUtils : nsISupports
{
/**
* Calls the given |callback| once for each non-dynamic child frame of the
* given |window|.
*/
void forEachNonDynamicChildFrame(in mozIDOMWindowProxy window,
in nsISessionStoreUtilsFrameCallback callback);
/**
* Creates and returns an event listener that filters events from dynamic
* docShells. It forwards those from non-dynamic docShells to the given
* |listener|.
*
* This is implemented as a native filter, rather than a JS-based one, for
* performance reasons.
*/
nsIDOMEventListener createDynamicFrameEventFilter(in nsIDOMEventListener listener);
};

@ -0,0 +1,126 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSessionStoreUtils.h"
#include "mozilla/dom/Event.h"
#include "nsPIDOMWindow.h"
#include "nsIDocShell.h"
using namespace mozilla::dom;
namespace {
class DynamicFrameEventFilter final : public nsIDOMEventListener
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(DynamicFrameEventFilter)
explicit DynamicFrameEventFilter(nsIDOMEventListener* aListener)
: mListener(aListener)
{ }
NS_IMETHODIMP HandleEvent(nsIDOMEvent* aEvent) override
{
if (mListener && TargetInNonDynamicDocShell(aEvent)) {
mListener->HandleEvent(aEvent);
}
return NS_OK;
}
private:
~DynamicFrameEventFilter() { }
bool TargetInNonDynamicDocShell(nsIDOMEvent* aEvent)
{
EventTarget* target = aEvent->InternalDOMEvent()->GetTarget();
if (!target) {
return false;
}
nsPIDOMWindowOuter* outer = target->GetOwnerGlobalForBindings();
if (!outer) {
return false;
}
nsIDocShell* docShell = outer->GetDocShell();
if (!docShell) {
return false;
}
bool isDynamic = false;
nsresult rv = docShell->GetCreatedDynamically(&isDynamic);
return NS_SUCCEEDED(rv) && !isDynamic;
}
nsCOMPtr<nsIDOMEventListener> mListener;
};
NS_IMPL_CYCLE_COLLECTION(DynamicFrameEventFilter, mListener)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DynamicFrameEventFilter)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(DynamicFrameEventFilter)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DynamicFrameEventFilter)
} // anonymous namespace
NS_IMPL_ISUPPORTS(nsSessionStoreUtils, nsISessionStoreUtils)
NS_IMETHODIMP
nsSessionStoreUtils::ForEachNonDynamicChildFrame(mozIDOMWindowProxy* aWindow,
nsISessionStoreUtilsFrameCallback* aCallback)
{
NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG);
nsCOMPtr<nsPIDOMWindowOuter> outer = nsPIDOMWindowOuter::From(aWindow);
NS_ENSURE_TRUE(outer, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocShell> docShell = outer->GetDocShell();
NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
int32_t length;
nsresult rv = docShell->GetChildCount(&length);
NS_ENSURE_SUCCESS(rv, rv);
for (int32_t i = 0; i < length; ++i) {
nsCOMPtr<nsIDocShellTreeItem> item;
docShell->GetChildAt(i, getter_AddRefs(item));
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocShell> childDocShell(do_QueryInterface(item));
NS_ENSURE_TRUE(childDocShell, NS_ERROR_FAILURE);
bool isDynamic = false;
nsresult rv = childDocShell->GetCreatedDynamically(&isDynamic);
if (NS_SUCCEEDED(rv) && isDynamic) {
continue;
}
int32_t childOffset = 0;
rv = childDocShell->GetChildOffset(&childOffset);
NS_ENSURE_SUCCESS(rv, rv);
aCallback->HandleFrame(item->GetWindow(), childOffset);
}
return NS_OK;
}
NS_IMETHODIMP
nsSessionStoreUtils::CreateDynamicFrameEventFilter(nsIDOMEventListener* aListener,
nsIDOMEventListener** aResult)
{
NS_ENSURE_TRUE(aListener, NS_ERROR_INVALID_ARG);
nsCOMPtr<nsIDOMEventListener> filter(new DynamicFrameEventFilter(aListener));
filter.forget(aResult);
return NS_OK;
}

@ -0,0 +1,29 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsSessionStoreUtils_h
#define nsSessionStoreUtils_h
#include "nsCycleCollectionParticipant.h"
#include "nsISessionStoreUtils.h"
#include "nsIDOMEventListener.h"
#include "nsCOMPtr.h"
#define NS_SESSIONSTOREUTILS_CID \
{0xd713b4be, 0x8285, 0x4cab, {0x9c, 0x0e, 0x0b, 0xbc, 0x38, 0xbf, 0xb9, 0x3c}}
#define NS_SESSIONSTOREUTILS_CONTRACTID \
"@mozilla.org/browser/sessionstore/utils;1"
class nsSessionStoreUtils final : public nsISessionStoreUtils
{
public:
NS_DECL_NSISESSIONSTOREUTILS
NS_DECL_ISUPPORTS
private:
~nsSessionStoreUtils() { }
};
#endif // nsSessionStoreUtils_h

@ -17,6 +17,7 @@ support-files =
browser_formdata_xpath_sample.html
browser_frametree_sample.html
browser_frametree_sample_frameset.html
browser_frametree_sample_iframes.html
browser_frame_history_index.html
browser_frame_history_index2.html
browser_frame_history_index_blank.html

@ -6,14 +6,14 @@
</head>
<body>
<input id="txt" />
<iframe id="iframe"></iframe>
<script type="text/javascript">
let isOuter = window == window.top;
if (isOuter) {
let iframe = document.createElement("iframe");
let iframe = document.getElementById("iframe");
iframe.setAttribute("src", "https://example.com" + location.pathname);
document.body.appendChild(iframe);
}
</script>
</body>

@ -5,127 +5,120 @@
const URL = HTTPROOT + "browser_frametree_sample.html";
const URL_FRAMESET = HTTPROOT + "browser_frametree_sample_frameset.html";
const URL_IFRAMES = HTTPROOT + "browser_frametree_sample_iframes.html";
/**
* This ensures that loading a page normally, aborting a page load, reloading
* a page, navigating using the bfcache, and ignoring frames that were
* created dynamically work as expect. We expect the frame tree to be reset
* when a page starts loading and we also expect a valid frame tree to exist
* when it has stopped loading.
* Check that we correctly enumerate non-dynamic child frames.
*/
add_task(async function test_frametree() {
const FRAME_TREE_SINGLE = { href: URL };
const FRAME_TREE_FRAMESET = {
href: URL_FRAMESET,
children: [{href: URL}, {href: URL}, {href: URL}]
};
// Create a tab with a single frame.
let tab = BrowserTestUtils.addTab(gBrowser, URL);
let browser = tab.linkedBrowser;
await promiseNewFrameTree(browser);
await checkFrameTree(browser, FRAME_TREE_SINGLE,
"loading a page resets and creates the frame tree correctly");
// Load the frameset and create two frames dynamically, the first on
// DOMContentLoaded and the second on load.
await sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL});
browser.loadURI(URL_FRAMESET);
await promiseNewFrameTree(browser);
await checkFrameTree(browser, FRAME_TREE_FRAMESET,
"dynamic frames created on or after the load event are ignored");
// Go back to the previous single-frame page. There will be no load event as
// the page is still in the bfcache. We thus make sure this type of navigation
// resets the frame tree.
browser.goBack();
await promiseNewFrameTree(browser);
await checkFrameTree(browser, FRAME_TREE_SINGLE,
"loading from bfache resets and creates the frame tree correctly");
// Load the frameset again but abort the load early.
// The frame tree should still be reset and created.
browser.loadURI(URL_FRAMESET);
executeSoon(() => browser.stop());
await promiseNewFrameTree(browser);
// Load the frameset and check the tree again.
await sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL});
browser.loadURI(URL_FRAMESET);
await promiseNewFrameTree(browser);
await checkFrameTree(browser, FRAME_TREE_FRAMESET,
"reloading a page resets and creates the frame tree correctly");
// Cleanup.
gBrowser.removeTab(tab);
});
/**
* This test ensures that we ignore frames that were created dynamically at or
* after the load event. SessionStore can't handle these and will not restore
* or collect any data for them.
*/
add_task(async function test_frametree_dynamic() {
// The frame tree as expected. The first two frames are static
// and the third one was created on DOMContentLoaded.
const FRAME_TREE = {
href: URL_FRAMESET,
children: [{href: URL}, {href: URL}, {href: URL}]
};
const FRAME_TREE_REMOVED = {
href: URL_FRAMESET,
children: [{href: URL}, {href: URL}]
};
// Add an empty tab for a start.
let tab = BrowserTestUtils.addTab(gBrowser, "about:blank");
let tab = BrowserTestUtils.addTab(gBrowser, URL);
let browser = tab.linkedBrowser;
await promiseBrowserLoaded(browser);
// Create dynamic frames on "DOMContentLoaded" and on "load".
await sendMessage(browser, "ss-test:createDynamicFrames", {id: "frames", url: URL});
// The page is a single frame with no children.
is(await countNonDynamicFrames(browser), 0, "no child frames");
// Navigate to a frameset.
browser.loadURI(URL_FRAMESET);
await promiseNewFrameTree(browser);
await promiseBrowserLoaded(browser);
// Check that the frame tree does not contain the frame created on "load".
// The two static frames and the one created on DOMContentLoaded must be in
// the tree.
await checkFrameTree(browser, FRAME_TREE,
"frame tree contains first four frames");
// The frameset has two frames.
is(await countNonDynamicFrames(browser), 2, "two non-dynamic child frames");
// Remove the last frame in the frameset.
await sendMessage(browser, "ss-test:removeLastFrame", {id: "frames"});
// Check that the frame tree didn't change.
await checkFrameTree(browser, FRAME_TREE,
"frame tree contains first four frames");
// Go back in history.
let pageShowPromise = ContentTask.spawn(browser, null, async () => {
return ContentTaskUtils.waitForEvent(this, "pageshow", true);
});
browser.goBack();
await pageShowPromise;
// Remove the last frame in the frameset.
await sendMessage(browser, "ss-test:removeLastFrame", {id: "frames"});
// Check that the frame tree excludes the removed frame.
await checkFrameTree(browser, FRAME_TREE_REMOVED,
"frame tree contains first three frames");
// We're at page one again.
is(await countNonDynamicFrames(browser), 0, "no child frames");
// Append a dynamic frame.
await ContentTask.spawn(browser, URL, async ([url]) => {
let frame = content.document.createElement("iframe");
frame.setAttribute("src", url);
content.document.body.appendChild(frame);
return ContentTaskUtils.waitForEvent(frame, "load");
});
// The dynamic frame should be ignored.
is(await countNonDynamicFrames(browser), 0, "we still have a single root frame");
// Cleanup.
gBrowser.removeTab(tab);
await promiseRemoveTab(tab);
});
/**
* Checks whether the current frame hierarchy of a given |browser| matches the
* |expected| frame hierarchy.
* Check that we correctly enumerate non-dynamic child frames.
*/
function checkFrameTree(browser, expected, msg) {
return sendMessage(browser, "ss-test:mapFrameTree").then(tree => {
is(JSON.stringify(tree), JSON.stringify(expected), msg);
add_task(async function test_frametree_dynamic() {
// Add an empty tab for a start.
let tab = BrowserTestUtils.addTab(gBrowser, URL_IFRAMES);
let browser = tab.linkedBrowser;
await promiseBrowserLoaded(browser);
// The page has two iframes.
is(await countNonDynamicFrames(browser), 2, "two non-dynamic child frames");
is(await enumerateIndexes(browser), "0,1", "correct indexes 0 and 1");
// Insert a dynamic frame.
await ContentTask.spawn(browser, URL, async ([url]) => {
let frame = content.document.createElement("iframe");
frame.setAttribute("src", url);
content.document.body.insertBefore(frame, content.document.getElementsByTagName("iframe")[1]);
return ContentTaskUtils.waitForEvent(frame, "load");
});
// The page still has two iframes.
is(await countNonDynamicFrames(browser), 2, "two non-dynamic child frames");
is(await enumerateIndexes(browser), "0,1", "correct indexes 0 and 1");
// Append a dynamic frame.
await ContentTask.spawn(browser, URL, async ([url]) => {
let frame = content.document.createElement("iframe");
frame.setAttribute("src", url);
content.document.body.appendChild(frame);
return ContentTaskUtils.waitForEvent(frame, "load");
});
// The page still has two iframes.
is(await countNonDynamicFrames(browser), 2, "two non-dynamic child frames");
is(await enumerateIndexes(browser), "0,1", "correct indexes 0 and 1");
// Remopve a non-dynamic iframe.
await ContentTask.spawn(browser, URL, async ([url]) => {
// Remove the first iframe, which should be a non-dynamic iframe.
content.document.body.removeChild(content.document.getElementsByTagName("iframe")[0]);
});
is(await countNonDynamicFrames(browser), 1, "one non-dynamic child frame");
is(await enumerateIndexes(browser), "1", "correct index 1");
// Cleanup.
await promiseRemoveTab(tab);
});
async function countNonDynamicFrames(browser) {
return ContentTask.spawn(browser, null, async () => {
const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
.getService(Ci.nsISessionStoreUtils);
let count = 0;
ssu.forEachNonDynamicChildFrame(content, () => count++);
return count;
});
}
/**
* Returns a promise that will be resolved when the given |browser| has loaded
* and we received messages saying that its frame tree has been reset and
* recollected.
*/
function promiseNewFrameTree(browser) {
let reset = promiseContentMessage(browser, "ss-test:onFrameTreeCollected");
let collect = promiseContentMessage(browser, "ss-test:onFrameTreeCollected");
return Promise.all([reset, collect]);
async function enumerateIndexes(browser) {
return ContentTask.spawn(browser, null, async () => {
const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
.getService(Ci.nsISessionStoreUtils);
let indexes = [];
ssu.forEachNonDynamicChildFrame(content, (frame, i) => indexes.push(i));
return indexes.join(",");
});
}

@ -0,0 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<html lang="en">
<head>
<meta charset="utf-8">
<title>browser_frametree_sample_iframes.html</title>
</head>
<iframe src="browser_frametree_sample.html"></iframe>
<iframe src="browser_frametree_sample.html"></iframe>
</html>

@ -78,9 +78,14 @@ add_task(async function test_pageshow() {
browser.loadURI(URL2);
await promiseBrowserLoaded(browser);
// Wait until shistory changes.
let pageShowPromise = ContentTask.spawn(browser, null, async () => {
return ContentTaskUtils.waitForEvent(this, "pageshow", true);
});
// Go back to the previous url which is loaded from the bfcache.
browser.goBack();
await promiseContentMessage(browser, "ss-test:onFrameTreeCollected");
await pageShowPromise;
is(browser.currentURI.spec, URL, "correct url after going back");
// Check that loading from bfcache did invalidate shistory.

@ -5,17 +5,18 @@
<title>browser_sessionStorage.html</title>
</head>
<body>
<iframe id="iframe"></iframe>
<script type="text/javascript">
let isOuter = window == window.top;
let args = window.location.search.slice(1).split("&");
let rand = args[0];
if (isOuter) {
let iframe = document.createElement("iframe");
let iframe = document.getElementById("iframe");
let isSecure = args.indexOf("secure") > -1;
let scheme = isSecure ? "https" : "http";
iframe.setAttribute("src", scheme + "://example.com" + location.pathname + "?" + rand);
document.body.appendChild(iframe);
}
if (sessionStorage.length === 0) {

@ -10,23 +10,11 @@ var Cu = Components.utils;
var Ci = Components.interfaces;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/sessionstore/FrameTree.jsm", this);
var gFrameTree = new FrameTree(this);
function executeSoon(callback) {
Services.tm.dispatchToMainThread(callback);
}
gFrameTree.addObserver({
onFrameTreeReset() {
sendAsyncMessage("ss-test:onFrameTreeReset");
},
onFrameTreeCollected() {
sendAsyncMessage("ss-test:onFrameTreeCollected");
}
});
var historyListener = {
OnHistoryNewEntry() {
sendAsyncMessage("ss-test:OnHistoryNewEntry");
@ -171,48 +159,6 @@ addMessageListener("ss-test:setScrollPosition", function(msg) {
});
});
addMessageListener("ss-test:createDynamicFrames", function({data}) {
function createIFrame(rows) {
let frames = content.document.getElementById(data.id);
frames.setAttribute("rows", rows);
let frame = content.document.createElement("frame");
frame.setAttribute("src", data.url);
frames.appendChild(frame);
}
addEventListener("DOMContentLoaded", function onContentLoaded(event) {
if (content.document == event.target) {
removeEventListener("DOMContentLoaded", onContentLoaded, true);
// DOMContentLoaded is fired right after we finished parsing the document.
createIFrame("33%, 33%, 33%");
}
}, true);
addEventListener("load", function onLoad(event) {
if (content.document == event.target) {
removeEventListener("load", onLoad, true);
// Creating this frame on the same tick as the load event
// means that it must not be included in the frame tree.
createIFrame("25%, 25%, 25%, 25%");
}
}, true);
sendAsyncMessage("ss-test:createDynamicFrames");
});
addMessageListener("ss-test:removeLastFrame", function({data}) {
let frames = content.document.getElementById(data.id);
frames.lastElementChild.remove();
sendAsyncMessage("ss-test:removeLastFrame");
});
addMessageListener("ss-test:mapFrameTree", function(msg) {
let result = gFrameTree.map(frame => ({href: frame.location.href}));
sendAsyncMessage("ss-test:mapFrameTree", result);
});
addMessageListener("ss-test:click", function({data}) {
content.document.getElementById(data.id).click();
sendAsyncMessage("ss-test:click");

@ -1071,10 +1071,6 @@ html|span.ac-emphasize-text-url {
opacity: 0;
}
#manage-share-providers {
-moz-image-region: rect(18px, 468px, 36px, 450px);
}
.social-share-toolbar {
border-bottom: 1px solid #dedede;
padding: 2px;

@ -96,7 +96,7 @@ module.exports = createClass({
return dom.div(
{
className: "property-view",
className: "computed-property-view",
"data-property-name": name,
tabIndex: "0",
ref: container => {
@ -105,11 +105,11 @@ module.exports = createClass({
},
dom.div(
{
className: "property-name-container",
className: "computed-property-name-container",
},
dom.div(
{
className: "property-name theme-fg-color5",
className: "computed-property-name theme-fg-color5",
tabIndex: "",
title: name,
onClick: this.onFocus,
@ -119,11 +119,11 @@ module.exports = createClass({
),
dom.div(
{
className: "property-value-container",
className: "computed-property-value-container",
},
dom.div(
{
className: "property-value theme-fg-color1",
className: "computed-property-value theme-fg-color1",
dir: "ltr",
tabIndex: "",
onClick: this.onFocus,

@ -31,8 +31,8 @@ add_task(function* () {
});
function* testAccordionStateAfterClickingHeader(doc) {
let header = doc.querySelector("#computedview-container .box-model-pane ._header");
let bContent = doc.querySelector("#computedview-container .box-model-pane ._content");
let header = doc.querySelector("#computed-container .box-model-pane ._header");
let bContent = doc.querySelector("#computed-container .box-model-pane ._content");
info("Checking initial state of the box model panel.");
is(bContent.style.display, "block", "The box model panel content is 'display: block'.");
@ -51,7 +51,7 @@ function* testAccordionStateAfterClickingHeader(doc) {
function* testAccordionStateAfterSwitchingSidebars(inspector, doc) {
info("Checking the box model accordion state is persistent after switching sidebars.");
let bContent = doc.querySelector("#computedview-container .box-model-pane ._content");
let bContent = doc.querySelector("#computed-container .box-model-pane ._content");
info("Selecting the layout view.");
inspector.sidebar.select("layoutview");
@ -75,7 +75,7 @@ function* testAccordionStateAfterReopeningComputedView(toolbox) {
info("Re-opening the layout view.");
let { view } = yield openBoxModelView();
let { document: doc } = view;
let bContent = doc.querySelector("#computedview-container .box-model-pane ._content");
let bContent = doc.querySelector("#computed-container .box-model-pane ._content");
info("Checking the state of the box model panel.");
ok(!bContent, "The box model panel content is not rendered.");

@ -16,7 +16,7 @@ const TEST_URI = `
<div id="fixed" style="position: fixed"></div>
`;
const OFFSET_PARENT_SELECTOR = ".property-value-container .objectBox-node";
const OFFSET_PARENT_SELECTOR = ".computed-property-value-container .objectBox-node";
const res1 = [
{

@ -115,6 +115,6 @@ function* testChangingValues(inspector, boxmodel, testActor) {
}
function getPropertySelector(propertyName) {
return `.boxmodel-properties-wrapper .property-view` +
`[data-property-name=${propertyName}] .property-value`;
return `.boxmodel-properties-wrapper .computed-property-view` +
`[data-property-name=${propertyName}] .computed-property-value`;
}

@ -179,12 +179,11 @@ function CssComputedView(inspector, document, pageStyle) {
this._onIncludeBrowserStyles = this._onIncludeBrowserStyles.bind(this);
let doc = this.styleDocument;
this.element = doc.getElementById("propertyContainer");
this.element = doc.getElementById("computed-property-container");
this.boxModelWrapper = doc.getElementById("boxmodel-wrapper");
this.searchField = doc.getElementById("computedview-searchbox");
this.searchClearButton = doc.getElementById("computedview-searchinput-clear");
this.includeBrowserStylesCheckbox =
doc.getElementById("browser-style-checkbox");
this.searchField = doc.getElementById("computed-searchbox");
this.searchClearButton = doc.getElementById("computed-searchinput-clear");
this.includeBrowserStylesCheckbox = doc.getElementById("browser-style-checkbox");
this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
this._onShortcut = this._onShortcut.bind(this);
@ -203,7 +202,7 @@ function CssComputedView(inspector, document, pageStyle) {
this.searchClearButton.hidden = true;
// No results text.
this.noResults = this.styleDocument.getElementById("computedview-no-results");
this.noResults = this.styleDocument.getElementById("computed-no-results");
// Refresh panel when color unit changed or pref for showing
// original sources changes.
@ -347,11 +346,11 @@ CssComputedView.prototype = {
let propertyContent;
let parent = node;
while (parent.parentNode) {
if (parent.classList.contains("property-view")) {
if (parent.classList.contains("computed-property-view")) {
propertyView = parent;
break;
}
if (parent.classList.contains("property-content")) {
if (parent.classList.contains("computed-property-content")) {
propertyContent = parent;
break;
}
@ -364,29 +363,29 @@ CssComputedView.prototype = {
let value, type;
// Get the property and value for a node that's a property name or value
let isHref = classes.contains("theme-link") && !classes.contains("link");
if (propertyView && (classes.contains("property-name") ||
classes.contains("property-value") ||
let isHref = classes.contains("theme-link") && !classes.contains("computed-link");
if (propertyView && (classes.contains("computed-property-name") ||
classes.contains("computed-property-value") ||
isHref)) {
value = {
property: parent.querySelector(".property-name").firstChild.textContent,
value: parent.querySelector(".property-value").textContent
property: parent.querySelector(".computed-property-name").firstChild.textContent,
value: parent.querySelector(".computed-property-value").textContent
};
}
if (propertyContent && (classes.contains("other-property-value") ||
if (propertyContent && (classes.contains("computed-other-property-value") ||
isHref)) {
let view = propertyContent.previousSibling;
value = {
property: view.querySelector(".property-name").firstChild.textContent,
property: view.querySelector(".computed-property-name").firstChild.textContent,
value: node.textContent
};
}
// Get the type
if (classes.contains("property-name")) {
if (classes.contains("computed-property-name")) {
type = VIEW_NODE_PROPERTY_TYPE;
} else if (classes.contains("property-value") ||
classes.contains("other-property-value")) {
} else if (classes.contains("computed-property-value") ||
classes.contains("computed-other-property-value")) {
type = VIEW_NODE_VALUE_TYPE;
} else if (isHref) {
type = VIEW_NODE_IMAGE_URL_TYPE;
@ -928,9 +927,9 @@ PropertyView.prototype = {
get propertyHeaderClassName() {
if (this.visible) {
let isDark = this.tree._darkStripe = !this.tree._darkStripe;
return isDark ? "property-view row-striped" : "property-view";
return isDark ? "computed-property-view row-striped" : "computed-property-view";
}
return "property-view-hidden";
return "computed-property-hidden";
},
/**
@ -942,9 +941,11 @@ PropertyView.prototype = {
get propertyContentClassName() {
if (this.visible) {
let isDark = this.tree._darkStripe;
return isDark ? "property-content row-striped" : "property-content";
return isDark
? "computed-property-content row-striped"
: "computed-property-content";
}
return "property-content-hidden";
return "computed-property-hidden";
},
/**
@ -977,18 +978,18 @@ PropertyView.prototype = {
this.shortcuts.on("Space", (name, event) => this.onMatchedToggle(event));
let nameContainer = doc.createElementNS(HTML_NS, "span");
nameContainer.className = "property-name-container";
nameContainer.className = "computed-property-name-container";
this.element.appendChild(nameContainer);
// Build the twisty expand/collapse
this.matchedExpander = doc.createElementNS(HTML_NS, "div");
this.matchedExpander.className = "expander theme-twisty";
this.matchedExpander.className = "computed-expander theme-twisty";
this.matchedExpander.addEventListener("click", this.onMatchedToggle);
nameContainer.appendChild(this.matchedExpander);
// Build the style name element
this.nameNode = doc.createElementNS(HTML_NS, "span");
this.nameNode.classList.add("property-name", "theme-fg-color5");
this.nameNode.classList.add("computed-property-name", "theme-fg-color5");
// Reset its tabindex attribute otherwise, if an ellipsis is applied
// it will be reachable via TABing
this.nameNode.setAttribute("tabindex", "");
@ -1009,12 +1010,12 @@ PropertyView.prototype = {
nameContainer.appendChild(this.nameNode);
let valueContainer = doc.createElementNS(HTML_NS, "span");
valueContainer.className = "property-value-container";
valueContainer.className = "computed-property-value-container";
this.element.appendChild(valueContainer);
// Build the style value element
this.valueNode = doc.createElementNS(HTML_NS, "span");
this.valueNode.classList.add("property-value", "theme-fg-color1");
this.valueNode.classList.add("computed-property-value", "theme-fg-color1");
// Reset its tabindex attribute otherwise, if an ellipsis is applied
// it will be reachable via TABing
this.valueNode.setAttribute("tabindex", "");
@ -1070,8 +1071,8 @@ PropertyView.prototype = {
let frag = outputParser.parseCssProperty(this.propertyInfo.name,
this.propertyInfo.value,
{
colorSwatchClass: "computedview-colorswatch",
colorClass: "computedview-color",
colorSwatchClass: "computed-colorswatch",
colorClass: "computed-color",
urlClass: "theme-link"
// No need to use baseURI here as computed URIs are never relative.
});
@ -1089,9 +1090,9 @@ PropertyView.prototype = {
this.matchedSelectorsContainer.parentNode.hidden = !hasMatchedSelectors;
if (hasMatchedSelectors) {
this.matchedExpander.classList.add("expandable");
this.matchedExpander.classList.add("computed-expandable");
} else {
this.matchedExpander.classList.remove("expandable");
this.matchedExpander.classList.remove("computed-expandable");
}
if (this.matchedExpanded && hasMatchedSelectors) {
@ -1132,7 +1133,7 @@ PropertyView.prototype = {
});
let link = createChild(span, "a", {
target: "_blank",
class: "link theme-link",
class: "computed-link theme-link",
title: selector.href,
sourcelocation: selector.source,
tabindex: "0",
@ -1157,7 +1158,7 @@ PropertyView.prototype = {
});
let valueDiv = createChild(status, "div", {
class: "fix-get-selection other-property-value theme-fg-color1"
class: "fix-get-selection computed-other-property-value theme-fg-color1"
});
valueDiv.appendChild(selector.outputFragment);
promises.push(selector.ready);
@ -1336,8 +1337,8 @@ SelectorView.prototype = {
let frag = outputParser.parseCssProperty(
this.selectorInfo.name,
this.selectorInfo.value, {
colorSwatchClass: "computedview-colorswatch",
colorClass: "computedview-color",
colorSwatchClass: "computed-colorswatch",
colorClass: "computed-color",
urlClass: "theme-link",
baseURI: this.selectorInfo.rule.href
}

@ -30,7 +30,7 @@ add_task(function* () {
});
function* checkColorCycling(container, view) {
let valueNode = container.querySelector(".computedview-color");
let valueNode = container.querySelector(".computed-color");
let win = view.styleWindow;
// "Authored" (default; currently the computed value)
@ -57,8 +57,8 @@ function* checkColorCycling(container, view) {
}
function* checkSwatchShiftClick(container, win, expectedValue, comment) {
let swatch = container.querySelector(".computedview-colorswatch");
let valueNode = container.querySelector(".computedview-color");
let swatch = container.querySelector(".computed-colorswatch");
let valueNode = container.querySelector(".computed-color");
swatch.scrollIntoView();
let onUnitChange = swatch.once("unit-change");

@ -145,7 +145,7 @@ const TEST_DATA = [
desc: "Testing a matched rule value",
getHoveredNode: function* (view) {
let el = yield getComputedViewMatchedRules(view, "color");
return el.querySelector(".other-property-value");
return el.querySelector(".computed-other-property-value");
},
assertNodeInfo: function (nodeInfo) {
is(nodeInfo.type, VIEW_NODE_VALUE_TYPE);

@ -38,7 +38,7 @@ add_task(function* () {
yield selectNode("span", inspector);
info("Selecting the first computed style in the list");
let firstStyle = view.styleDocument.querySelector(".property-view");
let firstStyle = view.styleDocument.querySelector(".computed-property-view");
ok(firstStyle, "First computed style found in panel");
firstStyle.focus();
@ -50,7 +50,7 @@ add_task(function* () {
info("Verify the 2nd style has been expanded");
let secondStyleSelectors = view.styleDocument.querySelectorAll(
".property-content .matchedselectors")[1];
".computed-property-content .matchedselectors")[1];
ok(secondStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
info("Tab back up and test the same thing, with space");
@ -61,6 +61,6 @@ add_task(function* () {
info("Verify the 1st style has been expanded too");
let firstStyleSelectors = view.styleDocument.querySelectorAll(
".property-content .matchedselectors")[0];
".computed-property-content .matchedselectors")[0];
ok(firstStyleSelectors.childNodes.length > 0, "Matched selectors expanded");
});

@ -30,7 +30,7 @@ function* testExpandOnTwistyClick({styleDocument, styleWindow}, inspector) {
info("Testing that a property expands on twisty click");
info("Getting twisty element");
let twisty = styleDocument.querySelector("#propertyContainer .expandable");
let twisty = styleDocument.querySelector(".computed-expandable");
ok(twisty, "Twisty found");
let onExpand = inspector.once("computed-view-property-expanded");
@ -40,7 +40,7 @@ function* testExpandOnTwistyClick({styleDocument, styleWindow}, inspector) {
yield onExpand;
// Expanded means the matchedselectors div is not empty
let div = styleDocument.querySelector(".property-content .matchedselectors");
let div = styleDocument.querySelector(".computed-property-content .matchedselectors");
ok(div.childNodes.length > 0,
"Matched selectors are expanded on twisty click");
}
@ -49,7 +49,7 @@ function* testCollapseOnTwistyClick({styleDocument, styleWindow}, inspector) {
info("Testing that a property collapses on twisty click");
info("Getting twisty element");
let twisty = styleDocument.querySelector("#propertyContainer .expandable");
let twisty = styleDocument.querySelector(".computed-expandable");
ok(twisty, "Twisty found");
let onCollapse = inspector.once("computed-view-property-collapsed");
@ -59,7 +59,7 @@ function* testCollapseOnTwistyClick({styleDocument, styleWindow}, inspector) {
yield onCollapse;
// Collapsed means the matchedselectors div is empty
let div = styleDocument.querySelector(".property-content .matchedselectors");
let div = styleDocument.querySelector(".computed-property-content .matchedselectors");
ok(div.childNodes.length === 0,
"Matched selectors are collapsed on twisty click");
}
@ -68,7 +68,7 @@ function* testExpandOnDblClick({styleDocument, styleWindow}, inspector) {
info("Testing that a property expands on container dbl-click");
info("Getting computed property container");
let container = styleDocument.querySelector(".property-view");
let container = styleDocument.querySelector(".computed-property-view");
ok(container, "Container found");
container.scrollIntoView();
@ -80,7 +80,7 @@ function* testExpandOnDblClick({styleDocument, styleWindow}, inspector) {
yield onExpand;
// Expanded means the matchedselectors div is not empty
let div = styleDocument.querySelector(".property-content .matchedselectors");
let div = styleDocument.querySelector(".computed-property-content .matchedselectors");
ok(div.childNodes.length > 0, "Matched selectors are expanded on dblclick");
}
@ -88,7 +88,7 @@ function* testCollapseOnDblClick({styleDocument, styleWindow}, inspector) {
info("Testing that a property collapses on container dbl-click");
info("Getting computed property container");
let container = styleDocument.querySelector(".property-view");
let container = styleDocument.querySelector(".computed-property-view");
ok(container, "Container found");
let onCollapse = inspector.once("computed-view-property-collapsed");
@ -98,7 +98,7 @@ function* testCollapseOnDblClick({styleDocument, styleWindow}, inspector) {
yield onCollapse;
// Collapsed means the matchedselectors div is empty
let div = styleDocument.querySelector(".property-content .matchedselectors");
let div = styleDocument.querySelector(".computed-property-content .matchedselectors");
ok(div.childNodes.length === 0,
"Matched selectors are collapsed on dblclick");
}

@ -35,9 +35,9 @@ function fireCopyEvent(element) {
*/
function getComputedViewProperty(view, name) {
let prop;
for (let property of view.styleDocument.querySelectorAll(".property-view")) {
let nameSpan = property.querySelector(".property-name");
let valueSpan = property.querySelector(".property-value");
for (let property of view.styleDocument.querySelectorAll(".computed-property-view")) {
let nameSpan = property.querySelector(".computed-property-name");
let valueSpan = property.querySelector(".computed-property-value");
if (nameSpan.firstChild.textContent === name) {
prop = {nameSpan: nameSpan, valueSpan: valueSpan};
@ -68,11 +68,11 @@ function getComputedViewPropertyView(view, name) {
}
/**
* Get a reference to the property-content element for a given property name in
* Get a reference to the computed-property-content element for a given property name in
* the computed-view.
* A property-content element always follows (nextSibling) the property itself
* A computed-property-content element always follows (nextSibling) the property itself
* and is only shown when the twisty icon is expanded on the property.
* A property-content element contains matched rules, with selectors,
* A computed-property-content element contains matched rules, with selectors,
* properties, values and stylesheet links
*
* @param {CssComputedView} view
@ -85,10 +85,10 @@ function getComputedViewPropertyView(view, name) {
var getComputedViewMatchedRules = Task.async(function* (view, name) {
let expander;
let propertyContent;
for (let property of view.styleDocument.querySelectorAll(".property-view")) {
let nameSpan = property.querySelector(".property-name");
for (let property of view.styleDocument.querySelectorAll(".computed-property-view")) {
let nameSpan = property.querySelector(".computed-property-name");
if (nameSpan.firstChild.textContent === name) {
expander = property.querySelector(".expandable");
expander = property.querySelector(".computed-expandable");
propertyContent = property.nextSibling;
break;
}
@ -132,7 +132,7 @@ function getComputedViewPropertyValue(view, name, propertyName) {
*/
function expandComputedViewPropertyByIndex(view, index) {
info("Expanding property " + index + " in the computed view");
let expandos = view.styleDocument.querySelectorAll("#propertyContainer .expandable");
let expandos = view.styleDocument.querySelectorAll(".computed-expandable");
if (!expandos.length || !expandos[index]) {
return promise.reject();
}
@ -152,7 +152,7 @@ function expandComputedViewPropertyByIndex(view, index) {
* @return {DOMNode} The link at the given index, if one exists, null otherwise
*/
function getComputedViewLinkByIndex(view, index) {
let links = view.styleDocument.querySelectorAll(".rule-link .link");
let links = view.styleDocument.querySelectorAll(".rule-link .computed-link");
return links[index];
}
@ -178,7 +178,7 @@ function selectAllText(view) {
function* copyAllAndCheckClipboard(view, expectedPattern) {
selectAllText(view);
let contentDoc = view.styleDocument;
let prop = contentDoc.querySelector(".property-view");
let prop = contentDoc.querySelector(".computed-property-view");
try {
info("Trigger a copy event and wait for the clipboard content");
@ -205,7 +205,7 @@ function* copySomeTextAndCheckClipboard(view, positions, expectedPattern) {
info("Testing selection copy");
let contentDocument = view.styleDocument;
let props = contentDocument.querySelectorAll(".property-view");
let props = contentDocument.querySelectorAll(".computed-property-view");
info("Create the text selection range");
let range = contentDocument.createRange();

@ -32,14 +32,18 @@ const PROMOTE_COUNT_PREF = "devtools.promote.layoutview";
// Default grid colors.
const GRID_COLORS = [
"#4B0082",
"#BB9DFF",
"#FFB53B",
"#71F362",
"#FF90FF",
"#FF90FF",
"#1B80FF",
"#FF2647"
"#9400FF",
"#DF00A9",
"#0A84FF",
"#12BC00",
"#EA8000",
"#00B0BD",
"#D70022",
"#4B42FF",
"#B5007F",
"#058B00",
"#A47F00",
"#005A71"
];
function GridInspector(inspector, window) {

@ -28,9 +28,9 @@ add_task(function* () {
let swatch = doc.querySelector(".grid-color-swatch");
info("Checking the initial state of the Grid Inspector.");
is(swatch.style.backgroundColor, "rgb(75, 0, 130)",
is(swatch.style.backgroundColor, "rgb(148, 0, 255)",
"The color swatch's background is correct.");
is(store.getState().grids[0].color, "#4B0082", "The grid color state is correct.");
is(store.getState().grids[0].color, "#9400FF", "The grid color state is correct.");
info("Scrolling into view of the #grid color swatch.");
swatch.scrollIntoView();
@ -47,12 +47,12 @@ add_task(function* () {
info("Pressing ESCAPE to close the tooltip.");
let onGridColorUpdate = waitUntilState(store, state =>
state.grids[0].color === "#4B0082");
state.grids[0].color === "#9400FF");
let onColorPickerHidden = cPicker.tooltip.once("hidden");
focusAndSendKey(spectrum.element.ownerDocument.defaultView, "ESCAPE");
yield onColorPickerHidden;
yield onGridColorUpdate;
is(swatch.style.backgroundColor, "rgb(75, 0, 130)",
is(swatch.style.backgroundColor, "rgb(148, 0, 255)",
"The color swatch's background was reverted after ESCAPE.");
});

@ -28,9 +28,9 @@ add_task(function* () {
let swatch = doc.querySelector(".grid-color-swatch");
info("Checking the initial state of the Grid Inspector.");
is(swatch.style.backgroundColor, "rgb(75, 0, 130)",
is(swatch.style.backgroundColor, "rgb(148, 0, 255)",
"The color swatch's background is correct.");
is(store.getState().grids[0].color, "#4B0082", "The grid color state is correct.");
is(store.getState().grids[0].color, "#9400FF", "The grid color state is correct.");
info("Scrolling into view of the #grid color swatch.");
swatch.scrollIntoView();

@ -57,7 +57,7 @@ add_task(function* () {
showInfiniteLines,
} = options;
is(color, "#4B0082", "CSS grid highlighter color is correct.");
is(color, "#9400FF", "CSS grid highlighter color is correct.");
ok(!showGridAreasOverlay, "Show grid areas overlay option is off.");
ok(!showGridLineNumbers, "Show grid line numbers option is off.");
ok(showInfiniteLines, "Show infinite lines option is on.");

@ -46,53 +46,47 @@
<!-- Main Panel Content -->
<div id="inspector-main-content" class="devtools-main-content">
<div id="inspector-toolbar" class="devtools-toolbar" nowindowdrag="true"
data-localization-bundle="devtools/client/locales/inspector.properties">
data-localization-bundle="devtools/client/locales/inspector.properties">
<button id="inspector-element-add-button" class="devtools-button"
data-localization="title=inspectorAddNode.label"></button>
data-localization="title=inspectorAddNode.label"></button>
<div class="devtools-toolbar-spacer"></div>
<span id="inspector-searchlabel"></span>
<div id="inspector-search" class="devtools-searchbox has-clear-btn">
<input id="inspector-searchbox" class="devtools-searchinput"
type="search"
data-localization="placeholder=inspectorSearchHTML.label3"/>
type="search"
data-localization="placeholder=inspectorSearchHTML.label3"/>
<button id="inspector-searchinput-clear" class="devtools-searchinput-clear" tabindex="-1"></button>
</div>
<button id="inspector-eyedropper-toggle"
class="devtools-button command-button-invertable"></button>
<button id="inspector-eyedropper-toggle" class="devtools-button command-button-invertable"></button>
<div id="inspector-sidebar-toggle-box"></div>
</div>
<div id="markup-box"></div>
<div id="inspector-breadcrumbs-toolbar" class="devtools-toolbar">
<div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"
role="group" data-localization="aria-label=inspector.breadcrumbs.label" tabindex="0"></div>
role="group" data-localization="aria-label=inspector.breadcrumbs.label" tabindex="0"></div>
</div>
</div>
<!-- Splitter -->
<div
xmlns="http://www.w3.org/1999/xhtml"
id="inspector-splitter-box">
<div xmlns="http://www.w3.org/1999/xhtml" id="inspector-splitter-box">
</div>
<!-- Sidebar Container -->
<div id="inspector-sidebar-container">
<div
xmlns="http://www.w3.org/1999/xhtml"
id="inspector-sidebar"
hidden="true"></div>
<div xmlns="http://www.w3.org/1999/xhtml" id="inspector-sidebar" hidden="true"></div>
</div>
<!-- Sidebar panel definitions -->
<div id="tabpanels" style="visibility:collapse">
<div id="sidebar-panel-ruleview" class="devtools-monospace theme-sidebar inspector-tabpanel"
data-localization-bundle="devtools/client/locales/inspector.properties">
data-localization-bundle="devtools/client/locales/inspector.properties">
<div id="ruleview-toolbar-container" class="devtools-toolbar">
<div id="ruleview-toolbar">
<div class="devtools-searchbox has-clear-btn">
<input id="ruleview-searchbox"
class="devtools-filterinput devtools-rule-searchbox"
type="search"
data-localization="placeholder=inspector.filterStyles.placeholder"/>
class="devtools-filterinput devtools-rule-searchbox"
type="search"
data-localization="placeholder=inspector.filterStyles.placeholder"/>
<button id="ruleview-searchinput-clear" class="devtools-searchinput-clear"></button>
</div>
<div id="ruleview-command-toolbar">
@ -116,31 +110,27 @@
</div>
<div id="sidebar-panel-computedview" class="devtools-monospace theme-sidebar inspector-tabpanel"
data-localization-bundle="devtools/client/locales/inspector.properties">
<div id="computedview-toolbar" class="devtools-toolbar">
data-localization-bundle="devtools/client/locales/inspector.properties">
<div id="computed-toolbar" class="devtools-toolbar">
<div class="devtools-searchbox has-clear-btn">
<input id="computedview-searchbox"
class="devtools-filterinput devtools-rule-searchbox"
type="search"
data-localization="placeholder=inspector.filterStyles.placeholder"/>
<button id="computedview-searchinput-clear" class="devtools-searchinput-clear"></button>
<input id="computed-searchbox"
class="devtools-filterinput devtools-rule-searchbox"
type="search"
data-localization="placeholder=inspector.filterStyles.placeholder"/>
<button id="computed-searchinput-clear" class="devtools-searchinput-clear"></button>
</div>
<input id="browser-style-checkbox"
type="checkbox"
class="includebrowserstyles"/>
type="checkbox"
class="includebrowserstyles"/>
<label id="browser-style-checkbox-label" for="browser-style-checkbox"
data-localization="content=inspector.browserStyles.label"></label>
data-localization="content=inspector.browserStyles.label"></label>
</div>
<div id="computedview-container">
<div id="computedview-container-focusable" tabindex="-1">
<div id="boxmodel-wrapper">
</div>
<div id="propertyContainer" class="theme-separator" tabindex="0" dir="ltr">
</div>
<div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"></div>
<div id="computed-container">
<div id="computed-container-focusable" tabindex="-1">
<div id="boxmodel-wrapper"></div>
<div id="computed-property-container" class="theme-separator" tabindex="0" dir="ltr"></div>
<div id="computed-no-results" hidden="" data-localization="content=inspector.noProperties"></div>
</div>
</div>
</div>

@ -96,7 +96,7 @@ function* testExpandedComputedViewProperty(computedView, nodeFront) {
yield propertyView.refreshMatchedSelectors();
let valueSpan = propertyView.matchedSelectorsContainer
.querySelector(".bestmatch .other-property-value");
.querySelector(".bestmatch .computed-other-property-value");
let tooltip = computedView.tooltips.getTooltip("previewTooltip");
let panel = tooltip.panel;

@ -199,9 +199,9 @@ var simulateColorPickerChange = Task.async(function* (ruleView, colorPicker,
*/
function getComputedViewProperty(view, name) {
let prop;
for (let property of view.styleDocument.querySelectorAll(".property-view")) {
let nameSpan = property.querySelector(".property-name");
let valueSpan = property.querySelector(".property-value");
for (let property of view.styleDocument.querySelectorAll(".computed-property-view")) {
let nameSpan = property.querySelector(".computed-property-name");
let valueSpan = property.querySelector(".computed-property-value");
if (nameSpan.firstChild.textContent === name) {
prop = {nameSpan, valueSpan};

@ -332,15 +332,15 @@
column-rule: 1px solid var(--theme-splitter-color);
}
.boxmodel-properties-wrapper .property-view {
.boxmodel-properties-wrapper .computed-property-view {
padding-inline-start: 17px;
}
.boxmodel-properties-wrapper .property-name-container {
.boxmodel-properties-wrapper .computed-property-name-container {
flex: 1;
}
.boxmodel-properties-wrapper .property-value-container {
.boxmodel-properties-wrapper .computed-property-value-container {
flex: 1;
display: block;
}

@ -11,7 +11,7 @@
height: 100%;
}
#computedview-container {
#computed-container {
overflow: auto;
height: 100%;
}
@ -21,12 +21,12 @@
is focused and therefore can handle shortcuts.
However, for accessibility reasons, tabindex is set to -1 to avoid having to tab
through it, and the outline is hidden. */
#computedview-container-focusable {
#computed-container-focusable {
height: 100%;
outline: none;
}
#computedview-toolbar {
#computed-toolbar {
display: flex;
align-items: center;
-moz-user-select: none;
@ -45,7 +45,7 @@
margin-inline-end: 5px;
}
#propertyContainer {
#computed-property-container {
-moz-user-select: text;
overflow-y: auto;
overflow-x: hidden;
@ -56,54 +56,59 @@
background: var(--theme-body-background);
}
.property-view-hidden,
.property-content-hidden {
.computed-property-hidden {
display: none;
}
.property-view {
.computed-property-view {
padding: 2px 0px;
padding-inline-start: 5px;
display: flex;
flex-wrap: wrap;
}
.property-name-container {
.computed-property-name-container {
width: 202px;
}
.property-value-container {
.computed-property-value-container {
display: flex;
flex: 1 1 168px;
overflow: hidden;
}
.property-name-container > *,
.property-value-container > * {
.computed-property-name-container > *,
.computed-property-value-container > * {
display: inline-block;
vertical-align: middle;
}
.property-name {
.computed-property-name {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
outline: 0 !important;
}
.other-property-value {
.computed-other-property-value {
background-image: url(images/arrow-e.png);
background-repeat: no-repeat;
background-size: 5px 8px;
background-position: left center;
padding-inline-start: 8px;
}
.computed-other-property-value:dir(rtl) {
background-position-x: right;
}
@media (min-resolution: 1.1dppx) {
.other-property-value {
.computed-other-property-value {
background-image: url(images/arrow-e@2x.png);
}
}
.property-value {
.computed-property-value {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -111,25 +116,16 @@
outline: 0 !important;
}
.other-property-value {
background-position: left center;
padding-inline-start: 8px;
}
.other-property-value:dir(rtl) {
background-position-x: right;
}
.property-content {
.computed-property-content {
padding-inline-start: 17px;
}
.theme-firebug .property-view,
.theme-firebug .property-content {
.theme-firebug .computed-property-view,
.theme-firebug .computed-property-content {
font-family: var(--proportional-font-family);
}
.theme-firebug .property-view {
.theme-firebug .computed-property-view {
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
@ -148,11 +144,11 @@
}
/* From skin */
.expander {
.computed-expander {
visibility: hidden;
}
.expandable {
.computed-expandable {
visibility: visible;
}
@ -183,7 +179,7 @@
opacity: 0.5;
}
#computedview-no-results {
#computed-no-results {
height: 100%;
}
@ -195,37 +191,31 @@
margin: 0 5px;
}
.link {
.computed-link {
padding: 0 3px;
cursor: pointer;
float: right;
}
/* Workaround until float: inline-end; is enabled by default */
.link:dir(rtl) {
.computed-link:dir(rtl) {
float: left;
}
/* Take away these two :visited rules to get a core dumper */
/* See https://bugzilla.mozilla.org/show_bug.cgi?id=575675#c30 */
.link,
.link:visited {
.computed-link,
.computed-link:visited {
color: #0091ff;
}
.link,
.helplink,
.link:visited,
.helplink:visited {
text-decoration: none;
}
.link:hover {
.computed-link:hover {
text-decoration: underline;
}
.computedview-colorswatch {
.computed-colorswatch {
border-radius: 50%;
width: 0.9em;
height: 0.9em;
@ -235,7 +225,7 @@
position: relative;
}
.computedview-colorswatch::before {
.computed-colorswatch::before {
content: '';
background-color: #eee;
background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc),

@ -181,7 +181,7 @@ body {
}
.ruleview-swatch,
.computedview-colorswatch {
.computed-colorswatch {
box-shadow: 0 0 0 1px #818181;
}

@ -191,7 +191,7 @@ window {
/* "no results" warning message displayed in the ruleview and in the computed view */
#ruleview-no-results,
#computedview-no-results {
#computed-no-results {
color: var(--theme-body-color-inactive);
text-align: center;
margin: 5px;

@ -183,7 +183,7 @@ body {
}
.ruleview-swatch,
.computedview-colorswatch {
.computed-colorswatch {
box-shadow: 0 0 0 1px #c4c4c4;
}

@ -97,18 +97,18 @@ const CANVAS_SIZE = 4096;
* as input; optionally applying a matrix, and a function to each of the coordinates'
* value.
*
* @param {Number} x1
* The x-axis coordinate of the rectangle's diagonal start point.
* @param {Number} y1
* The y-axis coordinate of the rectangle's diagonal start point.
* @param {Number} x2
* The x-axis coordinate of the rectangle's diagonal end point.
* @param {Number} y2
* The y-axis coordinate of the rectangle's diagonal end point.
* @param {Array} [matrix=identity()]
* A transformation matrix to apply.
* @param {Number} x1
* The x-axis coordinate of the rectangle's diagonal start point.
* @param {Number} y1
* The y-axis coordinate of the rectangle's diagonal start point.
* @param {Number} x2
* The x-axis coordinate of the rectangle's diagonal end point.
* @param {Number} y2
* The y-axis coordinate of the rectangle's diagonal end point.
* @param {Array} [matrix=identity()]
* A transformation matrix to apply.
* @return {Array}
* The rect four corners' points transformed by the matrix given.
* The rect four corners' points transformed by the matrix given.
*/
function getPointsFromDiagonal(x1, y1, x2, y2, matrix = identity()) {
return [
@ -127,8 +127,8 @@ function getPointsFromDiagonal(x1, y1, x2, y2, matrix = identity()) {
* Takes an array of four points and returns a DOMRect-like object, represent the
* boundaries defined by the points given.
*
* @param {Array} points
* The four points.
* @param {Array} points
* The four points.
* @return {Object}
* A DOMRect-like object.
*/
@ -151,8 +151,8 @@ function getBoundsFromPoints(points) {
/**
* Takes an array of four points and returns a string represent a path description.
*
* @param {Array} points
* The four points.
* @param {Array} points
* The four points.
* @return {String}
* A Path Description that can be used in svg's <path> element.
*/
@ -166,22 +166,22 @@ function getPathDescriptionFromPoints(points) {
/**
* Draws a line to the context given, applying a transformation matrix if passed.
*
* @param {CanvasRenderingContext2D} ctx
* The 2d canvas context.
* @param {Number} x1
* The x-axis of the coordinate for the begin of the line.
* @param {Number} y1
* The y-axis of the coordinate for the begin of the line.
* @param {Number} x2
* The x-axis of the coordinate for the end of the line.
* @param {Number} y2
* The y-axis of the coordinate for the end of the line.
* @param {Object} [options]
* The options object.
* @param {Array} [options.matrix=identity()]
* The transformation matrix to apply.
* @param {Array} [options.extendToBoundaries]
* If set, the line will be extended to reach the boundaries specified.
* @param {CanvasRenderingContext2D} ctx
* The 2d canvas context.
* @param {Number} x1
* The x-axis of the coordinate for the begin of the line.
* @param {Number} y1
* The y-axis of the coordinate for the begin of the line.
* @param {Number} x2
* The x-axis of the coordinate for the end of the line.
* @param {Number} y2
* The y-axis of the coordinate for the end of the line.
* @param {Object} [options]
* The options object.
* @param {Array} [options.matrix=identity()]
* The transformation matrix to apply.
* @param {Array} [options.extendToBoundaries]
* If set, the line will be extended to reach the boundaries specified.
*/
function drawLine(ctx, x1, y1, x2, y2, options) {
let matrix = options.matrix || identity();
@ -214,18 +214,18 @@ function drawLine(ctx, x1, y1, x2, y2, options) {
* Draws a rect to the context given, applying a transformation matrix if passed.
* The coordinates are the start and end points of the rectangle's diagonal.
*
* @param {CanvasRenderingContext2D} ctx
* The 2d canvas context.
* @param {Number} x1
* The x-axis coordinate of the rectangle's diagonal start point.
* @param {Number} y1
* The y-axis coordinate of the rectangle's diagonal start point.
* @param {Number} x2
* The x-axis coordinate of the rectangle's diagonal end point.
* @param {Number} y2
* The y-axis coordinate of the rectangle's diagonal end point.
* @param {Array} [matrix=identity()]
* The transformation matrix to apply.
* @param {CanvasRenderingContext2D} ctx
* The 2d canvas context.
* @param {Number} x1
* The x-axis coordinate of the rectangle's diagonal start point.
* @param {Number} y1
* The y-axis coordinate of the rectangle's diagonal start point.
* @param {Number} x2
* The x-axis coordinate of the rectangle's diagonal end point.
* @param {Number} y2
* The y-axis coordinate of the rectangle's diagonal end point.
* @param {Array} [matrix=identity()]
* The transformation matrix to apply.
*/
function drawRect(ctx, x1, y1, x2, y2, matrix = identity()) {
let p = getPointsFromDiagonal(x1, y1, x2, y2, matrix);
@ -623,7 +623,7 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
* Gets the grid gap pattern used to render the gap regions based on the device
* pixel ratio given.
*
* @param {Number} devicePixelRatio
* @param {Number} devicePixelRatio
* The device pixel ratio we want the pattern for.
* @param {Object} dimension
* Refers to the Map key for the grid dimension type which is either the
@ -779,7 +779,7 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
/**
* Checks if the current node has a CSS Grid layout.
*
* @return {Boolean} true if the current node has a CSS grid layout, false otherwise.
* @return {Boolean} true if the current node has a CSS grid layout, false otherwise.
*/
isGrid() {
return this.currentNode.getGridFragments().length > 0;
@ -885,7 +885,7 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
* @param {GridArea} area
* The grid area object.
* @param {Object} bounds
* A DOMRect-like object represent the grid area rectangle.
* A DOMRect-like object represent the grid area rectangle.
*/
_updateGridAreaInfobar(area, bounds) {
let { width, height } = bounds;
@ -911,7 +911,7 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
* @param {Number} columnNumber
* The grid cell's column number.
* @param {Object} bounds
* A DOMRect-like object represent the grid cell rectangle.
* A DOMRect-like object represent the grid cell rectangle.
*/
_updateGridCellInfobar(rowNumber, columnNumber, bounds) {
let { width, height } = bounds;
@ -1162,12 +1162,40 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
startPos) {
let lineStartPos = startPos;
// Keep track of the number of collapsed lines per line position
let stackedLines = [];
const { lines } = gridDimension;
for (let i = 0, line = lines[i]; i < lines.length; line = lines[++i]) {
for (let i = 0, line; (line = lines[i++]);) {
let linePos = line.start;
let negativeLineNumber = i - lines.length - 1;
const negativeLineNumber = i - lines.length;
// Check for overlapping lines. We render a second box beneath the last overlapping
// line number to indicate there are lines beneath it.
const gridLine = gridDimension.tracks[line.number - 1];
if (gridLine) {
const { breadth } = gridLine;
if (breadth === 0) {
stackedLines.push(negativeLineNumber);
if (stackedLines.length > 0) {
this.renderGridLineNumber(negativeLineNumber, linePos, lineStartPos,
line.breadth, dimensionType, 1);
}
continue;
}
}
// For negative line numbers, we want to display the smallest
// value at the front of the stack.
if (stackedLines.length) {
negativeLineNumber = stackedLines[0];
stackedLines = [];
}
this.renderGridLineNumber(negativeLineNumber, linePos, lineStartPos, line.breadth,
dimensionType);
@ -1360,8 +1388,9 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
// Keep track of the number of collapsed lines per line position
let stackedLines = [];
for (let i = 0; i < gridDimension.lines.length; i++) {
let line = gridDimension.lines[i];
const { lines } = gridDimension;
for (let i = 0, line; (line = lines[i++]);) {
let linePos = line.start;
// If you place something using negative numbers, you can trigger some implicit grid
@ -1379,14 +1408,18 @@ class CssGridHighlighter extends AutoRefreshHighlighter {
// Check for overlapping lines. We render a second box beneath the last overlapping
// line number to indicate there are lines beneath it.
const gridLine = gridDimension.tracks[line.number - 1];
if (gridLine) {
const { breadth } = gridLine;
if (breadth === 0) {
stackedLines.push(gridDimension.lines[i].number);
if (stackedLines.length > 0) {
this.renderGridLineNumber(line.number, linePos, lineStartPos, line.breadth,
dimensionType, 1);
}
continue;
}
}

@ -4083,12 +4083,19 @@ nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
}
NS_IMETHODIMP
nsDocShell::SetChildOffset(uint32_t aChildOffset)
nsDocShell::SetChildOffset(int32_t aChildOffset)
{
mChildOffset = aChildOffset;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetChildOffset(int32_t* aChildOffset)
{
*aChildOffset = mChildOffset;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::GetHistoryID(nsID** aID)
{

@ -906,7 +906,7 @@ protected:
// Offset in the parent's child list.
// -1 if the docshell is added dynamically to the parent shell.
uint32_t mChildOffset;
int32_t mChildOffset;
uint32_t mBusyFlags;
uint32_t mAppType;
uint32_t mLoadType;

@ -549,9 +549,10 @@ interface nsIDocShell : nsIDocShellTreeItem
readonly attribute nsIChannel currentDocumentChannel;
/**
* Set the offset of this child in its container.
* The original offset of this child in its container. This property is -1 for
* dynamically added docShells.
*/
[noscript] void setChildOffset(in unsigned long offset);
[noscript] attribute long childOffset;
/**
* Find out whether the docshell is currently in the middle of a page

@ -35,7 +35,6 @@
#include "BatteryManager.h"
#include "mozilla/dom/CredentialsContainer.h"
#include "mozilla/dom/GamepadServiceTest.h"
#include "mozilla/dom/PowerManager.h"
#include "mozilla/dom/WakeLock.h"
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/FlyWebPublishedServer.h"
@ -203,7 +202,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
@ -256,11 +254,6 @@ Navigator::Invalidate()
mBatteryPromise = nullptr;
if (mPowerManager) {
mPowerManager->Shutdown();
mPowerManager = nullptr;
}
if (mConnection) {
mConnection->Shutdown();
mConnection = nullptr;
@ -1417,24 +1410,6 @@ Navigator::PublishServer(const nsAString& aName,
return domPromise.forget();
}
PowerManager*
Navigator::GetMozPower(ErrorResult& aRv)
{
if (!mPowerManager) {
if (!mWindow) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
mPowerManager = PowerManager::CreateInstance(mWindow);
if (!mPowerManager) {
// We failed to get the power manager service?
aRv.Throw(NS_ERROR_UNEXPECTED);
}
}
return mPowerManager;
}
already_AddRefed<WakeLock>
Navigator::RequestWakeLock(const nsAString &aTopic, ErrorResult& aRv)
{

@ -73,7 +73,6 @@ namespace network {
class Connection;
} // namespace network
class PowerManager;
class Presentation;
class LegacyMozTCPSocket;
class VRDisplay;
@ -175,7 +174,6 @@ public:
bool CookieEnabled();
void GetBuildID(nsAString& aBuildID, CallerType aCallerType,
ErrorResult& aRv) const;
PowerManager* GetMozPower(ErrorResult& aRv);
bool JavaEnabled(CallerType aCallerType, ErrorResult& aRv);
uint64_t HardwareConcurrency();
bool CpuHasSSE2();
@ -292,7 +290,6 @@ private:
RefPtr<DesktopNotificationCenter> mNotification;
RefPtr<battery::BatteryManager> mBatteryManager;
RefPtr<Promise> mBatteryPromise;
RefPtr<PowerManager> mPowerManager;
RefPtr<network::Connection> mConnection;
RefPtr<CredentialsContainer> mCredentials;
RefPtr<MediaDevices> mMediaDevices;

@ -567,7 +567,7 @@ TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
}
if (gRunningTimeoutDepth == 0 &&
mWindow.GetPopupControlState() < openAbused) {
mWindow.GetPopupControlState() < openBlocked) {
// This timeout is *not* set from another timeout and it's set
// while popups are enabled. Propagate the state to the timeout if
// its delay (interval) is equal to or less than what

@ -2412,6 +2412,10 @@ nsFrameLoader::MaybeCreateDocShell()
mIsTopLevelContent =
AddTreeItemToTreeOwner(mDocShell, parentTreeOwner, parentType, docShell);
if (mIsTopLevelContent) {
mDocShell->SetCreatedDynamically(false);
}
// Make sure all shells have links back to the content element
// in the nearest enclosing chrome shell.
nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;

@ -7865,7 +7865,7 @@ nsGlobalWindow::FocusOuter(ErrorResult& aError)
// (bugs 355482 and 369306).
bool canFocus = CanSetProperty("dom.disable_window_flip") ||
(opener == callerOuter &&
RevisePopupAbuseLevel(gPopupControlState) < openAbused);
RevisePopupAbuseLevel(gPopupControlState) < openBlocked);
nsCOMPtr<mozIDOMWindowProxy> activeDOMWindow;
fm->GetActiveWindow(getter_AddRefs(activeDOMWindow));
@ -8860,18 +8860,25 @@ nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
PopupControlState abuse = aControl;
switch (abuse) {
case openControlled:
case openAbused:
case openBlocked:
case openOverridden:
if (PopupWhitelisted())
abuse = PopupControlState(abuse - 1);
break;
case openAbused:
if (PopupWhitelisted())
//Skip openBlocked
abuse = openControlled;
break;
case openAllowed: break;
default:
NS_WARNING("Strange PopupControlState!");
}
// limit the number of simultaneously open popups
if (abuse == openAbused || abuse == openControlled) {
if (abuse == openAbused ||
abuse == openBlocked ||
abuse == openControlled) {
int32_t popupMax = Preferences::GetInt("dom.popup_maximum", -1);
if (popupMax >= 0 && gOpenPopupSpamCount >= popupMax)
abuse = openOverridden;
@ -12993,7 +13000,7 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
PopupControlState abuseLevel = gPopupControlState;
if (checkForPopup) {
abuseLevel = RevisePopupAbuseLevel(abuseLevel);
if (abuseLevel >= openAbused) {
if (abuseLevel >= openBlocked) {
if (!aCalledNoScript) {
// If script in some other window is doing a window.open on us and
// it's being blocked, then it's OK to close us afterwards, probably.
@ -13031,9 +13038,9 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
NS_ENSURE_STATE(pwwatch);
MOZ_ASSERT_IF(checkForPopup, abuseLevel < openAbused);
MOZ_ASSERT_IF(checkForPopup, abuseLevel < openBlocked);
// At this point we should know for a fact that if checkForPopup then
// abuseLevel < openAbused, so we could just check for abuseLevel ==
// abuseLevel < openBlocked, so we could just check for abuseLevel ==
// openControlled. But let's be defensive just in case and treat anything
// that fails the above assert as a spam popup too, if it ever happens.
bool isPopupSpamWindow = checkForPopup && (abuseLevel >= openControlled);

@ -65,6 +65,7 @@ enum class CallerType : uint32_t;
enum PopupControlState {
openAllowed = 0, // open that window without worries
openControlled, // it's a popup, but allow it
openBlocked, // it's a popup, but not from an allowed event
openAbused, // it's a popup. disallow it, but allow domain override.
openOverridden // disallow window open
};

@ -259,7 +259,7 @@ function endCheck() {
}
function runTest() {
return Promise.resolve()
return SpecialPowers.pushPrefEnv({"set": [["network.http.rcwn.enabled", false]]})
.then(executeTest)
.then(endCheck)
.catch(aError => ok(false, "Some test failed with error " + aError))

@ -612,10 +612,6 @@ DOMInterfaces = {
'notflattened': True
},
'MozPowerManager': {
'nativeType': 'mozilla::dom::PowerManager',
},
'MozWakeLock': {
'nativeType': 'mozilla::dom::WakeLock',
},

@ -713,6 +713,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// triggered while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eFormSelect:
if (PopupAllowedForEvent("select")) {
@ -734,6 +735,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eEditorInput:
if (PopupAllowedForEvent("input")) {
@ -750,6 +752,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eFormChange:
if (PopupAllowedForEvent("change")) {
@ -766,6 +769,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
break;
case eKeyboardEventClass:
if (aEvent->IsTrusted()) {
abuse = openBlocked;
uint32_t key = aEvent->AsKeyboardEvent()->mKeyCode;
switch(aEvent->mMessage) {
case eKeyPress:
@ -796,6 +800,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
break;
case eTouchEventClass:
if (aEvent->IsTrusted()) {
abuse = openBlocked;
switch (aEvent->mMessage) {
case eTouchStart:
if (PopupAllowedForEvent("touchstart")) {
@ -815,6 +820,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
case eMouseEventClass:
if (aEvent->IsTrusted() &&
aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eMouseUp:
if (PopupAllowedForEvent("mouseup")) {
@ -869,6 +875,7 @@ Event::GetEventPopupControlState(WidgetEvent* aEvent, nsIDOMEvent* aDOMEvent)
// triggered while handling user input. See
// nsPresShell::HandleEventInternal() for details.
if (EventStateManager::IsHandlingUserInput()) {
abuse = openBlocked;
switch(aEvent->mMessage) {
case eFormSubmit:
if (PopupAllowedForEvent("submit")) {

@ -818,8 +818,8 @@ HTMLInputElement::IsPopupBlocked() const
return true;
}
// Check if page is allowed to open the popup
if (win->GetPopupControlState() <= openControlled) {
// Check if page can open a popup without abuse regardless of allowed events
if (win->GetPopupControlState() <= openBlocked) {
return false;
}
@ -6410,18 +6410,30 @@ HTMLInputElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
NS_IMETHODIMP
HTMLInputElement::SaveState()
{
RefPtr<HTMLInputElementState> inputState;
nsPresState* state = nullptr;
switch (GetValueMode()) {
case VALUE_MODE_DEFAULT_ON:
if (mCheckedChanged) {
inputState = new HTMLInputElementState();
state = GetPrimaryPresState();
if (!state) {
return NS_OK;
}
RefPtr<HTMLInputElementState> inputState = new HTMLInputElementState();
inputState->SetChecked(mChecked);
state->SetStateProperty(inputState);
}
break;
case VALUE_MODE_FILENAME:
if (!mFileData->mFilesOrDirectories.IsEmpty()) {
inputState = new HTMLInputElementState();
state = GetPrimaryPresState();
if (!state) {
return NS_OK;
}
RefPtr<HTMLInputElementState> inputState = new HTMLInputElementState();
inputState->SetFilesOrDirectories(mFileData->mFilesOrDirectories);
state->SetStateProperty(inputState);
}
break;
case VALUE_MODE_VALUE:
@ -6434,7 +6446,12 @@ HTMLInputElement::SaveState()
break;
}
inputState = new HTMLInputElementState();
state = GetPrimaryPresState();
if (!state) {
return NS_OK;
}
RefPtr<HTMLInputElementState> inputState = new HTMLInputElementState();
nsAutoString value;
GetValue(value, CallerType::System);
@ -6451,18 +6468,14 @@ HTMLInputElement::SaveState()
}
inputState->SetValue(value);
state->SetStateProperty(inputState);
break;
}
if (inputState) {
nsPresState* state = GetPrimaryPresState();
if (state) {
state->SetStateProperty(inputState);
}
}
if (mDisabledChanged) {
nsPresState* state = GetPrimaryPresState();
if (!state) {
state = GetPrimaryPresState();
}
if (state) {
// We do not want to save the real disabled state but the disabled
// attribute.

@ -3410,7 +3410,7 @@ HTMLMediaElement::AddCaptureMediaTrackToOutputStream(MediaTrack* aTrack,
}
bool
HTMLMediaElement::CanBeCaptured(bool aCaptureAudio)
HTMLMediaElement::CanBeCaptured(StreamCaptureType aCaptureType)
{
// Don't bother capturing when the document has gone away
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
@ -3419,19 +3419,20 @@ HTMLMediaElement::CanBeCaptured(bool aCaptureAudio)
}
// Prevent capturing restricted video
if (!aCaptureAudio && ContainsRestrictedContent()) {
if (aCaptureType == StreamCaptureType::CAPTURE_ALL_TRACKS &&
ContainsRestrictedContent()) {
return false;
}
return true;
}
already_AddRefed<DOMMediaStream>
HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
bool aCaptureAudio,
HTMLMediaElement::CaptureStreamInternal(StreamCaptureBehavior aFinishBehavior,
StreamCaptureType aStreamCaptureType,
MediaStreamGraph* aGraph)
{
MOZ_RELEASE_ASSERT(aGraph);
MOZ_ASSERT(CanBeCaptured(aCaptureAudio));
MOZ_ASSERT(CanBeCaptured(aStreamCaptureType));
MarkAsContentSource(CallerAPI::CAPTURE_STREAM);
MarkAsTainted();
@ -3447,10 +3448,10 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
out->mStream = DOMMediaStream::CreateTrackUnionStreamAsInput(window, aGraph, getter);
out->mStream->SetInactiveOnFinish();
out->mFinishWhenEnded = aFinishWhenEnded;
out->mCapturingAudioOnly = aCaptureAudio;
out->mFinishWhenEnded = aFinishBehavior == StreamCaptureBehavior::FINISH_WHEN_ENDED;
out->mCapturingAudioOnly = aStreamCaptureType == StreamCaptureType::CAPTURE_AUDIO;
if (aCaptureAudio) {
if (aStreamCaptureType == StreamCaptureType::CAPTURE_AUDIO) {
if (mSrcStream) {
// We don't support applying volume and mute to the captured stream, when
// capturing a MediaStream.
@ -3471,7 +3472,7 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
if (mDecoder) {
out->mCapturingDecoder = true;
mDecoder->AddOutputStream(out->mStream->GetInputStream()->AsProcessedStream(),
aFinishWhenEnded);
aFinishBehavior == StreamCaptureBehavior::FINISH_WHEN_ENDED);
} else if (mSrcStream) {
out->mCapturingMediaStream = true;
}
@ -3535,13 +3536,15 @@ HTMLMediaElement::CaptureAudio(ErrorResult& aRv,
{
MOZ_RELEASE_ASSERT(aGraph);
if (!CanBeCaptured(true)) {
if (!CanBeCaptured(StreamCaptureType::CAPTURE_AUDIO)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<DOMMediaStream> stream =
CaptureStreamInternal(false, true, aGraph);
CaptureStreamInternal(StreamCaptureBehavior::CONTINUE_WHEN_ENDED,
StreamCaptureType::CAPTURE_AUDIO,
aGraph);
if (!stream) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
@ -3564,7 +3567,7 @@ HTMLMediaElement::MozCaptureStream(ErrorResult& aRv)
return nullptr;
}
if (!CanBeCaptured(false)) {
if (!CanBeCaptured(StreamCaptureType::CAPTURE_ALL_TRACKS)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
@ -3573,7 +3576,9 @@ HTMLMediaElement::MozCaptureStream(ErrorResult& aRv)
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel, window);
RefPtr<DOMMediaStream> stream =
CaptureStreamInternal(false, false, graph);
CaptureStreamInternal(StreamCaptureBehavior::CONTINUE_WHEN_ENDED,
StreamCaptureType::CAPTURE_ALL_TRACKS,
graph);
if (!stream) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
@ -3595,7 +3600,7 @@ HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv)
return nullptr;
}
if (!CanBeCaptured(false)) {
if (!CanBeCaptured(StreamCaptureType::CAPTURE_ALL_TRACKS)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
@ -3604,7 +3609,9 @@ HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv)
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel, window);
RefPtr<DOMMediaStream> stream =
CaptureStreamInternal(true, false, graph);
CaptureStreamInternal(StreamCaptureBehavior::FINISH_WHEN_ENDED,
StreamCaptureType::CAPTURE_ALL_TRACKS,
graph);
if (!stream) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
@ -7226,7 +7233,9 @@ HTMLMediaElement::AudioCaptureStreamChange(bool aCapture)
mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream());
} else {
RefPtr<DOMMediaStream> stream =
CaptureStreamInternal(false, false, msg);
CaptureStreamInternal(StreamCaptureBehavior::CONTINUE_WHEN_ENDED,
StreamCaptureType::CAPTURE_AUDIO,
msg);
mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetPlaybackStream());
}
} else if (!aCapture && mCaptureStreamPort) {

@ -82,6 +82,18 @@ class TextTrackList;
class AudioTrackList;
class VideoTrackList;
enum class StreamCaptureType : uint8_t
{
CAPTURE_ALL_TRACKS,
CAPTURE_AUDIO
};
enum class StreamCaptureBehavior : uint8_t
{
CONTINUE_WHEN_ENDED,
FINISH_WHEN_ENDED
};
class HTMLMediaElement : public nsGenericHTMLElement,
public nsIDOMHTMLMediaElement,
public MediaDecoderOwner,
@ -932,18 +944,19 @@ protected:
/**
* Returns an DOMMediaStream containing the played contents of this
* element. When aFinishWhenEnded is true, when this element ends playback
* we will finish the stream and not play any more into it.
* When aFinishWhenEnded is false, ending playback does not finish the stream.
* element. When aBehavior is FINISH_WHEN_ENDED, when this element ends
* playback we will finish the stream and not play any more into it. When
* aType is CONTINUE_WHEN_ENDED, ending playback does not finish the stream.
* The stream will never finish.
*
* When aCaptureAudio is true, we stop playout of audio and instead route it
* When aType is CAPTURE_AUDIO, we stop playout of audio and instead route it
* to the DOMMediaStream. Volume and mute state will be applied to the audio
* reaching the stream. No video tracks will be captured in this case.
*/
already_AddRefed<DOMMediaStream> CaptureStreamInternal(bool aFinishWhenEnded,
bool aCaptureAudio,
MediaStreamGraph* aGraph);
already_AddRefed<DOMMediaStream>
CaptureStreamInternal(StreamCaptureBehavior aBehavior,
StreamCaptureType aType,
MediaStreamGraph* aGraph);
/**
* Initialize a decoder as a clone of an existing decoder in another
@ -1272,8 +1285,12 @@ protected:
// Anything we need to check after played success and not related with spec.
void UpdateCustomPolicyAfterPlayed();
// Returns a StreamCaptureType populated with the right bits, depending on the
// tracks this HTMLMediaElement has.
StreamCaptureType CaptureTypeForElement();
// True if this element can be captured, false otherwise.
bool CanBeCaptured(bool aCaptureAudio);
bool CanBeCaptured(StreamCaptureType aCaptureType);
class nsAsyncEventRunner;
class nsNotifyAboutPlayingRunner;

@ -1544,6 +1544,11 @@ HTMLSelectElement::IntrinsicState() const
NS_IMETHODIMP
HTMLSelectElement::SaveState()
{
nsPresState* presState = GetPrimaryPresState();
if (!presState) {
return NS_OK;
}
RefPtr<SelectState> state = new SelectState();
uint32_t len = Length();
@ -1557,15 +1562,12 @@ HTMLSelectElement::SaveState()
}
}
nsPresState* presState = GetPrimaryPresState();
if (presState) {
presState->SetStateProperty(state);
presState->SetStateProperty(state);
if (mDisabledChanged) {
// We do not want to save the real disabled state but the disabled
// attribute.
presState->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
}
if (mDisabledChanged) {
// We do not want to save the real disabled state but the disabled
// attribute.
presState->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
}
return NS_OK;

@ -1,12 +1,6 @@
[DEFAULT]
support-files =
file_anchor_ping.html
wakelock.ogg
wakelock.ogv
[test_anchor_ping.html]
skip-if = os == 'android'
[test_audio_wakelock.html]
skip-if = os == 'android' && processor == 'x86' # bug 1315749
[test_video_wakelock.html]
skip-if = os == 'android' && processor == 'x86' # bug 1315749

@ -60,6 +60,8 @@
<button id='button-up' onclick="document.getElementById('by-button').click();">foo</button>
<div id='div-click' onclick="document.getElementById('by-button').click();" tabindex='1'>foo</div>
<div id='div-click-on-demand' onclick="var i=document.createElement('input'); i.type='file'; i.click();" tabindex='1'>foo</div>
<div id='div-keydown' onkeydown="document.getElementById('by-button').click();" tabindex='1'>foo</div>
<a id='link-click' href="javascript:document.getElementById('by-button').click();" tabindex='1'>foo</a>
</div>
<pre id="test">
<script type="application/javascript">
@ -129,6 +131,8 @@ var testData = [["a", 1, MockFilePicker.filterImages, 1],
["button-up", 0, undefined, 0],
["div-click", 0, undefined, 0],
["div-click-on-demand", 0, undefined, 0],
["div-keydown", 0, undefined, 0],
["link-click", 0, undefined, 0],
];
var currentTest = 0;
@ -137,9 +141,8 @@ var filters;
var filterIndex;
var mixRefExtensionList;
// disable popups to make sure that the popup blocker does not interfere
// with manually opened file pickers.
SpecialPowers.pushPrefEnv({'set': [["dom.disable_open_during_load", false]]}, runTests);
// Make sure picker works with popup blocker enabled and no allowed events
SpecialPowers.pushPrefEnv({'set': [["dom.popup_allowed_events", ""]]}, runTests);
function launchNextTest() {
MockFilePicker.shown = false;
@ -192,8 +195,11 @@ function launchNextTest() {
testData[currentTest][0] == 'button-down' ||
testData[currentTest][0] == 'button-up' ||
testData[currentTest][0] == 'div-click' ||
testData[currentTest][0] == 'div-click-on-demand') {
testData[currentTest][0] == 'div-click-on-demand' ||
testData[currentTest][0] == 'link-click') {
synthesizeMouseAtCenter(document.getElementById(testData[currentTest][0]), {});
} else if (testData[currentTest][0] == 'div-keydown') {
synthesizeKey("a", {});
} else {
document.getElementById(testData[currentTest][0]).click();
}

@ -1,124 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=868943
-->
<head>
<title>Test for Bug 868943</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=868943">Mozilla Bug 868943</a>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 868943 **/
function testAudioPlayPause() {
var lockState = true;
var count = 0;
var content = document.getElementById('content');
var audio = document.createElement('audio');
audio.src = "wakelock.ogg";
content.appendChild(audio);
var startDate;
function testAudioPlayListener(topic, state) {
is(topic, "cpu", "#1 Audio element locked the target == cpu");
var locked = state == "locked-foreground" ||
state == "locked-background";
var s = locked ? "locked" : "unlocked";
is(locked, lockState, "#1 Audio element " + s + " the cpu");
count++;
// count == 1 is when the cpu wakelock is created
// count == 2 is when the cpu wakelock is released
if (count == 1) {
// The next step is to unlock the resource.
lockState = false;
audio.pause();
startDate = new Date();
return;
}
is(count, 2, "The count should be 2 which indicates wakelock release");
if (count == 2) {
var diffDate = (new Date() - startDate);
ok(diffDate > 200, "#1 There was at least 200 milliseconds between the stop and the wakelock release");
content.removeChild(audio);
navigator.mozPower.removeWakeLockListener(testAudioPlayListener);
runTests();
}
};
navigator.mozPower.addWakeLockListener(testAudioPlayListener);
audio.play();
}
function testAudioPlay() {
var lockState = true;
var count = 0;
var content = document.getElementById('content');
var audio = document.createElement('audio');
audio.src = "wakelock.ogg";
content.appendChild(audio);
function testAudioPlayListener(topic, state) {
is(topic, "cpu", "#2 Audio element locked the target == cpu");
var locked = state == "locked-foreground" ||
state == "locked-background";
var s = locked ? "locked" : "unlocked";
is(locked, lockState, "#2 Audio element " + s + " the cpu");
count++;
// count == 1 is when the cpu wakelock is created: the wakelock must be
// created when the media element starts playing.
// count == 2 is when the cpu wakelock is released.
if (count == 1) {
// The next step is to unlock the resource.
lockState = false;
} else if (count == 2) {
content.removeChild(audio);
navigator.mozPower.removeWakeLockListener(testAudioPlayListener);
runTests();
}
};
navigator.mozPower.addWakeLockListener(testAudioPlayListener);
audio.play();
}
var tests = [ testAudioPlayPause, testAudioPlay ];
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.pop();
test();
};
SpecialPowers.pushPrefEnv({"set": [["media.wakelock_timeout", 500]]}, runTests);
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

@ -1,197 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=868943
-->
<head>
<title>Test for Bug 868943</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=868943">Mozilla Bug 868943</a>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 868943 **/
function testVideoPlayPause() {
info("#1 testVideoPlayPause");
var lockState_cpu = true;
var lockState_screen = true;
var count_cpu = 0;
var count_screen = 0;
var content = document.getElementById('content');
var video = document.createElement('video');
ok(video.mozUseScreenWakeLock, "#1 Video element uses screen wake lock by default");
video.src = "wakelock.ogv";
content.appendChild(video);
var startDate;
function testVideoPlayPauseListener(topic, state) {
info("#1 topic=" + topic + ", state=" + state);
var locked = state == "locked-foreground" ||
state == "locked-background";
if (topic == "cpu") {
is(locked, lockState_cpu, "#1 Video element locked the cpu");
count_cpu++;
} else if (topic == "screen") {
is(locked, lockState_screen, "#1 Video element locked the screen");
count_screen++;
}
if (count_cpu == 1 && count_screen == 1) {
info("#1 Both cpu and screen are locked");
// The next step is to unlock the resource.
lockState_cpu = false;
lockState_screen = false;
video.pause();
startDate = new Date();
}
if (count_cpu == 2 && count_screen == 2) {
var diffDate = (new Date() - startDate);
ok(diffDate > 200, "#1 There was at least 200 milliseconds between the stop and the wakelock release");
content.removeChild(video);
navigator.mozPower.removeWakeLockListener(testVideoPlayPauseListener);
runTests();
}
}
navigator.mozPower.addWakeLockListener(testVideoPlayPauseListener);
video.play();
}
function testVideoPlay() {
info("#2 testVideoPlay");
var lockState_cpu = true;
var lockState_screen = true;
var count_cpu = 0;
var count_screen = 0;
var content = document.getElementById('content');
var video = document.createElement('video');
ok(video.mozUseScreenWakeLock, "#2 Video element uses screen wake lock by default");
video.src = "wakelock.ogv";
content.appendChild(video);
var startDate;
video.addEventListener('progress', function() {
startDate = new Date();
});
function testVideoPlayListener(topic, state) {
info("#2 topic=" + topic + ", state=" + state);
var locked = state == "locked-foreground" ||
state == "locked-background";
if (topic == "cpu") {
is(locked, lockState_cpu, "#2 Video element locked the cpu");
count_cpu++;
} else if (topic == "screen") {
is(locked, lockState_screen, "#2 Video element locked the screen");
count_screen++;
}
if (count_cpu == 1 && count_screen == 1) {
info("#2 Both cpu and screen are locked");
// The next step is to unlock the resource.
lockState_cpu = false;
lockState_screen = false;
} else if (count_cpu == 2 && count_screen == 2) {
var diffDate = (new Date() - startDate);
ok(diffDate > 200, "#2 There was at least milliseconds between the stop and the wakelock release");
content.removeChild(video);
navigator.mozPower.removeWakeLockListener(testVideoPlayListener);
runTests();
}
}
navigator.mozPower.addWakeLockListener(testVideoPlayListener);
video.play();
}
function testVideoNoScreenWakeLock() {
info("#3 testVideoNoScreenWakeLock");
var lockState_cpu = true;
var lockState_screen = false;
var count_cpu = 0;
var content = document.getElementById('content');
var video = document.createElement('video');
video.mozUseScreenWakeLock = false;
video.src = "wakelock.ogv";
content.appendChild(video);
var startDate;
function testVideoNoScreenWakeLockListener(topic, state) {
info("#3 topic=" + topic + ", state=" + state);
var locked = state == "locked-foreground" ||
state == "locked-background";
if (topic == "cpu") {
is(locked, lockState_cpu, "#3 Video element locked the cpu");
count_cpu++;
} else if (topic == "screen") {
is(locked, lockState_screen, "#3 Video element locked the screen");
}
if (count_cpu == 1) {
info("#3 Cpu is locked");
// The next step is to unlock the resource.
lockState_cpu = false;
video.pause();
startDate = new Date();
}
if (count_cpu == 2) {
var diffDate = (new Date() - startDate);
ok(diffDate > 200, "#3 There was at least 200 milliseconds between the stop and the wakelock release");
content.removeChild(video);
navigator.mozPower.removeWakeLockListener(testVideoNoScreenWakeLockListener);
runTests();
}
}
navigator.mozPower.addWakeLockListener(testVideoNoScreenWakeLockListener);
video.play();
}
var tests = [ testVideoPlayPause, testVideoPlay, testVideoNoScreenWakeLock ];
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.pop();
test();
};
SpecialPowers.pushPrefEnv({"set": [["media.wakelock_timeout", 500],
["dom.wakelock.enabled", true]]}, runTests);
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Binary file not shown.

Binary file not shown.

@ -559,7 +559,7 @@ uint64_t ContentParent::sNextTabParentId = 0;
nsDataHashtable<nsUint64HashKey, TabParent*> ContentParent::sNextTabParents;
// This is true when subprocess launching is enabled. This is the
// case between StartUp() and ShutDown() or JoinAllSubprocesses().
// case between StartUp() and ShutDown().
static bool sCanLaunchSubprocesses;
// Set to true if the DISABLE_UNSAFE_CPOW_WARNINGS environment variable is
@ -646,53 +646,6 @@ ContentParent::ShutDown()
#endif
}
/*static*/ void
ContentParent::JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
Monitor* aMonitor, bool* aDone)
{
const nsTArray<ContentParent*>& processes = *aProcesses;
for (uint32_t i = 0; i < processes.Length(); ++i) {
if (GeckoChildProcessHost* process = processes[i]->mSubprocess) {
process->Join();
}
}
{
MonitorAutoLock lock(*aMonitor);
*aDone = true;
lock.Notify();
}
// Don't touch any arguments to this function from now on.
}
/*static*/ void
ContentParent::JoinAllSubprocesses()
{
MOZ_ASSERT(NS_IsMainThread());
AutoTArray<ContentParent*, 8> processes;
GetAll(processes);
if (processes.IsEmpty()) {
printf_stderr("There are no live subprocesses.");
return;
}
printf_stderr("Subprocesses are still alive. Doing emergency join.\n");
bool done = false;
Monitor monitor("mozilla.dom.ContentParent.JoinAllSubprocesses");
XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction(
&ContentParent::JoinProcessesIOThread,
&processes, &monitor, &done));
{
MonitorAutoLock lock(monitor);
while (!done) {
lock.Wait();
}
}
sCanLaunchSubprocesses = false;
}
/*static*/ uint32_t
ContentParent::GetPoolSize(const nsAString& aContentProcessType)
{

@ -140,14 +140,6 @@ public:
/** Shut down the content-process machinery. */
static void ShutDown();
/**
* Ensure that all subprocesses are terminated and their OS
* resources have been reaped. This is synchronous and can be
* very expensive in general. It also bypasses the normal
* shutdown process.
*/
static void JoinAllSubprocesses();
static uint32_t GetPoolSize(const nsAString& aContentProcessType);
static uint32_t GetMaxProcessCount(const nsAString& aContentProcessType);
@ -671,9 +663,6 @@ private:
static nsDataHashtable<nsUint32HashKey, ContentParent*> *sJSPluginContentParents;
static StaticAutoPtr<LinkedList<ContentParent> > sContentParents;
static void JoinProcessesIOThread(const nsTArray<ContentParent*>* aProcesses,
Monitor* aMonitor, bool* aDone);
static hal::ProcessPriority GetInitialProcessPriority(Element* aFrameElement);
static ContentBridgeParent* CreateContentBridgeParent(const TabContext& aContext,

@ -214,7 +214,6 @@ const char* mozilla::dom::ContentPrefs::gInitPrefs[] = {
"security.sandbox.logging.enabled",
"security.sandbox.mac.track.violations",
"security.sandbox.windows.log.stackTraceDepth",
"shutdown.watchdog.timeoutSecs",
"signed.applets.codebase_principal_support",
"svg.disabled",
"svg.display-lists.hit-testing.enabled",

@ -1718,7 +1718,11 @@ TabParent::RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsStrin
return IPC_OK();
}
xulBrowserWindow->ShowTooltip(aX, aY, aTooltip, aDirection);
nsCOMPtr<nsIFrameLoaderOwner> frame = do_QueryInterface(mFrameElement);
if (!frame)
return IPC_OK();
xulBrowserWindow->ShowTooltip(aX, aY, aTooltip, aDirection, frame);
return IPC_OK();
}

@ -1,210 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/PowerManager.h"
#include "mozilla/Hal.h"
#include "WakeLock.h"
#include "nsDOMClassInfoID.h"
#include "nsIDOMWakeLockListener.h"
#include "nsIDocument.h"
#include "nsIPermissionManager.h"
#include "nsIPowerManagerService.h"
#include "nsIPrincipal.h"
#include "nsPIDOMWindow.h"
#include "nsServiceManagerUtils.h"
#include "nsError.h"
#include "mozilla/dom/MozPowerManagerBinding.h"
#include "mozilla/Services.h"
namespace mozilla {
namespace dom {
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PowerManager)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsIDOMMozWakeLockListener)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PowerManager, mListeners, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PowerManager)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PowerManager)
/* virtual */ JSObject*
PowerManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MozPowerManagerBinding::Wrap(aCx, this, aGivenProto);
}
nsresult
PowerManager::Init(nsPIDOMWindowInner* aWindow)
{
mWindow = aWindow;
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
NS_ENSURE_STATE(pmService);
// Add ourself to the global notification list.
pmService->AddWakeLockListener(this);
return NS_OK;
}
nsresult
PowerManager::Shutdown()
{
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
NS_ENSURE_STATE(pmService);
// Remove ourself from the global notification list.
pmService->RemoveWakeLockListener(this);
return NS_OK;
}
void
PowerManager::Reboot(ErrorResult& aRv)
{
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
if (pmService) {
pmService->Reboot();
} else {
aRv.Throw(NS_ERROR_UNEXPECTED);
}
}
void
PowerManager::FactoryReset(mozilla::dom::FactoryResetReason& aReason)
{
hal::FactoryReset(aReason);
}
void
PowerManager::PowerOff(ErrorResult& aRv)
{
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
if (pmService) {
pmService->PowerOff();
} else {
aRv.Throw(NS_ERROR_UNEXPECTED);
}
}
void
PowerManager::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener)
{
if (!mListeners.Contains(aListener)) {
mListeners.AppendElement(aListener);
}
}
void
PowerManager::RemoveWakeLockListener(nsIDOMMozWakeLockListener *aListener)
{
mListeners.RemoveElement(aListener);
}
void
PowerManager::GetWakeLockState(const nsAString& aTopic,
nsAString& aState,
ErrorResult& aRv)
{
nsCOMPtr<nsIPowerManagerService> pmService =
do_GetService(POWERMANAGERSERVICE_CONTRACTID);
if (pmService) {
aRv = pmService->GetWakeLockState(aTopic, aState);
} else {
aRv.Throw(NS_ERROR_UNEXPECTED);
}
}
NS_IMETHODIMP
PowerManager::Callback(const nsAString &aTopic, const nsAString &aState)
{
/**
* We maintain a local listener list instead of using the global
* list so that when the window is destroyed we don't have to
* cleanup the mess.
* Copy the listeners list before we walk through the callbacks
* because the callbacks may install new listeners. We expect no
* more than one listener per window, so it shouldn't be too long.
*/
AutoTArray<nsCOMPtr<nsIDOMMozWakeLockListener>, 2> listeners(mListeners);
for (uint32_t i = 0; i < listeners.Length(); ++i) {
listeners[i]->Callback(aTopic, aState);
}
return NS_OK;
}
bool
PowerManager::ScreenEnabled()
{
return hal::GetScreenEnabled();
}
void
PowerManager::SetScreenEnabled(bool aEnabled)
{
hal::SetScreenEnabled(aEnabled);
}
bool
PowerManager::KeyLightEnabled()
{
return hal::GetKeyLightEnabled();
}
void
PowerManager::SetKeyLightEnabled(bool aEnabled)
{
hal::SetKeyLightEnabled(aEnabled);
}
double
PowerManager::ScreenBrightness()
{
return hal::GetScreenBrightness();
}
void
PowerManager::SetScreenBrightness(double aBrightness, ErrorResult& aRv)
{
if (0 <= aBrightness && aBrightness <= 1) {
hal::SetScreenBrightness(aBrightness);
} else {
aRv.Throw(NS_ERROR_INVALID_ARG);
}
}
bool
PowerManager::CpuSleepAllowed()
{
return hal::GetCpuSleepAllowed();
}
void
PowerManager::SetCpuSleepAllowed(bool aAllowed)
{
hal::SetCpuSleepAllowed(aAllowed);
}
already_AddRefed<PowerManager>
PowerManager::CreateInstance(nsPIDOMWindowInner* aWindow)
{
RefPtr<PowerManager> powerManager = new PowerManager();
if (NS_FAILED(powerManager->Init(aWindow))) {
powerManager = nullptr;
}
return powerManager.forget();
}
} // namespace dom
} // namespace mozilla

@ -1,70 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_power_PowerManager_h
#define mozilla_dom_power_PowerManager_h
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "nsIDOMWakeLockListener.h"
#include "nsIDOMWindow.h"
#include "nsWeakReference.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/MozPowerManagerBinding.h"
class nsPIDOMWindowInner;
namespace mozilla {
class ErrorResult;
namespace dom {
class PowerManager final : public nsIDOMMozWakeLockListener
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PowerManager)
NS_DECL_NSIDOMMOZWAKELOCKLISTENER
nsresult Init(nsPIDOMWindowInner* aWindow);
nsresult Shutdown();
static already_AddRefed<PowerManager> CreateInstance(nsPIDOMWindowInner*);
// WebIDL
nsPIDOMWindowInner* GetParentObject() const
{
return mWindow;
}
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
void Reboot(ErrorResult& aRv);
void FactoryReset(mozilla::dom::FactoryResetReason& aReason);
void PowerOff(ErrorResult& aRv);
void AddWakeLockListener(nsIDOMMozWakeLockListener* aListener);
void RemoveWakeLockListener(nsIDOMMozWakeLockListener* aListener);
void GetWakeLockState(const nsAString& aTopic, nsAString& aState,
ErrorResult& aRv);
bool ScreenEnabled();
void SetScreenEnabled(bool aEnabled);
bool KeyLightEnabled();
void SetKeyLightEnabled(bool aEnabled);
double ScreenBrightness();
void SetScreenBrightness(double aBrightness, ErrorResult& aRv);
bool CpuSleepAllowed();
void SetCpuSleepAllowed(bool aAllowed);
private:
~PowerManager() {}
nsCOMPtr<nsPIDOMWindowInner> mWindow;
nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener> > mListeners;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_power_PowerManager_h

@ -24,24 +24,6 @@
#include <unistd.h>
#endif
#ifdef ANDROID
#include <android/log.h>
extern "C" char* PrintJSStack();
static void LogFunctionAndJSStack(const char* funcname) {
char *jsstack = PrintJSStack();
__android_log_print(ANDROID_LOG_INFO, "PowerManagerService", \
"Call to %s. The JS stack is:\n%s\n",
funcname,
jsstack ? jsstack : "<no JS stack>");
js_free(jsstack);
}
// bug 839452
#define LOG_FUNCTION_AND_JS_STACK() \
LogFunctionAndJSStack(__PRETTY_FUNCTION__);
#else
#define LOG_FUNCTION_AND_JS_STACK()
#endif
namespace mozilla {
namespace dom {
namespace power {
@ -69,12 +51,6 @@ void
PowerManagerService::Init()
{
RegisterWakeLockObserver(this);
// NB: default to *enabling* the watchdog even when the pref is
// absent, in case the profile might be damaged and we need to
// restart to repair it.
mWatchdogTimeoutSecs =
Preferences::GetInt("shutdown.watchdog.timeoutSecs", 10);
}
PowerManagerService::~PowerManagerService()
@ -119,68 +95,6 @@ PowerManagerService::Notify(const WakeLockInformation& aWakeLockInfo)
}
}
void
PowerManagerService::SyncProfile()
{
nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
if (obsServ) {
const char16_t* context = u"shutdown-persist";
obsServ->NotifyObservers(nullptr, "profile-change-net-teardown", context);
obsServ->NotifyObservers(nullptr, "profile-change-teardown", context);
obsServ->NotifyObservers(nullptr, "profile-before-change", context);
obsServ->NotifyObservers(nullptr, "profile-before-change-qm", context);
obsServ->NotifyObservers(nullptr, "profile-before-change-telemetry", context);
}
}
NS_IMETHODIMP
PowerManagerService::Reboot()
{
LOG_FUNCTION_AND_JS_STACK() // bug 839452
StartForceQuitWatchdog(eHalShutdownMode_Reboot, mWatchdogTimeoutSecs);
// To synchronize any unsaved user data before rebooting.
SyncProfile();
hal::Reboot();
MOZ_CRASH("hal::Reboot() shouldn't return");
}
NS_IMETHODIMP
PowerManagerService::PowerOff()
{
LOG_FUNCTION_AND_JS_STACK() // bug 839452
StartForceQuitWatchdog(eHalShutdownMode_PowerOff, mWatchdogTimeoutSecs);
// To synchronize any unsaved user data before powering off.
SyncProfile();
hal::PowerOff();
MOZ_CRASH("hal::PowerOff() shouldn't return");
}
NS_IMETHODIMP
PowerManagerService::Restart()
{
LOG_FUNCTION_AND_JS_STACK() // bug 839452
// FIXME/bug 796826 this implementation is currently gonk-specific,
// because it relies on the Gonk to initialize the Gecko processes to
// restart B2G. It's better to do it here to have a real "restart".
StartForceQuitWatchdog(eHalShutdownMode_Restart, mWatchdogTimeoutSecs);
// Ensure all content processes are dead before we continue
// restarting. This code is used to restart to apply updates, and
// if we don't join all the subprocesses, race conditions can cause
// them to see an inconsistent view of the application directory.
ContentParent::JoinAllSubprocesses();
// To synchronize any unsaved user data before restarting.
SyncProfile();
#ifdef XP_UNIX
sync();
#endif
_exit(0);
MOZ_CRASH("_exit() shouldn't return");
}
NS_IMETHODIMP
PowerManagerService::AddWakeLockListener(nsIDOMMozWakeLockListener *aListener)
{

@ -32,9 +32,7 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPOWERMANAGERSERVICE
PowerManagerService()
: mWatchdogTimeoutSecs(0)
{}
PowerManagerService() {}
static already_AddRefed<PowerManagerService> GetInstance();
@ -70,13 +68,9 @@ private:
void ComputeWakeLockState(const hal::WakeLockInformation& aWakeLockInfo,
nsAString &aState);
void SyncProfile();
static StaticRefPtr<PowerManagerService> sSingleton;
nsTArray<nsCOMPtr<nsIDOMMozWakeLockListener>> mWakeLockListeners;
int32_t mWatchdogTimeoutSecs;
};
} // namespace power

@ -15,7 +15,6 @@ XPIDL_SOURCES += [
XPIDL_MODULE = 'dom_power'
EXPORTS.mozilla.dom += [
'PowerManager.h',
'WakeLock.h',
]
@ -25,7 +24,6 @@ EXPORTS.mozilla.dom.power += [
]
UNIFIED_SOURCES += [
'PowerManager.cpp',
'PowerManagerService.cpp',
'WakeLock.cpp',
]
@ -35,5 +33,3 @@ include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']

@ -19,21 +19,6 @@ interface mozIDOMWindow;
[scriptable, builtinclass, uuid(ba7ca4c1-9d92-4425-a83b-85dd7fa953f7)]
interface nsIPowerManagerService : nsISupports
{
/**
* This API will power off the machine.
*/
void powerOff();
/**
* This API will completely shut down and boot the machine.
*/
void reboot();
/**
* This API will restart the Gecko processes without powering off the machine.
*/
void restart();
void addWakeLockListener(in nsIDOMMozWakeLockListener aListener);
void removeWakeLockListener(in nsIDOMMozWakeLockListener aListener);
DOMString getWakeLockState(in DOMString aTopic);

@ -1,4 +0,0 @@
[DEFAULT]
[browser_wakelocks.js]
skip-if = e10s # Bug ?????? - SpecialPowers issues ({file: "chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js" line: 759}]'[JavaScript Error: "content.window is undefined" {file: "chrome://mochikit/content/tests/SimpleTest/specialpowersAPI.js" line: 759}]' when calling method: [nsIObserver::observe]")

@ -1,225 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
waitForExplicitFinish();
var kUrlSource = "http://mochi.test:8888/";
var kDataSource = "data:text/html,";
var gOldPref;
var gWin, gWin1, gWin2;
var gTab, gTab1, gTab2;
var gLock, gLock1, gLock2;
var gCurStepIndex = -1;
var gSteps = [
function basicWakeLock() {
gTab = BrowserTestUtils.addTab(gBrowser, kUrlSource);
gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
let browser = gBrowser.getBrowserForTab(gTab);
browser.addEventListener("load", function(e) {
let nav = gWin.navigator;
let power = nav.mozPower;
gLock = nav.requestWakeLock("test");
ok(gLock != null,
"navigator.requestWakeLock should return a wake lock");
is(gLock.topic, "test",
"wake lock should remember the locked topic");
isnot(power.getWakeLockState("test"), "unlocked",
"topic is locked");
gLock.unlock();
is(gLock.topic, "test",
"wake lock should remember the locked topic even after unlock");
is(power.getWakeLockState("test"), "unlocked",
"topic is unlocked");
try {
gLock.unlock();
ok(false, "Should have thrown an error.");
} catch (e) {
is(e.name, "InvalidStateError", "double unlock should throw InvalidStateError");
is(e.code, DOMException.INVALID_STATE_ERR, "double unlock should throw InvalidStateError");
}
gBrowser.removeTab(gTab);
executeSoon(runNextStep);
}, {capture: true, once: true});
},
function multiWakeLock() {
gTab = BrowserTestUtils.addTab(gBrowser, kUrlSource);
gWin = gBrowser.getBrowserForTab(gTab).contentWindow;
let browser = gBrowser.getBrowserForTab(gTab);
browser.addEventListener("load", function(e) {
let nav = gWin.navigator;
let power = nav.mozPower;
let count = 0;
power.addWakeLockListener(function onWakeLockEvent(topic, state) {
is(topic, "test", "gLock topic is test");
ok(state == "unlocked" ||
state == "locked-foreground" ||
state == "locked-background",
"wake lock should be either locked or unlocked");
count++;
if (state == "locked-foreground" ||
state == "locked-background") {
is(count, 1,
"wake lock should be locked and the listener should only fire once");
}
if (state == "unlocked") {
is(count, 2,
"wake lock should be unlocked and the listener should only fire once");
ok(power.getWakeLockState("test") == "unlocked",
"topic is unlocked");
power.removeWakeLockListener(onWakeLockEvent);
gBrowser.removeTab(gTab);
executeSoon(runNextStep);
}
});
gLock1 = nav.requestWakeLock("test");
isnot(power.getWakeLockState("test"), "unlocked",
"topic is locked");
gLock2 = nav.requestWakeLock("test");
isnot(power.getWakeLockState("test"), "unlocked",
"topic is locked");
gLock1.unlock();
isnot(power.getWakeLockState("test"), "unlocked",
"topic is locked");
gLock2.unlock();
}, {capture: true, once: true});
},
function crossTabWakeLock1() {
gTab1 = BrowserTestUtils.addTab(gBrowser, kUrlSource);
gWin1 = gBrowser.getBrowserForTab(gTab1).contentWindow;
gTab2 = BrowserTestUtils.addTab(gBrowser, kUrlSource);
gWin2 = gBrowser.getBrowserForTab(gTab2).contentWindow;
gBrowser.selectedTab = gTab1;
let browser = gBrowser.getBrowserForTab(gTab2);
browser.addEventListener("load", function(e) {
gLock2 = gWin2.navigator.requestWakeLock("test");
is(gWin2.document.hidden, true,
"window is background")
is(gWin2.navigator.mozPower.getWakeLockState("test"), "locked-background",
"wake lock is background");
let doc2 = gWin2.document;
doc2.addEventListener("visibilitychange", function onVisibilityChange(e) {
if (!doc2.hidden) {
doc2.removeEventListener("visibilitychange", onVisibilityChange);
executeSoon(runNextStep);
}
});
gBrowser.selectedTab = gTab2;
}, {capture: true, once: true});
},
function crossTabWakeLock2() {
is(gWin2.document.hidden, false,
"window is foreground")
is(gWin2.navigator.mozPower.getWakeLockState("test"), "locked-foreground",
"wake lock is foreground");
gWin2.addEventListener("pagehide", function(e) {
executeSoon(runNextStep);
}, {capture: true, once: true});
gWin2.addEventListener("pageshow", function(e) {
executeSoon(runNextStep);
}, {capture: true, once: true});
gWin2.location = kDataSource;
},
function crossTabWakeLock3() {
is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
"wake lock should auto-unlock when page is unloaded");
gWin2.back();
// runNextStep called in onPageShow
},
function crossTabWakeLock4() {
is(gWin1.navigator.mozPower.getWakeLockState("test"), "locked-foreground",
"wake lock should auto-reacquire when page is available again");
gBrowser.selectedTab = gTab1;
executeSoon(runNextStep);
},
function crossTabWakeLock5() {
// Test again in background tab
is(gWin2.document.hidden, true,
"window is background")
is(gWin2.navigator.mozPower.getWakeLockState("test"), "locked-background",
"wake lock is background");
gWin2.addEventListener("pagehide", function(e) {
executeSoon(runNextStep);
}, {capture: true, once: true});
gWin2.addEventListener("pageshow", function(e) {
executeSoon(runNextStep);
}, {capture: true, once: true});
gWin2.location = kDataSource;
},
function crossTabWakeLock6() {
is(gWin1.navigator.mozPower.getWakeLockState("test"), "unlocked",
"wake lock should auto-unlock when page is unloaded");
gWin2.back();
// runNextStep called in onPageShow
},
function crossTabWakeLock7() {
is(gWin1.navigator.mozPower.getWakeLockState("test"), "locked-background",
"wake lock should auto-reacquire when page is available again");
gLock2.unlock();
gBrowser.selectedTab = gTab2;
executeSoon(runNextStep);
},
function crossTabWakeLock8() {
is(gWin1.document.hidden, true,
"gWin1 is background");
is(gWin2.document.hidden, false,
"gWin2 is foreground");
gLock1 = gWin1.navigator.requestWakeLock("test");
gLock2 = gWin2.navigator.requestWakeLock("test");
is(gWin1.navigator.mozPower.getWakeLockState("test"), "locked-foreground",
"topic is locked-foreground when one page is foreground and one is background");
gLock2.unlock();
is(gWin1.navigator.mozPower.getWakeLockState("test"), "locked-background",
"topic is locked-background when all locks are background");
gLock2 = gWin2.navigator.requestWakeLock("test");
is(gWin1.navigator.mozPower.getWakeLockState("test"), "locked-foreground",
"topic is locked-foreground when one page is foreground and one is background");
gLock1.unlock();
is(gWin1.navigator.mozPower.getWakeLockState("test"), "locked-foreground",
"topic is locked-foreground");
gBrowser.removeTab(gTab1);
gBrowser.removeTab(gTab2);
executeSoon(runNextStep);
},
];
function runNextStep() {
gCurStepIndex++;
if (gCurStepIndex < gSteps.length) {
gSteps[gCurStepIndex]();
} else {
finish();
}
}
function test() {
SpecialPowers.pushPrefEnv({"set": [["dom.wakelock.enabled", true]]},
runNextStep);
}

@ -1 +0,0 @@
[test_power_basics.html]

@ -1,40 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Power API</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Power API **/
SimpleTest.waitForExplicitFinish();
function startTest() {
doTest1();
}
function doTest1() {
window.frames[0].frameElement.setAttribute('onload', 'doTest3()');
power = window.frames[0].navigator.mozPower;
ok(power, "Should be able to access power manager with permission.");
window.frames[0].location.reload();
}
function doTest3() {
power = window.frames[0].navigator.mozPower;
ok(power, "Should be able to access power manager with permission.");
SimpleTest.finish();
}
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<iframe onload="startTest()"></iframe>
<pre id="test">
</pre>
</body>
</html>

@ -0,0 +1,6 @@
[DEFAULT]
support-files =
file_blocked_script.sjs
[test_bug1053321.html]
skip-if = os == 'android' # bug 1386644

@ -1,97 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
interface MozWakeLockListener;
/**
* The reason for the factory reset.
* "normal" : simple factory reset.
* "wipe" : will also attempt to wipe all user storage areas.
* "root" : simple factory reset that also root the phone to get more
* privileges when using devtools.
*/
enum FactoryResetReason {
"normal",
"wipe",
"root"
};
/**
* This interface implements navigator.mozPower
*/
[ChromeOnly]
interface MozPowerManager
{
[Throws]
void powerOff();
[Throws]
void reboot();
void factoryReset(optional FactoryResetReason reason = "normal");
/**
* The listeners are notified when a resource changes its lock state to:
* - unlocked
* - locked but not visible
* - locked and visible
*/
void addWakeLockListener(MozWakeLockListener aListener);
void removeWakeLockListener(MozWakeLockListener aListener);
/**
* Query the wake lock state of the topic.
*
* Possible states are:
*
* - "unlocked" - nobody holds the wake lock.
*
* - "locked-foreground" - at least one window holds the wake lock,
* and it is visible.
*
* - "locked-background" - at least one window holds the wake lock,
* but all of them are hidden.
*
* @param aTopic The resource name related to the wake lock.
*/
[Throws]
DOMString getWakeLockState(DOMString aTopic);
/**
* Is the device's screen currently enabled? This attribute controls the
* device's screen, so setting it to false will turn off the screen.
*/
attribute boolean screenEnabled;
/**
* Is the device's keypad/button backlight enabled? Setting it to false will
* turn off the device's keypad/button backlight. And the brightness level
* is the same as |screenBrightness|.
*/
attribute boolean keyLightEnabled;
/**
* How bright is the screen's backlight, on a scale from 0 (very dim) to 1
* (full brightness)? Setting this attribute modifies the screen's
* brightness.
*
* You can read and write this attribute even when the screen is disabled,
* but the backlight is off while the screen is disabled.
*
* If you write a value of X into this attribute, the attribute may not have
* the same value X when you later read it. Most screens don't support as
* many different brightness levels as there are doubles between 0 and 1, so
* we may reduce the value's precision before storing it.
*
* @throw NS_ERROR_INVALID_ARG if brightness is not in the range [0, 1].
*/
[SetterThrows]
attribute double screenBrightness;
/**
* Is it possible that the device's CPU will sleep after the screen is
* disabled? Setting this attribute to false will prevent the device
* entering suspend state.
*/
attribute boolean cpuSleepAllowed;
};

@ -188,8 +188,6 @@ partial interface Navigator {
readonly attribute boolean cookieEnabled;
[Throws, Constant, Cached, NeedsCallerType]
readonly attribute DOMString buildID;
[Throws, ChromeOnly, UnsafeInPrerendering]
readonly attribute MozPowerManager mozPower;
// WebKit/Blink/Trident/Presto support this.
[Throws, NeedsCallerType]

@ -698,7 +698,6 @@ WEBIDL_FILES = [
'MimeTypeArray.webidl',
'MouseEvent.webidl',
'MouseScrollEvent.webidl',
'MozPowerManager.webidl',
'MozSelfSupport.webidl',
'MozTimeManager.webidl',
'MozWakeLock.webidl',

@ -173,6 +173,8 @@ HTMLEditor::~HTMLEditor()
}
RemoveEventListeners();
HideAnonymousEditingUIs();
}
void

@ -543,22 +543,23 @@ TextureClient::Unlock()
}
if (mBorrowedDrawTarget) {
if (mOpenMode & OpenMode::OPEN_WRITE) {
mBorrowedDrawTarget->Flush();
if (mReadbackSink && !mData->ReadBack(mReadbackSink)) {
// Fallback implementation for reading back, because mData does not
// have a backend-specific implementation and returned false.
RefPtr<SourceSurface> snapshot = mBorrowedDrawTarget->Snapshot();
RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
mReadbackSink->ProcessReadback(dataSurf);
if (!(mOpenMode & OpenMode::OPEN_ASYNC_WRITE)) {
if (mOpenMode & OpenMode::OPEN_WRITE) {
mBorrowedDrawTarget->Flush();
if (mReadbackSink && !mData->ReadBack(mReadbackSink)) {
// Fallback implementation for reading back, because mData does not
// have a backend-specific implementation and returned false.
RefPtr<SourceSurface> snapshot = mBorrowedDrawTarget->Snapshot();
RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface();
mReadbackSink->ProcessReadback(dataSurf);
}
}
}
mBorrowedDrawTarget->DetachAllSnapshots();
// If this assertion is hit, it means something is holding a strong reference
// to our DrawTarget externally, which is not allowed.
MOZ_ASSERT_IF(!(mOpenMode & OpenMode::OPEN_ASYNC_WRITE),
mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
mBorrowedDrawTarget->DetachAllSnapshots();
// If this assertion is hit, it means something is holding a strong reference
// to our DrawTarget externally, which is not allowed.
MOZ_ASSERT(mBorrowedDrawTarget->refCount() <= mExpectedDtRefs);
}
mBorrowedDrawTarget = nullptr;
}

@ -1699,6 +1699,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
new AsyncImagePipelineManager(WebRenderBridgeParent::AllocIdNameSpace());
if (!api) {
mWrBridge = WebRenderBridgeParent::CreateDestroyed();
mWrBridge.get()->AddRef(); // IPDL reference
*aIdNamespace = mWrBridge->GetIdNamespace();
*aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
return mWrBridge;
@ -1706,11 +1707,11 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
api->SetRootPipeline(aPipelineId);
RefPtr<CompositorAnimationStorage> animStorage = GetAnimationStorage();
mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, Move(api), Move(asyncMgr), Move(animStorage));
*aIdNamespace = mWrBridge->GetIdNamespace();
mWrBridge.get()->AddRef(); // IPDL reference
*aIdNamespace = mWrBridge->GetIdNamespace();
mCompositorScheduler = mWrBridge->CompositorScheduler();
MOZ_ASSERT(mCompositorScheduler);
mWrBridge.get()->AddRef(); // IPDL reference
MonitorAutoLock lock(*sIndirectLayerTreesLock);
MOZ_ASSERT(sIndirectLayerTrees[mRootLayerTreeID].mWrBridge == nullptr);
sIndirectLayerTrees[mRootLayerTreeID].mWrBridge = mWrBridge;

@ -77,7 +77,9 @@ public:
// This is a wrapper around SetShadowVisibleRegion. Some layers have visible
// regions that extend beyond what is actually drawn. When performing CPU-
// based occlusion culling we must clamp the visible region to the actual
// area.
// area. Note that if a layer is opaque, it must not expand its visible
// region such that it might include non-opaque pixels, as may be the case
// for PaintedLayers with a restricted visible region.
virtual void SetRegionToRender(LayerIntRegion&& aRegion);
virtual void AssignToView(FrameBuilder* aBuilder,

@ -39,6 +39,13 @@ PaintedLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
return false;
}
mTextureOnWhite = mHost->AcquireTextureSourceOnWhite();
return true;
}
nsIntRegion
PaintedLayerMLGPU::GetRenderRegion()
{
nsIntRegion region;
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
// Note: we don't set PaintWillResample on our ContentTextureHost. The old
@ -49,12 +56,15 @@ PaintedLayerMLGPU::OnPrepareToRender(FrameBuilder* aBuilder)
// behavior), we might break up the visible region again. If that turns
// out to be a problem, we can factor this into ForEachDrawRect instead.
if (MayResample()) {
LayerIntRegion visible = Move(GetShadowVisibleRegion());
visible = visible.GetBounds();
SetShadowVisibleRegion(Move(visible));
}
region = GetShadowVisibleRegion().GetBounds().ToUnknownRect();
} else
#endif
return true;
{
region = GetShadowVisibleRegion().ToUnknownRegion();
}
region.AndWith(gfx::IntRect(region.GetBounds().TopLeft(), mTexture->GetSize()));
return region;
}
bool

@ -46,16 +46,14 @@ public:
MOZ_ASSERT(HasComponentAlpha());
return mTextureOnWhite;
}
ContentHostTexture* GetContentHost() const {
return mHost;
}
nsIntRegion GetRenderRegion() const {
nsIntRegion region = GetShadowVisibleRegion().ToUnknownRegion();
region.AndWith(gfx::IntRect(region.GetBounds().TopLeft(), mTexture->GetSize()));
return region;
}
// This can return a different region than GetShadowVisibleRegion or
// GetLocalVisibleRegion, since we make sure to clamp it to the
// texture size and account for resampling.
nsIntRegion GetRenderRegion();
MOZ_LAYER_DECL_NAME("PaintedLayerMLGPU", TYPE_PAINTED)

@ -388,58 +388,6 @@ NotifyBatteryChange(const BatteryInformation& aInfo)
BatteryObservers().BroadcastCachedInformation();
}
bool GetScreenEnabled()
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled(), false);
}
void SetScreenEnabled(bool aEnabled)
{
AssertMainThread();
PROXY_IF_SANDBOXED(SetScreenEnabled(aEnabled));
}
bool GetKeyLightEnabled()
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetKeyLightEnabled(), false);
}
void SetKeyLightEnabled(bool aEnabled)
{
AssertMainThread();
PROXY_IF_SANDBOXED(SetKeyLightEnabled(aEnabled));
}
bool GetCpuSleepAllowed()
{
// Generally for interfaces that are accessible by normal web content
// we should cache the result and be notified on state changes, like
// what the battery API does. But since this is only used by
// privileged interface, the synchronous getter is OK here.
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetCpuSleepAllowed(), true);
}
void SetCpuSleepAllowed(bool aAllowed)
{
AssertMainThread();
PROXY_IF_SANDBOXED(SetCpuSleepAllowed(aAllowed));
}
double GetScreenBrightness()
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness(), 0);
}
void SetScreenBrightness(double aBrightness)
{
AssertMainThread();
PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(aBrightness, 0.0, 1.0)));
}
class SystemClockChangeObserversManager : public ObserversManager<int64_t>
{
protected:
@ -527,27 +475,6 @@ AdjustSystemClock(int64_t aDeltaMilliseconds)
PROXY_IF_SANDBOXED(AdjustSystemClock(aDeltaMilliseconds));
}
void
SetTimezone(const nsCString& aTimezoneSpec)
{
AssertMainThread();
PROXY_IF_SANDBOXED(SetTimezone(aTimezoneSpec));
}
int32_t
GetTimezoneOffset()
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetTimezoneOffset(), 0);
}
nsCString
GetTimezone()
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetTimezone(), nsCString(""));
}
void
EnableSensorNotifications(SensorType aSensor) {
AssertMainThread();
@ -646,27 +573,6 @@ NotifyNetworkChange(const NetworkInformation& aInfo)
NetworkObservers().BroadcastCachedInformation();
}
void Reboot()
{
AssertMainProcess();
AssertMainThread();
PROXY_IF_SANDBOXED(Reboot());
}
void PowerOff()
{
AssertMainProcess();
AssertMainThread();
PROXY_IF_SANDBOXED(PowerOff());
}
void StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs)
{
AssertMainProcess();
AssertMainThread();
PROXY_IF_SANDBOXED(StartForceQuitWatchdog(aMode, aTimeoutSecs));
}
void
RegisterWakeLockObserver(WakeLockObserver* aObserver)
{
@ -766,18 +672,6 @@ DisableSwitchNotifications(SwitchDevice aDevice) {
PROXY_IF_SANDBOXED(DisableSwitchNotifications(aDevice));
}
SwitchState GetCurrentSwitchState(SwitchDevice aDevice)
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(GetCurrentSwitchState(aDevice), SWITCH_STATE_UNKNOWN);
}
void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
{
AssertMainThread();
PROXY_IF_SANDBOXED(NotifySwitchStateFromInputDevice(aDevice, aState));
}
typedef mozilla::ObserverList<SwitchEvent> SwitchObserverList;
static SwitchObserverList *sSwitchObserverLists = nullptr;
@ -910,12 +804,6 @@ ThreadPriorityToString(ThreadPriority aPriority)
}
}
void FactoryReset(mozilla::dom::FactoryResetReason& aReason)
{
AssertMainThread();
PROXY_IF_SANDBOXED(FactoryReset(aReason));
}
void
StartDiskSpaceWatcher()
{
@ -932,35 +820,5 @@ StopDiskSpaceWatcher()
PROXY_IF_SANDBOXED(StopDiskSpaceWatcher());
}
uint32_t
GetTotalSystemMemory()
{
return hal_impl::GetTotalSystemMemory();
}
bool IsHeadphoneEventFromInputDev()
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(IsHeadphoneEventFromInputDev(), false);
}
nsresult StartSystemService(const char* aSvcName, const char* aArgs)
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(StartSystemService(aSvcName, aArgs), NS_ERROR_FAILURE);
}
void StopSystemService(const char* aSvcName)
{
AssertMainThread();
PROXY_IF_SANDBOXED(StopSystemService(aSvcName));
}
bool SystemServiceIsRunning(const char* aSvcName)
{
AssertMainThread();
RETURN_PROXY_IF_SANDBOXED(SystemServiceIsRunning(aSvcName), false);
}
} // namespace hal
} // namespace mozilla

140
hal/Hal.h

@ -11,7 +11,6 @@
#include "base/platform_thread.h"
#include "nsTArray.h"
#include "mozilla/dom/battery/Types.h"
#include "mozilla/dom/MozPowerManagerBinding.h"
#include "mozilla/dom/network/Types.h"
#include "mozilla/dom/power/Types.h"
#include "mozilla/dom/ScreenOrientation.h"
@ -109,60 +108,6 @@ void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
*/
void NotifyBatteryChange(const hal::BatteryInformation& aBatteryInfo);
/**
* Determine whether the device's screen is currently enabled.
*/
bool GetScreenEnabled();
/**
* Enable or disable the device's screen.
*
* Note that it may take a few seconds for the screen to turn on or off.
*/
void SetScreenEnabled(bool aEnabled);
/**
* Determine whether the device's keypad/button backlight is currently enabled.
*/
bool GetKeyLightEnabled();
/**
* Enable or disable the device's keypad/button backlight.
*/
void SetKeyLightEnabled(bool aEnabled);
/**
* Get the brightness of the device's screen's backlight, on a scale from 0
* (very dim) to 1 (full blast).
*
* If the display is currently disabled, this returns the brightness the
* backlight will have when the display is re-enabled.
*/
double GetScreenBrightness();
/**
* Set the brightness of the device's screen's backlight, on a scale from 0
* (very dimm) to 1 (full blast). Values larger than 1 are treated like 1, and
* values smaller than 0 are treated like 0.
*
* Note that we may reduce the resolution of the given brightness value before
* sending it to the screen. Therefore if you call SetScreenBrightness(x)
* followed by GetScreenBrightness(), the value returned by
* GetScreenBrightness() may not be exactly x.
*/
void SetScreenBrightness(double aBrightness);
/**
* Determine whether the device is allowed to sleep.
*/
bool GetCpuSleepAllowed();
/**
* Set whether the device is allowed to suspend automatically after
* the screen is disabled.
*/
void SetCpuSleepAllowed(bool aAllowed);
/**
* Register an observer for the sensor of given type.
*
@ -231,25 +176,6 @@ void NotifyNetworkChange(const hal::NetworkInformation& aNetworkInfo);
*/
void AdjustSystemClock(int64_t aDeltaMilliseconds);
/**
* Set timezone
* @param aTimezoneSpec The definition can be found in
* http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
*/
void SetTimezone(const nsCString& aTimezoneSpec);
/**
* Get timezone
* http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
*/
nsCString GetTimezone();
/**
* Get timezone offset
* returns the timezone offset relative to UTC in minutes (DST effect included)
*/
int32_t GetTimezoneOffset();
/**
* Register observer for system clock changed notification.
* @param aObserver The observer that should be added.
@ -291,20 +217,6 @@ void UnregisterSystemTimezoneChangeObserver(
void NotifySystemTimezoneChange(
const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
/**
* Reboot the device.
*
* This API is currently only allowed to be used from the main process.
*/
void Reboot();
/**
* Power off the device.
*
* This API is currently only allowed to be used from the main process.
*/
void PowerOff();
/**
* Enable wake lock notifications from the backend.
*
@ -419,17 +331,6 @@ void UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aS
*/
void NotifySwitchChange(const hal::SwitchEvent& aEvent);
/**
* Get current switch information.
*/
hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice);
/**
* Notify switch status change from input device.
*/
void NotifySwitchStateFromInputDevice(hal::SwitchDevice aDevice,
hal::SwitchState aState);
/**
* Return true if the current platform supports the setting of process
* priority.
@ -461,20 +362,6 @@ void SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority);
void SetThreadPriority(PlatformThreadId aThreadId,
hal::ThreadPriority aThreadPriority);
/**
* Start a watchdog to compulsively shutdown the system if it hangs.
* @param aMode Specify how to shutdown the system.
* @param aTimeoutSecs Specify the delayed seconds to shutdown the system.
*
* This API is currently only allowed to be used from the main process.
*/
void StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs);
/**
* Perform Factory Reset to wipe out all user data.
*/
void FactoryReset(mozilla::dom::FactoryResetReason& aReason);
/**
* Start monitoring disk space for low space situations.
*
@ -489,33 +376,6 @@ void StartDiskSpaceWatcher();
*/
void StopDiskSpaceWatcher();
/**
* Get total system memory of device being run on in bytes.
*
* Returns 0 if we are unable to determine this information from /proc/meminfo.
*/
uint32_t GetTotalSystemMemory();
/**
* Determine whether the headphone switch event is from input device
*/
bool IsHeadphoneEventFromInputDev();
/**
* Start the system service with the specified name and arguments.
*/
nsresult StartSystemService(const char* aSvcName, const char* aArgs);
/**
* Stop the system service with the specified name.
*/
void StopSystemService(const char* aSvcName);
/**
* Determine whether the system service with the specified name is running.
*/
bool SystemServiceIsRunning(const char* aSvcName);
} // namespace MOZ_HAL_NAMESPACE
} // namespace mozilla

@ -20,19 +20,6 @@ namespace hal {
const uint64_t CONTENT_PROCESS_ID_UNKNOWN = uint64_t(-1);
const uint64_t CONTENT_PROCESS_ID_MAIN = 0;
/**
* These are defined by libhardware, specifically, hardware/libhardware/include/hardware/lights.h
* in the gonk subsystem.
* If these change and are exposed to JS, make sure nsIHal.idl is updated as well.
*/
enum ShutdownMode {
eHalShutdownMode_Unknown = -1,
eHalShutdownMode_PowerOff = 0,
eHalShutdownMode_Reboot = 1,
eHalShutdownMode_Restart = 2,
eHalShutdownMode_Count = 3
};
class SwitchEvent;
enum SwitchDevice {
@ -119,17 +106,6 @@ enum WakeLockControl {
namespace IPC {
/**
* Serializer for ShutdownMode.
*/
template <>
struct ParamTraits<mozilla::hal::ShutdownMode>
: public ContiguousEnumSerializer<
mozilla::hal::ShutdownMode,
mozilla::hal::eHalShutdownMode_Unknown,
mozilla::hal::eHalShutdownMode_Count>
{};
/**
* WakeLockControl serializer.
*/

@ -1,18 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
namespace mozilla {
namespace hal_impl {
void
FactoryReset(mozilla::dom::FactoryResetReason&)
{}
} // namespace hal_impl
} // namespace mozilla

@ -1,20 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
namespace mozilla {
namespace hal_impl {
uint32_t
GetTotalSystemMemory()
{
return 0;
}
} // namespace hal_impl
} // namespace mozilla

@ -1,25 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
namespace mozilla {
namespace hal_impl {
void
Reboot()
{}
void
PowerOff()
{}
void
StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
{}
} // namespace hal_impl
} // namespace mozilla

@ -2,6 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_fallback_FallbackScreenConfiguration_h
#define mozilla_fallback_FallbackScreenConfiguration_h
#include "Hal.h"
#include "mozilla/dom/ScreenOrientation.h"
#include "nsIScreenManager.h"
@ -39,4 +42,6 @@ GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration)
}
}
}
}
#endif // mozilla_fallback_FallbackScreenConfiguration_h

@ -1,41 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace mozilla {
namespace hal_impl {
bool
GetScreenEnabled()
{
return true;
}
void
SetScreenEnabled(bool aEnabled)
{}
bool
GetKeyLightEnabled()
{
return true;
}
void
SetKeyLightEnabled(bool aEnabled)
{}
double
GetScreenBrightness()
{
return 1;
}
void
SetScreenBrightness(double aBrightness)
{}
} // namespace hal_impl
} // namespace mozilla

Some files were not shown because too many files have changed in this diff Show More