Bug 1591120 - Move print and color-scheme simulation to browsingContext. r=ochameau,nika,devtools-backward-compat-reviewers

We keep mMedium in nsPresContext rather than just looking it up in the
browsing context because that's used quite more frequently.

Differential Revision: https://phabricator.services.mozilla.com/D103782
This commit is contained in:
Emilio Cobos Álvarez 2021-02-03 10:38:09 +00:00
Родитель 635e3580e3
Коммит bfe77f303a
26 изменённых файлов: 291 добавлений и 506 удалений

Просмотреть файл

@ -1,26 +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";
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { contentViewerSpec } = require("devtools/shared/specs/content-viewer");
/**
* The corresponding Front object for the ContentViewer actor.
*/
class ContentViewerFront extends FrontClassWithSpec(contentViewerSpec) {
constructor(client, targetFront, parentFront) {
super(client, targetFront, parentFront);
// Attribute name from which to retrieve the actorID out of the target actor's form
this.formAttributeName = "contentViewerActor";
}
}
exports.ContentViewerFront = ContentViewerFront;
registerFront(ContentViewerFront);

Просмотреть файл

@ -19,7 +19,6 @@ DevToolsModules(
"breakpoint-list.js",
"changes.js",
"compatibility.js",
"content-viewer.js",
"css-properties.js",
"device.js",
"eventsource.js",

Просмотреть файл

@ -90,16 +90,17 @@ class Toolbar extends PureComponent {
onColorSchemeSimulationClick(event) {
event.stopPropagation();
this.props.onToggleColorSchemeSimulation();
let nextColorScheme =
(this.state.currentColorScheme + 1) % COLOR_SCHEMES.length;
this.props.onToggleColorSchemeSimulation(COLOR_SCHEMES[nextColorScheme]);
this.setState(prevState => ({
currentColorScheme:
(prevState.currentColorScheme + 1) % COLOR_SCHEMES.length,
currentColorScheme: nextColorScheme,
}));
}
onPrintSimulationToggle(event) {
event.stopPropagation();
this.props.onTogglePrintSimulation();
this.props.onTogglePrintSimulation(!this.state.isPrintSimulationEnabled);
this.setState(prevState => ({
isPrintSimulationEnabled: !prevState.isPrintSimulationEnabled,
}));

Просмотреть файл

@ -187,13 +187,6 @@ class RulesView {
* if they are supported in the current target.
*/
async initSimulationFeatures() {
// XXX: We used to initialize the front early in order to call
// actorHasMethod to check against backward compatibility. This is no longer
// necessary and the call to getFront could be done later if needed.
this.contentViewerFront = await this.currentTarget.getFront(
"contentViewer"
);
if (!this.currentTarget.chrome) {
this.store.dispatch(updatePrintSimulationHidden(false));
} else {
@ -241,11 +234,6 @@ class RulesView {
this.elementStyle = null;
}
if (this.contentViewerFront) {
this.contentViewerFront.destroy();
this.contentViewerFront = null;
}
this._dummyElement = null;
this.cssProperties = null;
this.doc = null;
@ -507,26 +495,24 @@ class RulesView {
/**
* Handler for toggling color scheme simulation.
*/
async onToggleColorSchemeSimulation() {
const currentState = await this.contentViewerFront.getEmulatedColorScheme();
const index = COLOR_SCHEMES.indexOf(currentState);
const nextState = COLOR_SCHEMES[(index + 1) % COLOR_SCHEMES.length];
await this.contentViewerFront.setEmulatedColorScheme(nextState);
async onToggleColorSchemeSimulation(nextState) {
await this.currentTarget.reconfigure({
options: {
colorSchemeSimulation: nextState,
}
});
await this.updateElementStyle();
}
/**
* Handler for toggling print media simulation.
*/
async onTogglePrintSimulation() {
const enabled = await this.contentViewerFront.getIsPrintSimulationEnabled();
if (!enabled) {
await this.contentViewerFront.startPrintMediaSimulation();
} else {
await this.contentViewerFront.stopPrintMediaSimulation(false);
}
async onTogglePrintSimulation(enabled) {
await this.currentTarget.reconfigure({
options: {
printSimulationEnabled: enabled,
}
});
await this.updateElementStyle();
}

Просмотреть файл

@ -507,13 +507,6 @@ CssRuleView.prototype = {
* if they are supported in the current target.
*/
async _initSimulationFeatures() {
// XXX: We used to initialize the front early in order to call
// actorHasMethod to check against backward compatibility. This is no longer
// necessary and the call to getFront could be done later if needed.
this.contentViewerFront = await this.currentTarget.getFront(
"contentViewer"
);
if (!this.currentTarget.chrome) {
this.printSimulationButton.removeAttribute("hidden");
this.printSimulationButton.addEventListener(
@ -842,22 +835,17 @@ CssRuleView.prototype = {
}
// Clean-up for print simulation.
if (this.contentViewerFront) {
this.colorSchemeSimulationButton.removeEventListener(
"click",
this._onToggleColorSchemeSimulation
);
this.printSimulationButton.removeEventListener(
"click",
this._onTogglePrintSimulation
);
this.colorSchemeSimulationButton.removeEventListener(
"click",
this._onToggleColorSchemeSimulation
);
this.printSimulationButton.removeEventListener(
"click",
this._onTogglePrintSimulation
);
this.contentViewerFront.destroy();
this.colorSchemeSimulationButton = null;
this.printSimulationButton = null;
this.contentViewerFront = null;
}
this.colorSchemeSimulationButton = null;
this.printSimulationButton = null;
this.tooltips.destroy();
@ -1750,7 +1738,7 @@ CssRuleView.prototype = {
},
async _onToggleColorSchemeSimulation() {
const currentState = await this.contentViewerFront.getEmulatedColorScheme();
const currentState = this.colorSchemeSimulationButton.getAttribute("state");
const index = COLOR_SCHEMES.indexOf(currentState);
const nextState = COLOR_SCHEMES[(index + 1) % COLOR_SCHEMES.length];
@ -1760,21 +1748,21 @@ CssRuleView.prototype = {
this.colorSchemeSimulationButton.removeAttribute("state");
}
await this.contentViewerFront.setEmulatedColorScheme(nextState);
this.currentTarget.reconfigure({
options: {
colorSchemeSimulation: nextState,
}
});
this.refreshPanel();
},
async _onTogglePrintSimulation() {
const enabled = await this.contentViewerFront.getIsPrintSimulationEnabled();
if (!enabled) {
this.printSimulationButton.classList.add("checked");
await this.contentViewerFront.startPrintMediaSimulation();
} else {
this.printSimulationButton.classList.remove("checked");
await this.contentViewerFront.stopPrintMediaSimulation(false);
}
const enabled = this.printSimulationButton.classList.toggle("checked");
this.currentTarget.reconfigure({
options: {
printSimulationEnabled: enabled,
}
});
// Refresh the current element's rules in the panel.
this.refreshPanel();
},

Просмотреть файл

@ -51,7 +51,6 @@ skip-if = !debug && ((os == 'linux' && bits == 64 && os_version == '18.04') || o
[browser_rules_class_panel_state_preserved.js]
[browser_rules_class_panel_toggle.js]
[browser_rules_color_scheme_simulation.js]
fail-if = fission # Bug 1678945
[browser_rules_colorpicker-and-image-tooltip_01.js]
[browser_rules_colorpicker-and-image-tooltip_02.js]
[browser_rules_colorpicker-appears-on-swatch-click-or-keyboard-activation.js]

Просмотреть файл

@ -1,128 +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";
const { Ci } = require("chrome");
const protocol = require("devtools/shared/protocol");
const { contentViewerSpec } = require("devtools/shared/specs/content-viewer");
/**
* This actor emulates various browser content environments by using methods available
* on the ContentViewer exposed by the platform.
*/
const ContentViewerActor = protocol.ActorClassWithSpec(contentViewerSpec, {
initialize(conn, targetActor) {
protocol.Actor.prototype.initialize.call(this, conn);
this.targetActor = targetActor;
this.docShell = targetActor.docShell;
this.onWillNavigate = this.onWillNavigate.bind(this);
this.onWindowReady = this.onWindowReady.bind(this);
this.targetActor.on("will-navigate", this.onWillNavigate);
this.targetActor.on("window-ready", this.onWindowReady);
},
destroy() {
this.stopPrintMediaSimulation();
this.setEmulatedColorScheme();
this.targetActor.off("will-navigate", this.onWillNavigate);
this.targetActor.off("window-ready", this.onWindowReady);
this.targetActor = null;
this.docShell = null;
protocol.Actor.prototype.destroy.call(this);
},
onWillNavigate({ isTopLevel }) {
// Make sure that print simulation is stopped before navigating to another page. We
// need to do this since the browser will cache the last state of the page in its
// session history.
if (this._printSimulationEnabled && isTopLevel) {
this.stopPrintMediaSimulation(true);
}
},
onWindowReady({ isTopLevel }) {
// Since `emulateMedium` only works for the current page, we need to ensure persistent
// print simulation for when the user navigates to a new page while its enabled.
// To do this, we need to tell the page to begin print simulation before the DOM
// content is available to the user:
if (this._printSimulationEnabled && isTopLevel) {
this.startPrintMediaSimulation();
}
},
/* Color scheme simulation */
/**
* Returns the currently emulated color scheme.
*/
getEmulatedColorScheme() {
return this._emulatedColorScheme;
},
/**
* Sets the currently emulated color scheme or if an invalid value is given,
* the override is cleared.
*/
setEmulatedColorScheme(scheme = null) {
if (this._emulatedColorScheme === scheme) {
return;
}
let internalColorScheme;
switch (scheme) {
case "light":
internalColorScheme = Ci.nsIContentViewer.PREFERS_COLOR_SCHEME_LIGHT;
break;
case "dark":
internalColorScheme = Ci.nsIContentViewer.PREFERS_COLOR_SCHEME_DARK;
break;
default:
internalColorScheme = Ci.nsIContentViewer.PREFERS_COLOR_SCHEME_NONE;
}
this._emulatedColorScheme = scheme;
this.docShell.contentViewer.emulatePrefersColorScheme(internalColorScheme);
},
// The current emulated color scheme value. It's possible values are listed in the
// COLOR_SCHEMES constant in devtools/client/inspector/rules/constants.
_emulatedColorScheme: null,
/* Simulating print media for the page */
_printSimulationEnabled: false,
getIsPrintSimulationEnabled() {
return this._printSimulationEnabled;
},
async startPrintMediaSimulation() {
this._printSimulationEnabled = true;
this.targetActor.docShell.contentViewer.emulateMedium("print");
},
/**
* Stop simulating print media for the current page.
*
* @param {Boolean} state
* Whether or not to set _printSimulationEnabled to false. If true, we want to
* stop simulation print media for the current page but NOT set
* _printSimulationEnabled to false. We do this specifically for the
* "will-navigate" event where we still want to continue simulating print when
* navigating to the next page. Defaults to false, meaning we want to completely
* stop print simulation.
*/
async stopPrintMediaSimulation(state = false) {
this._printSimulationEnabled = state;
this.targetActor.docShell.contentViewer.stopEmulatingMedium();
},
});
exports.ContentViewerActor = ContentViewerActor;

Просмотреть файл

@ -5,7 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
"content-viewer.js",
"responsive.js",
"touch-simulator.js",
)

Просмотреть файл

@ -1248,6 +1248,12 @@ const browsingContextTargetPrototype = {
) {
this._setPaintFlashingEnabled(options.paintFlashing);
}
if (typeof options.colorSchemeSimulation !== "undefined") {
this._setColorSchemeSimulation(options.colorSchemeSimulation);
}
if (typeof options.printSimulationEnabled !== "undefined") {
this._setPrintSimulationEnabled(options.printSimulationEnabled);
}
if (typeof options.serviceWorkersTestingEnabled !== "undefined") {
this._setServiceWorkersTestingEnabled(
options.serviceWorkersTestingEnabled
@ -1256,7 +1262,6 @@ const browsingContextTargetPrototype = {
if (typeof options.restoreFocus == "boolean") {
this._restoreFocus = options.restoreFocus;
}
// Reload if:
// - there's an explicit `performReload` flag and it's true
// - there's no `performReload` flag, but it makes sense to do so
@ -1278,6 +1283,8 @@ const browsingContextTargetPrototype = {
this._setCacheDisabled(false);
this._setServiceWorkersTestingEnabled(false);
this._setPaintFlashingEnabled(false);
this._setPrintSimulationEnabled(false);
this._setColorSchemeSimulation(null);
if (this._restoreFocus && this.browsingContext?.isActive) {
this.window.focus();
@ -1336,6 +1343,26 @@ const browsingContextTargetPrototype = {
}
},
/**
* Disable or enable the print simulation.
*/
_setPrintSimulationEnabled(enabled) {
let value = enabled ? "print" : "";
if (this.browsingContext.mediumOverride != value) {
this.browsingContext.mediumOverride = value;
}
},
/**
* Disable or enable the color-scheme simulation.
*/
_setColorSchemeSimulation(override) {
let value = override || "none";
if (this.browsingContext.prefersColorSchemeOverride != value) {
this.browsingContext.prefersColorSchemeOverride = value;
}
},
/**
* Disable or enable the paint flashing on the target.
*/

Просмотреть файл

@ -226,11 +226,6 @@ const ActorRegistry = {
constructor: "ResponsiveActor",
type: { target: true },
});
this.registerModule("devtools/server/actors/emulation/content-viewer", {
prefix: "contentViewer",
constructor: "ContentViewerActor",
type: { target: true },
});
this.registerModule(
"devtools/server/actors/addon/webextension-inspected-window",
{

Просмотреть файл

@ -1,47 +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";
const { Arg, RetVal, generateActorSpec } = require("devtools/shared/protocol");
const contentViewerSpec = generateActorSpec({
typeName: "contentViewer",
methods: {
getEmulatedColorScheme: {
request: {},
response: {
emulated: RetVal("nullable:string"),
},
},
setEmulatedColorScheme: {
request: {
scheme: Arg(0, "nullable:string"),
},
response: {},
},
getIsPrintSimulationEnabled: {
request: {},
response: {
enabled: RetVal("boolean"),
},
},
startPrintMediaSimulation: {
request: {},
response: {},
},
stopPrintMediaSimulation: {
request: {
state: Arg(0, "boolean"),
},
response: {},
},
},
});
exports.contentViewerSpec = contentViewerSpec;

Просмотреть файл

@ -57,11 +57,6 @@ const Types = (exports.__TypesForTests = [
spec: "devtools/shared/specs/compatibility",
front: "devtools/client/fronts/compatibility",
},
{
types: ["contentViewer"],
spec: "devtools/shared/specs/content-viewer",
front: "devtools/client/fronts/content-viewer",
},
{
types: ["cssProperties"],
spec: "devtools/shared/specs/css-properties",

Просмотреть файл

@ -19,7 +19,6 @@ DevToolsModules(
"breakpoint-list.js",
"changes.js",
"compatibility.js",
"content-viewer.js",
"css-properties.js",
"device.js",
"environment.js",

Просмотреть файл

@ -45,8 +45,10 @@ types.addDictType("browsingContextTarget.reload", {
types.addDictType("browsingContextTarget.reconfigure", {
javascriptEnabled: "nullable:boolean",
cacheDisabled: "nullable:boolean",
colorSchemeSimulation: "nullable:string",
serviceWorkersTestingEnabled: "nullable:boolean",
performReload: "nullable:boolean",
printSimulationEnabled: "nullable:boolean",
});
const browsingContextTargetSpecPrototype = {

Просмотреть файл

@ -96,6 +96,13 @@ struct ParamTraits<mozilla::dom::DisplayMode>
mozilla::dom::DisplayMode::Browser,
mozilla::dom::DisplayMode::EndGuard_> {};
template <>
struct ParamTraits<mozilla::dom::PrefersColorSchemeOverride>
: public ContiguousEnumSerializer<
mozilla::dom::PrefersColorSchemeOverride,
mozilla::dom::PrefersColorSchemeOverride::None,
mozilla::dom::PrefersColorSchemeOverride::EndGuard_> {};
template <>
struct ParamTraits<mozilla::dom::ExplicitActiveStatus>
: public ContiguousEnumSerializer<
@ -2476,10 +2483,42 @@ bool BrowsingContext::CanSet(
return true;
}
bool BrowsingContext::CanSet(FieldIndex<IDX_DisplayMode>,
const enum DisplayMode& aDisplayMOde,
ContentParent* aSource) {
return IsTop();
void BrowsingContext::DidSet(FieldIndex<IDX_PrefersColorSchemeOverride>,
dom::PrefersColorSchemeOverride aOldValue) {
MOZ_ASSERT(IsTop());
if (PrefersColorSchemeOverride() == aOldValue) {
return;
}
PreOrderWalk([&](BrowsingContext* aContext) {
if (nsIDocShell* shell = aContext->GetDocShell()) {
if (nsPresContext* pc = shell->GetPresContext()) {
// This is a bit of a lie, but it's the code-path that gets taken for
// regular system metrics changes via ThemeChanged().
// TODO(emilio): The JustThisDocument is a bit suspect here,
// prefers-color-scheme also applies to images or such, but the override
// means that we could need to render the same image both with "light"
// and "dark" appearance, so we just don't bother.
pc->MediaFeatureValuesChanged(
{MediaFeatureChangeReason::SystemMetricsChange},
MediaFeatureChangePropagation::JustThisDocument);
}
}
});
}
void BrowsingContext::DidSet(FieldIndex<IDX_MediumOverride>,
nsString&& aOldValue) {
MOZ_ASSERT(IsTop());
if (GetMediumOverride() == aOldValue) {
return;
}
PreOrderWalk([&](BrowsingContext* aContext) {
if (nsIDocShell* shell = aContext->GetDocShell()) {
if (nsPresContext* pc = shell->GetPresContext()) {
pc->RecomputeBrowsingContextDependentData();
}
}
});
}
void BrowsingContext::DidSet(FieldIndex<IDX_DisplayMode>,

Просмотреть файл

@ -95,105 +95,107 @@ enum class ExplicitActiveStatus : uint8_t {
// * `CanSet` is called before attempting to set the value, in both the process
// which calls `Set`, and the parent process, and will kill the misbehaving
// process if it fails.
#define MOZ_EACH_BC_FIELD(FIELD) \
FIELD(Name, nsString) \
FIELD(Closed, bool) \
FIELD(ExplicitActive, ExplicitActiveStatus) \
/* Top()-only. If true, new-playing media will be suspended when in an \
* inactive browsing context. */ \
FIELD(SuspendMediaWhenInactive, bool) \
/* If true, we're within the nested event loop in window.open, and this \
* context may not be used as the target of a load */ \
FIELD(PendingInitialization, bool) \
/* Indicates if the browser window is active for the purpose of the \
* :-moz-window-inactive pseudoclass. Only read from or set on the \
* top BrowsingContext. */ \
FIELD(IsActiveBrowserWindowInternal, bool) \
FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy) \
/* Current opener for the BrowsingContext. Weak reference */ \
FIELD(OpenerId, uint64_t) \
FIELD(OnePermittedSandboxedNavigatorId, uint64_t) \
/* WindowID of the inner window which embeds this BC */ \
FIELD(EmbedderInnerWindowId, uint64_t) \
FIELD(CurrentInnerWindowId, uint64_t) \
FIELD(HadOriginalOpener, bool) \
FIELD(IsPopupSpam, bool) \
/* Hold the audio muted state and should be used on top level browsing \
* contexts only */ \
FIELD(Muted, bool) \
/* See nsSandboxFlags.h for the possible flags. */ \
FIELD(SandboxFlags, uint32_t) \
FIELD(InitialSandboxFlags, uint32_t) \
/* A non-zero unique identifier for the browser element that is hosting \
* this \
* BrowsingContext tree. Every BrowsingContext in the element's tree will \
* return the same ID in all processes and it will remain stable \
* regardless of process changes. When a browser element's frameloader is \
* switched to another browser element this ID will remain the same but \
* hosted under the under the new browser element. */ \
FIELD(BrowserId, uint64_t) \
FIELD(HistoryID, nsID) \
FIELD(InRDMPane, bool) \
FIELD(Loading, bool) \
/* A field only set on top browsing contexts, which indicates that either: \
* \
* * This is a browsing context created explicitly for printing or print \
* preview (thus hosting static documents). \
* \
* * This is a browsing context where something in this tree is calling \
* window.print() (and thus showing a modal dialog). \
* \
* We use it exclusively to block navigation for both of these cases. */ \
FIELD(IsPrinting, bool) \
FIELD(AncestorLoading, bool) \
FIELD(AllowPlugins, bool) \
FIELD(AllowContentRetargeting, bool) \
FIELD(AllowContentRetargetingOnChildren, bool) \
FIELD(ForceEnableTrackingProtection, bool) \
FIELD(UseGlobalHistory, bool) \
FIELD(FullscreenAllowedByOwner, bool) \
/* These field are used to store the states of autoplay media request on \
* GeckoView only, and it would only be modified on the top level browsing \
* context. */ \
FIELD(GVAudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \
FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \
/* ScreenOrientation-related APIs */ \
FIELD(CurrentOrientationAngle, float) \
FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \
FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \
FIELD(UserAgentOverride, nsString) \
FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \
FIELD(EmbedderElementType, Maybe<nsString>) \
FIELD(MessageManagerGroup, nsString) \
FIELD(MaxTouchPointsOverride, uint8_t) \
FIELD(FullZoom, float) \
FIELD(WatchedByDevToolsInternal, bool) \
FIELD(TextZoom, float) \
/* The current in-progress load. */ \
FIELD(CurrentLoadIdentifier, Maybe<uint64_t>) \
/* See nsIRequest for possible flags. */ \
FIELD(DefaultLoadFlags, uint32_t) \
/* Signals that session history is enabled for this browsing context tree. \
* This is only ever set to true on the top BC, so consumers need to get \
* the value from the top BC! */ \
FIELD(HasSessionHistory, bool) \
/* Tracks if this context is the only top-level document in the session \
* history of the context. */ \
FIELD(IsSingleToplevelInHistory, bool) \
FIELD(UseErrorPages, bool) \
FIELD(PlatformOverride, nsString) \
FIELD(HasLoadedNonInitialDocument, bool) \
FIELD(CreatedDynamically, bool) \
/* Default value for nsIContentViewer::authorStyleDisabled in any new \
* browsing contexts created as a descendant of this one. Valid only for \
* top BCs. */ \
FIELD(AuthorStyleDisabledDefault, bool) \
FIELD(ServiceWorkersTestingEnabled, bool) \
FIELD(DisplayMode, mozilla::dom::DisplayMode) \
/* True if the top level browsing context owns a main media controller */ \
FIELD(HasMainMediaController, bool) \
/* The number of entries added to the session history because of this \
* browsing context. */ \
#define MOZ_EACH_BC_FIELD(FIELD) \
FIELD(Name, nsString) \
FIELD(Closed, bool) \
FIELD(ExplicitActive, ExplicitActiveStatus) \
/* Top()-only. If true, new-playing media will be suspended when in an \
* inactive browsing context. */ \
FIELD(SuspendMediaWhenInactive, bool) \
/* If true, we're within the nested event loop in window.open, and this \
* context may not be used as the target of a load */ \
FIELD(PendingInitialization, bool) \
/* Indicates if the browser window is active for the purpose of the \
* :-moz-window-inactive pseudoclass. Only read from or set on the \
* top BrowsingContext. */ \
FIELD(IsActiveBrowserWindowInternal, bool) \
FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy) \
/* Current opener for the BrowsingContext. Weak reference */ \
FIELD(OpenerId, uint64_t) \
FIELD(OnePermittedSandboxedNavigatorId, uint64_t) \
/* WindowID of the inner window which embeds this BC */ \
FIELD(EmbedderInnerWindowId, uint64_t) \
FIELD(CurrentInnerWindowId, uint64_t) \
FIELD(HadOriginalOpener, bool) \
FIELD(IsPopupSpam, bool) \
/* Hold the audio muted state and should be used on top level browsing \
* contexts only */ \
FIELD(Muted, bool) \
/* See nsSandboxFlags.h for the possible flags. */ \
FIELD(SandboxFlags, uint32_t) \
FIELD(InitialSandboxFlags, uint32_t) \
/* A non-zero unique identifier for the browser element that is hosting \
* this \
* BrowsingContext tree. Every BrowsingContext in the element's tree will \
* return the same ID in all processes and it will remain stable \
* regardless of process changes. When a browser element's frameloader is \
* switched to another browser element this ID will remain the same but \
* hosted under the under the new browser element. */ \
FIELD(BrowserId, uint64_t) \
FIELD(HistoryID, nsID) \
FIELD(InRDMPane, bool) \
FIELD(Loading, bool) \
/* A field only set on top browsing contexts, which indicates that either: \
* \
* * This is a browsing context created explicitly for printing or print \
* preview (thus hosting static documents). \
* \
* * This is a browsing context where something in this tree is calling \
* window.print() (and thus showing a modal dialog). \
* \
* We use it exclusively to block navigation for both of these cases. */ \
FIELD(IsPrinting, bool) \
FIELD(AncestorLoading, bool) \
FIELD(AllowPlugins, bool) \
FIELD(AllowContentRetargeting, bool) \
FIELD(AllowContentRetargetingOnChildren, bool) \
FIELD(ForceEnableTrackingProtection, bool) \
FIELD(UseGlobalHistory, bool) \
FIELD(FullscreenAllowedByOwner, bool) \
/* These field are used to store the states of autoplay media request on \
* GeckoView only, and it would only be modified on the top level browsing \
* context. */ \
FIELD(GVAudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \
FIELD(GVInaudibleAutoplayRequestStatus, GVAutoplayRequestStatus) \
/* ScreenOrientation-related APIs */ \
FIELD(CurrentOrientationAngle, float) \
FIELD(CurrentOrientationType, mozilla::dom::OrientationType) \
FIELD(OrientationLock, mozilla::hal::ScreenOrientation) \
FIELD(UserAgentOverride, nsString) \
FIELD(TouchEventsOverrideInternal, mozilla::dom::TouchEventsOverride) \
FIELD(EmbedderElementType, Maybe<nsString>) \
FIELD(MessageManagerGroup, nsString) \
FIELD(MaxTouchPointsOverride, uint8_t) \
FIELD(FullZoom, float) \
FIELD(WatchedByDevToolsInternal, bool) \
FIELD(TextZoom, float) \
/* The current in-progress load. */ \
FIELD(CurrentLoadIdentifier, Maybe<uint64_t>) \
/* See nsIRequest for possible flags. */ \
FIELD(DefaultLoadFlags, uint32_t) \
/* Signals that session history is enabled for this browsing context tree. \
* This is only ever set to true on the top BC, so consumers need to get \
* the value from the top BC! */ \
FIELD(HasSessionHistory, bool) \
/* Tracks if this context is the only top-level document in the session \
* history of the context. */ \
FIELD(IsSingleToplevelInHistory, bool) \
FIELD(UseErrorPages, bool) \
FIELD(PlatformOverride, nsString) \
FIELD(HasLoadedNonInitialDocument, bool) \
FIELD(CreatedDynamically, bool) \
/* Default value for nsIContentViewer::authorStyleDisabled in any new \
* browsing contexts created as a descendant of this one. Valid only for \
* top BCs. */ \
FIELD(AuthorStyleDisabledDefault, bool) \
FIELD(ServiceWorkersTestingEnabled, bool) \
FIELD(MediumOverride, nsString) \
FIELD(PrefersColorSchemeOverride, mozilla::dom::PrefersColorSchemeOverride) \
FIELD(DisplayMode, mozilla::dom::DisplayMode) \
/* True if the top level browsing context owns a main media controller */ \
FIELD(HasMainMediaController, bool) \
/* The number of entries added to the session history because of this \
* browsing context. */ \
FIELD(HistoryEntryCount, uint32_t)
// BrowsingContext, in this context, is the cross process replicated
@ -794,6 +796,14 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return GetServiceWorkersTestingEnabled();
}
void GetMediumOverride(nsAString& aOverride) const {
aOverride = GetMediumOverride();
}
dom::PrefersColorSchemeOverride PrefersColorSchemeOverride() const {
return GetPrefersColorSchemeOverride();
}
protected:
virtual ~BrowsingContext();
BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup,
@ -887,6 +897,20 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
return IsTop();
}
bool CanSet(FieldIndex<IDX_MediumOverride>, const nsString&, ContentParent*) {
return IsTop();
}
bool CanSet(FieldIndex<IDX_PrefersColorSchemeOverride>,
dom::PrefersColorSchemeOverride, ContentParent*) {
return IsTop();
}
void DidSet(FieldIndex<IDX_PrefersColorSchemeOverride>,
dom::PrefersColorSchemeOverride aOldValue);
void DidSet(FieldIndex<IDX_MediumOverride>, nsString&& aOldValue);
bool CanSet(FieldIndex<IDX_SuspendMediaWhenInactive>, bool, ContentParent*) {
return IsTop();
}
@ -896,7 +920,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
ContentParent* aSource);
bool CanSet(FieldIndex<IDX_DisplayMode>, const enum DisplayMode& aDisplayMode,
ContentParent* aSource);
ContentParent* aSource) {
return IsTop();
}
void DidSet(FieldIndex<IDX_DisplayMode>, enum DisplayMode aOldValue);
void DidSet(FieldIndex<IDX_ExplicitActive>, ExplicitActiveStatus aOldValue);

Просмотреть файл

@ -307,31 +307,6 @@ interface nsIContentViewer : nsISupports
*/
void resumePainting();
/*
* Render the document as if being viewed on a device with the specified
* media type. This will cause a reflow.
*
* @param mediaType The media type to be emulated
*/
void emulateMedium(in AString aMediaType);
/*
* Restore the viewer's natural media type
*/
void stopEmulatingMedium();
cenum PrefersColorScheme : 8 {
PREFERS_COLOR_SCHEME_LIGHT,
PREFERS_COLOR_SCHEME_DARK,
PREFERS_COLOR_SCHEME_NONE, /* This clears the override. */
};
/*
* Emulate or stop emulating the prefers color scheme on this page and
* subdocuments.
*/
void emulatePrefersColorScheme(in nsIContentViewer_PrefersColorScheme aPrefersColorScheme);
[noscript, notxpcom] Encoding getHintCharset();
[noscript, notxpcom] void setHintCharset(in Encoding aEncoding);
};

Просмотреть файл

@ -16826,11 +16826,19 @@ StylePrefersColorScheme Document::PrefersColorScheme(
return StylePrefersColorScheme::Light;
}
if (nsPresContext* pc = GetPresContext()) {
if (auto devtoolsOverride = pc->GetOverridePrefersColorScheme()) {
return *devtoolsOverride;
if (auto* bc = GetBrowsingContext()) {
switch (bc->Top()->PrefersColorSchemeOverride()) {
case dom::PrefersColorSchemeOverride::Dark:
return StylePrefersColorScheme::Dark;
case dom::PrefersColorSchemeOverride::Light:
return StylePrefersColorScheme::Light;
case dom::PrefersColorSchemeOverride::None:
case dom::PrefersColorSchemeOverride::EndGuard_:
break;
}
}
if (nsPresContext* pc = GetPresContext()) {
if (pc->IsPrintingOrPrintPreview()) {
return StylePrefersColorScheme::Light;
}

Просмотреть файл

@ -41,6 +41,15 @@ enum DisplayMode {
"fullscreen",
};
/**
* CSS prefers-color-scheme values.
*/
enum PrefersColorSchemeOverride {
"none",
"light",
"dark",
};
/**
* Allowed overrides of platform/pref default behaviour for touch events.
*/
@ -148,6 +157,12 @@ interface BrowsingContext {
// Enable some service workers testing features, for DevTools.
[SetterThrows] attribute boolean serviceWorkersTestingEnabled;
// Enable media query medium override, for DevTools.
[SetterThrows] attribute DOMString mediumOverride;
// Color-scheme simulation, for DevTools.
[SetterThrows] attribute PrefersColorSchemeOverride prefersColorSchemeOverride;
/**
* A unique identifier for the browser element that is hosting this
* BrowsingContext tree. Every BrowsingContext in the element's tree will

Просмотреть файл

@ -11,18 +11,14 @@
#define mozilla_MediaEmulationData_h
#include "nsAtom.h"
#include "mozilla/Maybe.h"
namespace mozilla {
enum class StylePrefersColorScheme : uint8_t;
struct MediaEmulationData final {
MediaEmulationData() = default;
RefPtr<nsAtom> mMedium;
float mDPPX = 0.0;
Maybe<StylePrefersColorScheme> mPrefersColorScheme;
};
} // namespace mozilla

Просмотреть файл

@ -339,11 +339,6 @@ class nsDocumentViewer final : public nsIContentViewer,
// nsIDocumentViewerPrint Printing Methods
NS_DECL_NSIDOCUMENTVIEWERPRINT
void EmulateMediumInternal(nsAtom*);
using ColorSchemeOverride = Maybe<StylePrefersColorScheme>;
void EmulatePrefersColorSchemeInternal(const ColorSchemeOverride&);
protected:
virtual ~nsDocumentViewer();
@ -2646,61 +2641,6 @@ nsDocumentViewer::GetAuthorStyleDisabled(bool* aStyleDisabled) {
return NS_OK;
}
void nsDocumentViewer::EmulateMediumInternal(nsAtom* aMedia) {
auto childFn = [&](nsDocumentViewer* aChild) {
aChild->EmulateMediumInternal(aMedia);
};
auto presContextFn = [&](nsPresContext* aPc) { aPc->EmulateMedium(aMedia); };
PropagateToPresContextsHelper(childFn, presContextFn);
}
NS_IMETHODIMP
nsDocumentViewer::EmulateMedium(const nsAString& aMediaType) {
nsAutoString mediaType;
nsContentUtils::ASCIIToLower(aMediaType, mediaType);
RefPtr<nsAtom> media = NS_Atomize(mediaType);
EmulateMediumInternal(media);
return NS_OK;
}
NS_IMETHODIMP
nsDocumentViewer::StopEmulatingMedium() {
EmulateMediumInternal(nullptr);
return NS_OK;
}
NS_IMETHODIMP
nsDocumentViewer::EmulatePrefersColorScheme(PrefersColorScheme aScheme) {
auto ToStyle = [](PrefersColorScheme aScheme) -> ColorSchemeOverride {
switch (aScheme) {
case PREFERS_COLOR_SCHEME_LIGHT:
return Some(StylePrefersColorScheme::Light);
case PREFERS_COLOR_SCHEME_DARK:
return Some(StylePrefersColorScheme::Dark);
case PREFERS_COLOR_SCHEME_NONE:
return Nothing();
default:
MOZ_ASSERT_UNREACHABLE("Unknown prefers color scheme value?");
return Nothing();
};
};
EmulatePrefersColorSchemeInternal(ToStyle(aScheme));
return NS_OK;
}
void nsDocumentViewer::EmulatePrefersColorSchemeInternal(
const ColorSchemeOverride& aOverride) {
auto childFn = [&aOverride](nsDocumentViewer* aChild) {
aChild->EmulatePrefersColorSchemeInternal(aOverride);
};
auto presContextFn = [&aOverride](nsPresContext* aPc) {
aPc->SetOverridePrefersColorScheme(aOverride);
};
PropagateToPresContextsHelper(childFn, presContextFn);
}
NS_IMETHODIMP nsDocumentViewer::GetHintCharacterSet(
nsACString& aHintCharacterSet) {
auto encoding = nsDocumentViewer::GetHintCharset();

Просмотреть файл

@ -768,11 +768,23 @@ void nsPresContext::RecomputeBrowsingContextDependentData() {
if (!browsingContext) {
// This can legitimately happen for e.g. SVG images. Those just get scaled
// as a result of the zoom on the embedder document so it doesn't really
// matter...
// matter... Medium also doesn't affect those.
return;
}
SetFullZoom(browsingContext->FullZoom());
SetTextZoom(browsingContext->TextZoom());
if (doc == mDocument) {
// Medium doesn't apply to resource documents, etc.
auto* top = browsingContext->Top();
RefPtr<nsAtom> mediumToEmulate;
if (MOZ_UNLIKELY(!top->GetMediumOverride().IsEmpty())) {
nsAutoString lower;
nsContentUtils::ASCIIToLower(top->GetMediumOverride(), lower);
mediumToEmulate = NS_Atomize(lower);
}
EmulateMedium(mediumToEmulate);
}
mDocument->EnumerateExternalResources([](dom::Document& aSubResource) {
if (nsPresContext* subResourcePc = aSubResource.GetPresContext()) {
subResourcePc->RecomputeBrowsingContextDependentData();
@ -1063,18 +1075,6 @@ void nsPresContext::SetOverrideDPPX(float aDPPX) {
MediaFeatureChangePropagation::JustThisDocument);
}
void nsPresContext::SetOverridePrefersColorScheme(
const Maybe<StylePrefersColorScheme>& aOverride) {
if (GetOverridePrefersColorScheme() == aOverride) {
return;
}
mMediaEmulationData.mPrefersColorScheme = aOverride;
// This is a bit of a lie, but it's the code-path that gets taken for regular
// system metrics changes via ThemeChanged().
MediaFeatureValuesChanged({MediaFeatureChangeReason::SystemMetricsChange},
MediaFeatureChangePropagation::JustThisDocument);
}
gfxSize nsPresContext::ScreenSizeInchesForFontInflation(bool* aChanged) {
if (aChanged) {
*aChanged = false;

Просмотреть файл

@ -135,7 +135,6 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
template <typename T>
using Maybe = mozilla::Maybe<T>;
using MediaEmulationData = mozilla::MediaEmulationData;
using StylePrefersColorScheme = mozilla::StylePrefersColorScheme;
typedef mozilla::ScrollStyles ScrollStyles;
using TransactionId = mozilla::layers::TransactionId;
@ -554,11 +553,6 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
*/
void RecomputeBrowsingContextDependentData();
Maybe<StylePrefersColorScheme> GetOverridePrefersColorScheme() const {
return mMediaEmulationData.mPrefersColorScheme;
}
void SetOverridePrefersColorScheme(const Maybe<StylePrefersColorScheme>&);
mozilla::CSSCoord GetAutoQualityMinFontSize() const {
return DevPixelsToFloatCSSPixels(mAutoQualityMinFontSizePixelsPref);
}

Просмотреть файл

@ -22,18 +22,19 @@ function colorId() {
}
{
let cv = SpecialPowers.wrap(window).docShell.contentViewer;
ok('emulatePrefersColorScheme' in cv, "API should exist");
let bc = SpecialPowers.wrap(window).browsingContext.top;
ok('prefersColorSchemeOverride' in bc, "API should exist");
is(bc.prefersColorSchemeOverride, "none", "Override shouldn't be active.");
let originalColor = colorId();
cv.emulatePrefersColorScheme(cv.PREFERS_COLOR_SCHEME_LIGHT);
bc.prefersColorSchemeOverride = "light";
is(colorId(), 1, "Light emulation works");
cv.emulatePrefersColorScheme(cv.PREFERS_COLOR_SCHEME_DARK);
bc.prefersColorSchemeOverride = "dark";
is(colorId(), 2, "Dark emulation works");
cv.emulatePrefersColorScheme(cv.PREFERS_COLOR_SCHEME_NONE);
bc.prefersColorSchemeOverride = "none";
is(colorId(), originalColor, "Clearing the override works");
}
</script>

Просмотреть файл

@ -32,6 +32,7 @@
using namespace mozilla;
using mozilla::dom::Document;
using mozilla::dom::DisplayMode;
static nsTArray<const nsStaticAtom*>* sSystemMetrics = nullptr;
@ -213,7 +214,7 @@ StyleDisplayMode Gecko_MediaFeatures_GetDisplayMode(const Document* aDocument) {
static_cast<int32_t>(StyleDisplayMode::Fullscreen),
"DisplayMode must mach nsStyleConsts.h");
BrowsingContext* browsingContext = aDocument->GetBrowsingContext();
dom::BrowsingContext* browsingContext = aDocument->GetBrowsingContext();
if (!browsingContext) {
return StyleDisplayMode::Browser;
}
@ -297,11 +298,10 @@ static PointerCapabilities GetPointerCapabilities(const Document* aDocument,
aID == LookAndFeel::IntID::AllPointerCapabilities);
MOZ_ASSERT(aDocument);
if (BrowsingContext* bc = aDocument->GetBrowsingContext()) {
if (dom::BrowsingContext* bc = aDocument->GetBrowsingContext()) {
// The touch-events-override happens only for the Responsive Design Mode so
// that we don't need to care about ResistFingerprinting.
if (bc->TouchEventsOverride() ==
mozilla::dom::TouchEventsOverride::Enabled) {
if (bc->TouchEventsOverride() == dom::TouchEventsOverride::Enabled) {
return PointerCapabilities::Coarse;
}
}

Просмотреть файл

@ -1190,10 +1190,11 @@ class SpecialPowersChild extends JSWindowActorChild {
}
emulateMedium(window, mediaType) {
this._getMUDV(window).emulateMedium(mediaType);
BrowsingContext.getFromWindow(window).top.mediumOverride = mediaType;
}
stopEmulatingMedium(window) {
this._getMUDV(window).stopEmulatingMedium();
BrowsingContext.getFromWindow(window).top.mediumOverride = "";
}
// Takes a snapshot of the given window and returns a <canvas>