mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-02 14:30:43 +00:00
Merge inbound to central, a=merge
MozReview-Commit-ID: 9NFjSEt96iT
This commit is contained in:
commit
baf6cddc4c
addon-sdk
browser
base/content
components
build
sessionstore
themes/osx
devtools
client
inspector
themes
server/actors/highlighters
docshell/base
dom
base
bindings
events
html
ipc
power
PowerManager.cppPowerManager.hPowerManagerService.cppPowerManagerService.hmoz.buildnsIPowerManagerService.idl
test
tests/mochitest/script
webidl
editor/libeditor
gfx/layers
client
ipc
mlgpu
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')
|
||||
|
46
browser/components/sessionstore/nsISessionStoreUtils.idl
Normal file
46
browser/components/sessionstore/nsISessionStoreUtils.idl
Normal file
@ -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);
|
||||
};
|
126
browser/components/sessionstore/nsSessionStoreUtils.cpp
Normal file
126
browser/components/sessionstore/nsSessionStoreUtils.cpp
Normal file
@ -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;
|
||||
}
|
29
browser/components/sessionstore/nsSessionStoreUtils.h
Normal file
29
browser/components/sessionstore/nsSessionStoreUtils.h
Normal file
@ -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>
|
6
dom/tests/mochitest/script/mochitest.ini
Normal file
6
dom/tests/mochitest/script/mochitest.ini
Normal file
@ -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)
|
||||
|
||||
|
142
hal/Hal.cpp
142
hal/Hal.cpp
@ -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
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
Loading…
x
Reference in New Issue
Block a user