mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
constellation: Pass system theme to new Pipelines (#37132)
Previously, when the theme was set it was only set on currently active `Window`s. This change makes setting the `Theme` stateful. Now the `Constellation` tracks what theme is applied to a `WebView` and properly passes that value to new `Pipeline`s when they are constructed. In addition, the value is passed to layout when that is constructed as well. Testing: this change adds a unit test. Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
c96de69e80
commit
d3e57a513c
19 changed files with 201 additions and 74 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1925,6 +1925,7 @@ dependencies = [
|
||||||
"servo_malloc_size_of",
|
"servo_malloc_size_of",
|
||||||
"servo_url",
|
"servo_url",
|
||||||
"strum_macros",
|
"strum_macros",
|
||||||
|
"stylo",
|
||||||
"stylo_traits",
|
"stylo_traits",
|
||||||
"url",
|
"url",
|
||||||
"webdriver",
|
"webdriver",
|
||||||
|
|
|
@ -172,6 +172,7 @@ use crate::browsingcontext::{
|
||||||
AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator,
|
AllBrowsingContextsIterator, BrowsingContext, FullyActiveBrowsingContextsIterator,
|
||||||
NewBrowsingContextInfo,
|
NewBrowsingContextInfo,
|
||||||
};
|
};
|
||||||
|
use crate::constellation_webview::ConstellationWebView;
|
||||||
use crate::event_loop::EventLoop;
|
use crate::event_loop::EventLoop;
|
||||||
use crate::pipeline::{InitialPipelineState, Pipeline};
|
use crate::pipeline::{InitialPipelineState, Pipeline};
|
||||||
use crate::process_manager::ProcessManager;
|
use crate::process_manager::ProcessManager;
|
||||||
|
@ -229,18 +230,6 @@ struct WebrenderWGPU {
|
||||||
wgpu_image_map: WGPUImageMap,
|
wgpu_image_map: WGPUImageMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Servo supports multiple top-level browsing contexts or “webviews”, so `Constellation` needs to
|
|
||||||
/// store webview-specific data for bookkeeping.
|
|
||||||
struct WebView {
|
|
||||||
/// The currently focused browsing context in this webview for key events.
|
|
||||||
/// The focused pipeline is the current entry of the focused browsing
|
|
||||||
/// context.
|
|
||||||
focused_browsing_context_id: BrowsingContextId,
|
|
||||||
|
|
||||||
/// The joint session history for this webview.
|
|
||||||
session_history: JointSessionHistory,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A browsing context group.
|
/// A browsing context group.
|
||||||
///
|
///
|
||||||
/// <https://html.spec.whatwg.org/multipage/#browsing-context-group>
|
/// <https://html.spec.whatwg.org/multipage/#browsing-context-group>
|
||||||
|
@ -324,7 +313,7 @@ pub struct Constellation<STF, SWF> {
|
||||||
compositor_proxy: CompositorProxy,
|
compositor_proxy: CompositorProxy,
|
||||||
|
|
||||||
/// Bookkeeping data for all webviews in the constellation.
|
/// Bookkeeping data for all webviews in the constellation.
|
||||||
webviews: WebViewManager<WebView>,
|
webviews: WebViewManager<ConstellationWebView>,
|
||||||
|
|
||||||
/// Channels for the constellation to send messages to the public
|
/// Channels for the constellation to send messages to the public
|
||||||
/// resource-related threads. There are two groups of resource threads: one
|
/// resource-related threads. There are two groups of resource threads: one
|
||||||
|
@ -895,6 +884,16 @@ where
|
||||||
if self.shutting_down {
|
if self.shutting_down {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let Some(theme) = self
|
||||||
|
.webviews
|
||||||
|
.get(webview_id)
|
||||||
|
.map(ConstellationWebView::theme)
|
||||||
|
else {
|
||||||
|
warn!("Tried to create Pipeline for uknown WebViewId: {webview_id:?}");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"{}: Creating new pipeline in {}",
|
"{}: Creating new pipeline in {}",
|
||||||
pipeline_id, browsing_context_id
|
pipeline_id, browsing_context_id
|
||||||
|
@ -973,6 +972,7 @@ where
|
||||||
time_profiler_chan: self.time_profiler_chan.clone(),
|
time_profiler_chan: self.time_profiler_chan.clone(),
|
||||||
mem_profiler_chan: self.mem_profiler_chan.clone(),
|
mem_profiler_chan: self.mem_profiler_chan.clone(),
|
||||||
viewport_details: initial_viewport_details,
|
viewport_details: initial_viewport_details,
|
||||||
|
theme,
|
||||||
event_loop,
|
event_loop,
|
||||||
load_data,
|
load_data,
|
||||||
prev_throttled: throttled,
|
prev_throttled: throttled,
|
||||||
|
@ -1436,8 +1436,8 @@ where
|
||||||
size_type,
|
size_type,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
EmbedderToConstellationMessage::ThemeChange(theme) => {
|
EmbedderToConstellationMessage::ThemeChange(webview_id, theme) => {
|
||||||
self.handle_theme_change(theme);
|
self.handle_theme_change(webview_id, theme);
|
||||||
},
|
},
|
||||||
EmbedderToConstellationMessage::TickAnimation(webview_ids) => {
|
EmbedderToConstellationMessage::TickAnimation(webview_ids) => {
|
||||||
self.handle_tick_animation(webview_ids)
|
self.handle_tick_animation(webview_ids)
|
||||||
|
@ -3142,13 +3142,8 @@ where
|
||||||
|
|
||||||
// Register this new top-level browsing context id as a webview and set
|
// Register this new top-level browsing context id as a webview and set
|
||||||
// its focused browsing context to be itself.
|
// its focused browsing context to be itself.
|
||||||
self.webviews.add(
|
self.webviews
|
||||||
webview_id,
|
.add(webview_id, ConstellationWebView::new(browsing_context_id));
|
||||||
WebView {
|
|
||||||
focused_browsing_context_id: browsing_context_id,
|
|
||||||
session_history: JointSessionHistory::new(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#creating-a-new-browsing-context-group
|
// https://html.spec.whatwg.org/multipage/#creating-a-new-browsing-context-group
|
||||||
let mut new_bc_group: BrowsingContextGroup = Default::default();
|
let mut new_bc_group: BrowsingContextGroup = Default::default();
|
||||||
|
@ -3554,10 +3549,7 @@ where
|
||||||
self.pipelines.insert(new_pipeline_id, pipeline);
|
self.pipelines.insert(new_pipeline_id, pipeline);
|
||||||
self.webviews.add(
|
self.webviews.add(
|
||||||
new_webview_id,
|
new_webview_id,
|
||||||
WebView {
|
ConstellationWebView::new(new_browsing_context_id),
|
||||||
focused_browsing_context_id: new_browsing_context_id,
|
|
||||||
session_history: JointSessionHistory::new(),
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/#bcg-append
|
// https://html.spec.whatwg.org/multipage/#bcg-append
|
||||||
|
@ -5623,18 +5615,31 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle theme change events from the embedder and forward them to the script thread
|
/// Handle theme change events from the embedder and forward them to all appropriate `ScriptThread`s.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "tracing",
|
feature = "tracing",
|
||||||
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
|
tracing::instrument(skip_all, fields(servo_profiling = true), level = "trace")
|
||||||
)]
|
)]
|
||||||
fn handle_theme_change(&mut self, theme: Theme) {
|
fn handle_theme_change(&mut self, webview_id: WebViewId, theme: Theme) {
|
||||||
|
let Some(webview) = self.webviews.get_mut(webview_id) else {
|
||||||
|
warn!("Received theme change request for uknown WebViewId: {webview_id:?}");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if !webview.set_theme(theme) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for pipeline in self.pipelines.values() {
|
for pipeline in self.pipelines.values() {
|
||||||
let msg = ScriptThreadMessage::ThemeChange(pipeline.id, theme);
|
if pipeline.webview_id != webview_id {
|
||||||
if let Err(err) = pipeline.event_loop.send(msg) {
|
continue;
|
||||||
|
}
|
||||||
|
if let Err(error) = pipeline
|
||||||
|
.event_loop
|
||||||
|
.send(ScriptThreadMessage::ThemeChange(pipeline.id, theme))
|
||||||
|
{
|
||||||
warn!(
|
warn!(
|
||||||
"{}: Failed to send theme change event to pipeline ({:?}).",
|
"{}: Failed to send theme change event to pipeline ({error:?}).",
|
||||||
pipeline.id, err
|
pipeline.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
components/constellation/constellation_webview.rs
Normal file
45
components/constellation/constellation_webview.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* 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 https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use base::id::BrowsingContextId;
|
||||||
|
use embedder_traits::Theme;
|
||||||
|
|
||||||
|
use crate::session_history::JointSessionHistory;
|
||||||
|
|
||||||
|
/// The `Constellation`'s view of a `WebView` in the embedding layer. This tracks all of the
|
||||||
|
/// `Constellation` state for this `WebView`.
|
||||||
|
pub(crate) struct ConstellationWebView {
|
||||||
|
/// The currently focused browsing context in this webview for key events.
|
||||||
|
/// The focused pipeline is the current entry of the focused browsing
|
||||||
|
/// context.
|
||||||
|
pub focused_browsing_context_id: BrowsingContextId,
|
||||||
|
|
||||||
|
/// The joint session history for this webview.
|
||||||
|
pub session_history: JointSessionHistory,
|
||||||
|
|
||||||
|
/// The [`Theme`] that this [`ConstellationWebView`] uses. This is communicated to all
|
||||||
|
/// `ScriptThread`s so that they know how to render the contents of a particular `WebView.
|
||||||
|
theme: Theme,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstellationWebView {
|
||||||
|
pub(crate) fn new(focused_browsing_context_id: BrowsingContextId) -> Self {
|
||||||
|
Self {
|
||||||
|
focused_browsing_context_id,
|
||||||
|
session_history: JointSessionHistory::new(),
|
||||||
|
theme: Theme::Light,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the [`Theme`] on this [`ConstellationWebView`] returning true if the theme changed.
|
||||||
|
pub(crate) fn set_theme(&mut self, new_theme: Theme) -> bool {
|
||||||
|
let old_theme = std::mem::replace(&mut self.theme, new_theme);
|
||||||
|
old_theme != self.theme
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the [`Theme`] of this [`ConstellationWebView`].
|
||||||
|
pub(crate) fn theme(&self) -> Theme {
|
||||||
|
self.theme
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ mod tracing;
|
||||||
|
|
||||||
mod browsingcontext;
|
mod browsingcontext;
|
||||||
mod constellation;
|
mod constellation;
|
||||||
|
mod constellation_webview;
|
||||||
mod event_loop;
|
mod event_loop;
|
||||||
mod logging;
|
mod logging;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
|
|
|
@ -25,7 +25,7 @@ use constellation_traits::{LoadData, SWManagerMsg, ScriptToConstellationChan};
|
||||||
use crossbeam_channel::{Sender, unbounded};
|
use crossbeam_channel::{Sender, unbounded};
|
||||||
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
|
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
|
||||||
use embedder_traits::user_content_manager::UserContentManager;
|
use embedder_traits::user_content_manager::UserContentManager;
|
||||||
use embedder_traits::{AnimationState, FocusSequenceNumber, ViewportDetails};
|
use embedder_traits::{AnimationState, FocusSequenceNumber, Theme, ViewportDetails};
|
||||||
use fonts::{SystemFontServiceProxy, SystemFontServiceProxySender};
|
use fonts::{SystemFontServiceProxy, SystemFontServiceProxySender};
|
||||||
use ipc_channel::Error;
|
use ipc_channel::Error;
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
|
@ -61,7 +61,7 @@ pub struct Pipeline {
|
||||||
/// The ID of the browsing context that contains this Pipeline.
|
/// The ID of the browsing context that contains this Pipeline.
|
||||||
pub browsing_context_id: BrowsingContextId,
|
pub browsing_context_id: BrowsingContextId,
|
||||||
|
|
||||||
/// The ID of the top-level browsing context that contains this Pipeline.
|
/// The [`WebViewId`] of the `WebView` that contains this Pipeline.
|
||||||
pub webview_id: WebViewId,
|
pub webview_id: WebViewId,
|
||||||
|
|
||||||
pub opener: Option<BrowsingContextId>,
|
pub opener: Option<BrowsingContextId>,
|
||||||
|
@ -170,6 +170,9 @@ pub struct InitialPipelineState {
|
||||||
/// The initial [`ViewportDetails`] to use when starting this new [`Pipeline`].
|
/// The initial [`ViewportDetails`] to use when starting this new [`Pipeline`].
|
||||||
pub viewport_details: ViewportDetails,
|
pub viewport_details: ViewportDetails,
|
||||||
|
|
||||||
|
/// The initial [`Theme`] to use when starting this new [`Pipeline`].
|
||||||
|
pub theme: Theme,
|
||||||
|
|
||||||
/// The ID of the pipeline namespace for this script thread.
|
/// The ID of the pipeline namespace for this script thread.
|
||||||
pub pipeline_namespace_id: PipelineNamespaceId,
|
pub pipeline_namespace_id: PipelineNamespaceId,
|
||||||
|
|
||||||
|
@ -224,6 +227,7 @@ impl Pipeline {
|
||||||
opener: state.opener,
|
opener: state.opener,
|
||||||
load_data: state.load_data.clone(),
|
load_data: state.load_data.clone(),
|
||||||
viewport_details: state.viewport_details,
|
viewport_details: state.viewport_details,
|
||||||
|
theme: state.theme,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = script_chan.send(ScriptThreadMessage::AttachLayout(new_layout_info))
|
if let Err(e) = script_chan.send(ScriptThreadMessage::AttachLayout(new_layout_info))
|
||||||
|
@ -280,6 +284,7 @@ impl Pipeline {
|
||||||
time_profiler_chan: state.time_profiler_chan,
|
time_profiler_chan: state.time_profiler_chan,
|
||||||
mem_profiler_chan: state.mem_profiler_chan,
|
mem_profiler_chan: state.mem_profiler_chan,
|
||||||
viewport_details: state.viewport_details,
|
viewport_details: state.viewport_details,
|
||||||
|
theme: state.theme,
|
||||||
script_chan: script_chan.clone(),
|
script_chan: script_chan.clone(),
|
||||||
load_data: state.load_data.clone(),
|
load_data: state.load_data.clone(),
|
||||||
script_port,
|
script_port,
|
||||||
|
@ -494,6 +499,7 @@ pub struct UnprivilegedPipelineContent {
|
||||||
time_profiler_chan: time::ProfilerChan,
|
time_profiler_chan: time::ProfilerChan,
|
||||||
mem_profiler_chan: profile_mem::ProfilerChan,
|
mem_profiler_chan: profile_mem::ProfilerChan,
|
||||||
viewport_details: ViewportDetails,
|
viewport_details: ViewportDetails,
|
||||||
|
theme: Theme,
|
||||||
script_chan: IpcSender<ScriptThreadMessage>,
|
script_chan: IpcSender<ScriptThreadMessage>,
|
||||||
load_data: LoadData,
|
load_data: LoadData,
|
||||||
script_port: IpcReceiver<ScriptThreadMessage>,
|
script_port: IpcReceiver<ScriptThreadMessage>,
|
||||||
|
@ -544,6 +550,7 @@ impl UnprivilegedPipelineContent {
|
||||||
memory_profiler_sender: self.mem_profiler_chan.clone(),
|
memory_profiler_sender: self.mem_profiler_chan.clone(),
|
||||||
devtools_server_sender: self.devtools_ipc_sender,
|
devtools_server_sender: self.devtools_ipc_sender,
|
||||||
viewport_details: self.viewport_details,
|
viewport_details: self.viewport_details,
|
||||||
|
theme: self.theme,
|
||||||
pipeline_namespace_id: self.pipeline_namespace_id,
|
pipeline_namespace_id: self.pipeline_namespace_id,
|
||||||
content_process_shutdown_sender: content_process_shutdown_chan,
|
content_process_shutdown_sender: content_process_shutdown_chan,
|
||||||
webgl_chan: self.webgl_chan,
|
webgl_chan: self.webgl_chan,
|
||||||
|
|
|
@ -15,7 +15,7 @@ use base::Epoch;
|
||||||
use base::id::{PipelineId, WebViewId};
|
use base::id::{PipelineId, WebViewId};
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use constellation_traits::ScrollState;
|
use constellation_traits::ScrollState;
|
||||||
use embedder_traits::{UntrustedNodeAddress, ViewportDetails};
|
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
||||||
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect};
|
||||||
use euclid::{Point2D, Scale, Size2D, Vector2D};
|
use euclid::{Point2D, Scale, Size2D, Vector2D};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
|
@ -503,8 +503,7 @@ impl LayoutThread {
|
||||||
Scale::new(config.viewport_details.hidpi_scale_factor.get()),
|
Scale::new(config.viewport_details.hidpi_scale_factor.get()),
|
||||||
Box::new(LayoutFontMetricsProvider(config.font_context.clone())),
|
Box::new(LayoutFontMetricsProvider(config.font_context.clone())),
|
||||||
ComputedValues::initial_values_with_font_override(font),
|
ComputedValues::initial_values_with_font_override(font),
|
||||||
// TODO: obtain preferred color scheme from embedder
|
config.theme.into(),
|
||||||
PrefersColorScheme::Light,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
LayoutThread {
|
LayoutThread {
|
||||||
|
@ -951,7 +950,8 @@ impl LayoutThread {
|
||||||
size_did_change || pixel_ratio_did_change
|
size_did_change || pixel_ratio_did_change
|
||||||
}
|
}
|
||||||
|
|
||||||
fn theme_did_change(&self, theme: PrefersColorScheme) -> bool {
|
fn theme_did_change(&self, theme: Theme) -> bool {
|
||||||
|
let theme: PrefersColorScheme = theme.into();
|
||||||
theme != self.device().color_scheme()
|
theme != self.device().color_scheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -959,7 +959,7 @@ impl LayoutThread {
|
||||||
fn update_device(
|
fn update_device(
|
||||||
&mut self,
|
&mut self,
|
||||||
viewport_details: ViewportDetails,
|
viewport_details: ViewportDetails,
|
||||||
theme: PrefersColorScheme,
|
theme: Theme,
|
||||||
guards: &StylesheetGuards,
|
guards: &StylesheetGuards,
|
||||||
) {
|
) {
|
||||||
let device = Device::new(
|
let device = Device::new(
|
||||||
|
@ -969,7 +969,7 @@ impl LayoutThread {
|
||||||
Scale::new(viewport_details.hidpi_scale_factor.get()),
|
Scale::new(viewport_details.hidpi_scale_factor.get()),
|
||||||
Box::new(LayoutFontMetricsProvider(self.font_context.clone())),
|
Box::new(LayoutFontMetricsProvider(self.font_context.clone())),
|
||||||
self.stylist.device().default_computed_values().to_arc(),
|
self.stylist.device().default_computed_values().to_arc(),
|
||||||
theme,
|
theme.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Preserve any previously computed root font size.
|
// Preserve any previously computed root font size.
|
||||||
|
|
|
@ -223,6 +223,7 @@ impl HTMLIFrameElement {
|
||||||
old_pipeline_id,
|
old_pipeline_id,
|
||||||
sandbox: sandboxed,
|
sandbox: sandboxed,
|
||||||
viewport_details,
|
viewport_details,
|
||||||
|
theme: window.theme(),
|
||||||
};
|
};
|
||||||
window
|
window
|
||||||
.as_global_scope()
|
.as_global_scope()
|
||||||
|
@ -238,6 +239,7 @@ impl HTMLIFrameElement {
|
||||||
opener: None,
|
opener: None,
|
||||||
load_data,
|
load_data,
|
||||||
viewport_details,
|
viewport_details,
|
||||||
|
theme: window.theme(),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.pipeline_id.set(Some(new_pipeline_id));
|
self.pipeline_id.set(Some(new_pipeline_id));
|
||||||
|
@ -250,6 +252,7 @@ impl HTMLIFrameElement {
|
||||||
old_pipeline_id,
|
old_pipeline_id,
|
||||||
sandbox: sandboxed,
|
sandbox: sandboxed,
|
||||||
viewport_details,
|
viewport_details,
|
||||||
|
theme: window.theme(),
|
||||||
};
|
};
|
||||||
window
|
window
|
||||||
.as_global_scope()
|
.as_global_scope()
|
||||||
|
|
|
@ -80,7 +80,6 @@ use style::dom::OpaqueNode;
|
||||||
use style::error_reporting::{ContextualParseError, ParseErrorReporter};
|
use style::error_reporting::{ContextualParseError, ParseErrorReporter};
|
||||||
use style::properties::PropertyId;
|
use style::properties::PropertyId;
|
||||||
use style::properties::style_structs::Font;
|
use style::properties::style_structs::Font;
|
||||||
use style::queries::values::PrefersColorScheme;
|
|
||||||
use style::selector_parser::PseudoElement;
|
use style::selector_parser::PseudoElement;
|
||||||
use style::str::HTML_SPACE_CHARACTERS;
|
use style::str::HTML_SPACE_CHARACTERS;
|
||||||
use style::stylesheets::UrlExtraData;
|
use style::stylesheets::UrlExtraData;
|
||||||
|
@ -269,7 +268,7 @@ pub(crate) struct Window {
|
||||||
|
|
||||||
/// Platform theme.
|
/// Platform theme.
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
theme: Cell<PrefersColorScheme>,
|
theme: Cell<Theme>,
|
||||||
|
|
||||||
/// Parent id associated with this page, if any.
|
/// Parent id associated with this page, if any.
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
|
@ -2739,13 +2738,13 @@ impl Window {
|
||||||
self.viewport_details.get()
|
self.viewport_details.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the theme of this [`Window`].
|
||||||
|
pub(crate) fn theme(&self) -> Theme {
|
||||||
|
self.theme.get()
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle a theme change request, triggering a reflow is any actual change occured.
|
/// Handle a theme change request, triggering a reflow is any actual change occured.
|
||||||
pub(crate) fn handle_theme_change(&self, new_theme: Theme) {
|
pub(crate) fn handle_theme_change(&self, new_theme: Theme) {
|
||||||
let new_theme = match new_theme {
|
|
||||||
Theme::Light => PrefersColorScheme::Light,
|
|
||||||
Theme::Dark => PrefersColorScheme::Dark,
|
|
||||||
};
|
|
||||||
|
|
||||||
if self.theme.get() == new_theme {
|
if self.theme.get() == new_theme {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3033,6 +3032,7 @@ impl Window {
|
||||||
player_context: WindowGLContext,
|
player_context: WindowGLContext,
|
||||||
#[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
|
#[cfg(feature = "webgpu")] gpu_id_hub: Arc<IdentityHub>,
|
||||||
inherited_secure_context: Option<bool>,
|
inherited_secure_context: Option<bool>,
|
||||||
|
theme: Theme,
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
let error_reporter = CSSErrorReporter {
|
let error_reporter = CSSErrorReporter {
|
||||||
pipelineid: pipeline_id,
|
pipelineid: pipeline_id,
|
||||||
|
@ -3118,7 +3118,7 @@ impl Window {
|
||||||
throttled: Cell::new(false),
|
throttled: Cell::new(false),
|
||||||
layout_marker: DomRefCell::new(Rc::new(Cell::new(true))),
|
layout_marker: DomRefCell::new(Rc::new(Cell::new(true))),
|
||||||
current_event: DomRefCell::new(None),
|
current_event: DomRefCell::new(None),
|
||||||
theme: Cell::new(PrefersColorScheme::Light),
|
theme: Cell::new(theme),
|
||||||
trusted_types: Default::default(),
|
trusted_types: Default::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -329,6 +329,9 @@ impl WindowProxy {
|
||||||
opener: Some(self.browsing_context_id),
|
opener: Some(self.browsing_context_id),
|
||||||
load_data,
|
load_data,
|
||||||
viewport_details: window.viewport_details(),
|
viewport_details: window.viewport_details(),
|
||||||
|
// Use the current `WebView`'s theme initially, but the embedder may
|
||||||
|
// change this later.
|
||||||
|
theme: window.theme(),
|
||||||
};
|
};
|
||||||
ScriptThread::process_attach_layout(new_layout_info, document.origin().clone());
|
ScriptThread::process_attach_layout(new_layout_info, document.origin().clone());
|
||||||
// TODO: if noopener is false, copy the sessionStorage storage area of the creator origin.
|
// TODO: if noopener is false, copy the sessionStorage storage area of the creator origin.
|
||||||
|
|
|
@ -12,7 +12,7 @@ use base::cross_process_instant::CrossProcessInstant;
|
||||||
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
||||||
use constellation_traits::LoadData;
|
use constellation_traits::LoadData;
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use embedder_traits::ViewportDetails;
|
use embedder_traits::{Theme, ViewportDetails};
|
||||||
use http::header;
|
use http::header;
|
||||||
use net_traits::request::{
|
use net_traits::request::{
|
||||||
CredentialsMode, InsecureRequestsPolicy, RedirectMode, RequestBuilder, RequestMode,
|
CredentialsMode, InsecureRequestsPolicy, RedirectMode, RequestBuilder, RequestMode,
|
||||||
|
@ -159,6 +159,9 @@ pub(crate) struct InProgressLoad {
|
||||||
/// this load.
|
/// this load.
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
pub(crate) url_list: Vec<ServoUrl>,
|
pub(crate) url_list: Vec<ServoUrl>,
|
||||||
|
/// The [`Theme`] to use for this page, once it loads.
|
||||||
|
#[no_trace]
|
||||||
|
pub(crate) theme: Theme,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InProgressLoad {
|
impl InProgressLoad {
|
||||||
|
@ -171,6 +174,7 @@ impl InProgressLoad {
|
||||||
parent_info: Option<PipelineId>,
|
parent_info: Option<PipelineId>,
|
||||||
opener: Option<BrowsingContextId>,
|
opener: Option<BrowsingContextId>,
|
||||||
viewport_details: ViewportDetails,
|
viewport_details: ViewportDetails,
|
||||||
|
theme: Theme,
|
||||||
origin: MutableOrigin,
|
origin: MutableOrigin,
|
||||||
load_data: LoadData,
|
load_data: LoadData,
|
||||||
) -> InProgressLoad {
|
) -> InProgressLoad {
|
||||||
|
@ -189,6 +193,7 @@ impl InProgressLoad {
|
||||||
canceller: Default::default(),
|
canceller: Default::default(),
|
||||||
load_data,
|
load_data,
|
||||||
url_list: vec![url],
|
url_list: vec![url],
|
||||||
|
theme,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -403,14 +403,20 @@ impl ScriptThreadFactory for ScriptThread {
|
||||||
WebViewId::install(state.webview_id);
|
WebViewId::install(state.webview_id);
|
||||||
let roots = RootCollection::new();
|
let roots = RootCollection::new();
|
||||||
let _stack_roots = ThreadLocalStackRoots::new(&roots);
|
let _stack_roots = ThreadLocalStackRoots::new(&roots);
|
||||||
let id = state.id;
|
|
||||||
let browsing_context_id = state.browsing_context_id;
|
|
||||||
let webview_id = state.webview_id;
|
|
||||||
let parent_info = state.parent_info;
|
|
||||||
let opener = state.opener;
|
|
||||||
let memory_profiler_sender = state.memory_profiler_sender.clone();
|
let memory_profiler_sender = state.memory_profiler_sender.clone();
|
||||||
let viewport_details = state.viewport_details;
|
|
||||||
|
|
||||||
|
let in_progress_load = InProgressLoad::new(
|
||||||
|
state.id,
|
||||||
|
state.browsing_context_id,
|
||||||
|
state.webview_id,
|
||||||
|
state.parent_info,
|
||||||
|
state.opener,
|
||||||
|
state.viewport_details,
|
||||||
|
state.theme,
|
||||||
|
MutableOrigin::new(load_data.url.origin()),
|
||||||
|
load_data,
|
||||||
|
);
|
||||||
|
let reporter_name = format!("script-reporter-{:?}", state.id);
|
||||||
let script_thread = ScriptThread::new(state, layout_factory, system_font_service);
|
let script_thread = ScriptThread::new(state, layout_factory, system_font_service);
|
||||||
|
|
||||||
SCRIPT_THREAD_ROOT.with(|root| {
|
SCRIPT_THREAD_ROOT.with(|root| {
|
||||||
|
@ -419,19 +425,8 @@ impl ScriptThreadFactory for ScriptThread {
|
||||||
|
|
||||||
let mut failsafe = ScriptMemoryFailsafe::new(&script_thread);
|
let mut failsafe = ScriptMemoryFailsafe::new(&script_thread);
|
||||||
|
|
||||||
let origin = MutableOrigin::new(load_data.url.origin());
|
script_thread.pre_page_load(in_progress_load);
|
||||||
script_thread.pre_page_load(InProgressLoad::new(
|
|
||||||
id,
|
|
||||||
browsing_context_id,
|
|
||||||
webview_id,
|
|
||||||
parent_info,
|
|
||||||
opener,
|
|
||||||
viewport_details,
|
|
||||||
origin,
|
|
||||||
load_data,
|
|
||||||
));
|
|
||||||
|
|
||||||
let reporter_name = format!("script-reporter-{:?}", id);
|
|
||||||
memory_profiler_sender.run_with_memory_reporting(
|
memory_profiler_sender.run_with_memory_reporting(
|
||||||
|| {
|
|| {
|
||||||
script_thread.start(CanGc::note());
|
script_thread.start(CanGc::note());
|
||||||
|
@ -2435,6 +2430,7 @@ impl ScriptThread {
|
||||||
opener,
|
opener,
|
||||||
load_data,
|
load_data,
|
||||||
viewport_details,
|
viewport_details,
|
||||||
|
theme,
|
||||||
} = new_layout_info;
|
} = new_layout_info;
|
||||||
|
|
||||||
// Kick off the fetch for the new resource.
|
// Kick off the fetch for the new resource.
|
||||||
|
@ -2446,6 +2442,7 @@ impl ScriptThread {
|
||||||
parent_info,
|
parent_info,
|
||||||
opener,
|
opener,
|
||||||
viewport_details,
|
viewport_details,
|
||||||
|
theme,
|
||||||
origin,
|
origin,
|
||||||
load_data,
|
load_data,
|
||||||
);
|
);
|
||||||
|
@ -3189,6 +3186,7 @@ impl ScriptThread {
|
||||||
time_profiler_chan: self.senders.time_profiler_sender.clone(),
|
time_profiler_chan: self.senders.time_profiler_sender.clone(),
|
||||||
compositor_api: self.compositor_api.clone(),
|
compositor_api: self.compositor_api.clone(),
|
||||||
viewport_details: incomplete.viewport_details,
|
viewport_details: incomplete.viewport_details,
|
||||||
|
theme: incomplete.theme,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create the window and document objects.
|
// Create the window and document objects.
|
||||||
|
@ -3228,6 +3226,7 @@ impl ScriptThread {
|
||||||
#[cfg(feature = "webgpu")]
|
#[cfg(feature = "webgpu")]
|
||||||
self.gpu_id_hub.clone(),
|
self.gpu_id_hub.clone(),
|
||||||
incomplete.load_data.inherited_secure_context,
|
incomplete.load_data.inherited_secure_context,
|
||||||
|
incomplete.theme,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _realm = enter_realm(&*window);
|
let _realm = enter_realm(&*window);
|
||||||
|
|
|
@ -17,14 +17,21 @@ use std::rc::Rc;
|
||||||
use anyhow::ensure;
|
use anyhow::ensure;
|
||||||
use common::{ServoTest, run_api_tests};
|
use common::{ServoTest, run_api_tests};
|
||||||
use servo::{
|
use servo::{
|
||||||
JSValue, JavaScriptEvaluationError, LoadStatus, WebView, WebViewBuilder, WebViewDelegate,
|
JSValue, JavaScriptEvaluationError, LoadStatus, Theme, WebView, WebViewBuilder, WebViewDelegate,
|
||||||
};
|
};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct WebViewDelegateImpl {
|
struct WebViewDelegateImpl {
|
||||||
url_changed: Cell<bool>,
|
url_changed: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WebViewDelegateImpl {
|
||||||
|
pub(crate) fn reset(&self) {
|
||||||
|
self.url_changed.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WebViewDelegate for WebViewDelegateImpl {
|
impl WebViewDelegate for WebViewDelegateImpl {
|
||||||
fn notify_url_changed(&self, _webview: servo::WebView, _url: url::Url) {
|
fn notify_url_changed(&self, _webview: servo::WebView, _url: url::Url) {
|
||||||
self.url_changed.set(true);
|
self.url_changed.set(true);
|
||||||
|
@ -128,10 +135,40 @@ fn test_create_webview_and_immediately_drop_webview_before_shutdown(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_theme_change(servo_test: &ServoTest) -> Result<(), anyhow::Error> {
|
||||||
|
let delegate = Rc::new(WebViewDelegateImpl::default());
|
||||||
|
let webview = WebViewBuilder::new(servo_test.servo())
|
||||||
|
.delegate(delegate.clone())
|
||||||
|
.url(Url::parse("data:text/html,page one").unwrap())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let is_dark_theme_script = "window.matchMedia('(prefers-color-scheme: dark)').matches";
|
||||||
|
|
||||||
|
// The default theme is "light".
|
||||||
|
let result = evaluate_javascript(servo_test, webview.clone(), is_dark_theme_script);
|
||||||
|
ensure!(result == Ok(JSValue::Boolean(false)));
|
||||||
|
|
||||||
|
// Changing the theme updates the current page.
|
||||||
|
webview.notify_theme_change(Theme::Dark);
|
||||||
|
let result = evaluate_javascript(servo_test, webview.clone(), is_dark_theme_script);
|
||||||
|
ensure!(result == Ok(JSValue::Boolean(true)));
|
||||||
|
|
||||||
|
delegate.reset();
|
||||||
|
webview.load(Url::parse("data:text/html,page two").unwrap());
|
||||||
|
servo_test.spin(move || Ok(!delegate.url_changed.get()))?;
|
||||||
|
|
||||||
|
// The theme persists after a navigation.
|
||||||
|
let result = evaluate_javascript(servo_test, webview.clone(), is_dark_theme_script);
|
||||||
|
ensure!(result == Ok(JSValue::Boolean(true)));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
run_api_tests!(
|
run_api_tests!(
|
||||||
test_create_webview,
|
test_create_webview,
|
||||||
test_evaluate_javascript_basic,
|
test_evaluate_javascript_basic,
|
||||||
|
test_theme_change,
|
||||||
// This test needs to be last, as it tests creating and dropping
|
// This test needs to be last, as it tests creating and dropping
|
||||||
// a WebView right before shutdown.
|
// a WebView right before shutdown.
|
||||||
test_create_webview_and_immediately_drop_webview_before_shutdown
|
test_create_webview_and_immediately_drop_webview_before_shutdown
|
||||||
|
|
|
@ -395,7 +395,10 @@ impl WebView {
|
||||||
pub fn notify_theme_change(&self, theme: Theme) {
|
pub fn notify_theme_change(&self, theme: Theme) {
|
||||||
self.inner()
|
self.inner()
|
||||||
.constellation_proxy
|
.constellation_proxy
|
||||||
.send(EmbedderToConstellationMessage::ThemeChange(theme))
|
.send(EmbedderToConstellationMessage::ThemeChange(
|
||||||
|
self.id(),
|
||||||
|
theme,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(&self, url: Url) {
|
pub fn load(&self, url: Url) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use canvas_traits::canvas::{CanvasId, CanvasMsg};
|
||||||
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
|
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
|
||||||
use embedder_traits::{
|
use embedder_traits::{
|
||||||
AnimationState, EmbedderMsg, FocusSequenceNumber, JSValue, JavaScriptEvaluationError,
|
AnimationState, EmbedderMsg, FocusSequenceNumber, JSValue, JavaScriptEvaluationError,
|
||||||
JavaScriptEvaluationId, MediaSessionEvent, TouchEventResult, ViewportDetails,
|
JavaScriptEvaluationId, MediaSessionEvent, Theme, TouchEventResult, ViewportDetails,
|
||||||
WebDriverMessageId,
|
WebDriverMessageId,
|
||||||
};
|
};
|
||||||
use euclid::default::Size2D as UntypedSize2D;
|
use euclid::default::Size2D as UntypedSize2D;
|
||||||
|
@ -417,6 +417,8 @@ pub struct IFrameLoadInfoWithData {
|
||||||
pub sandbox: IFrameSandboxState,
|
pub sandbox: IFrameSandboxState,
|
||||||
/// The initial viewport size for this iframe.
|
/// The initial viewport size for this iframe.
|
||||||
pub viewport_details: ViewportDetails,
|
pub viewport_details: ViewportDetails,
|
||||||
|
/// The [`Theme`] to use within this iframe.
|
||||||
|
pub theme: Theme,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resources required by workerglobalscopes
|
/// Resources required by workerglobalscopes
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub enum EmbedderToConstellationMessage {
|
||||||
/// Inform the Constellation that a `WebView`'s [`ViewportDetails`] have changed.
|
/// Inform the Constellation that a `WebView`'s [`ViewportDetails`] have changed.
|
||||||
ChangeViewportDetails(WebViewId, ViewportDetails, WindowSizeType),
|
ChangeViewportDetails(WebViewId, ViewportDetails, WindowSizeType),
|
||||||
/// Inform the constellation of a theme change.
|
/// Inform the constellation of a theme change.
|
||||||
ThemeChange(Theme),
|
ThemeChange(WebViewId, Theme),
|
||||||
/// Requests that the constellation instruct script/layout to try to layout again and tick
|
/// Requests that the constellation instruct script/layout to try to layout again and tick
|
||||||
/// animations.
|
/// animations.
|
||||||
TickAnimation(Vec<WebViewId>),
|
TickAnimation(Vec<WebViewId>),
|
||||||
|
|
|
@ -35,6 +35,7 @@ serde = { workspace = true }
|
||||||
servo_url = { path = "../../url" }
|
servo_url = { path = "../../url" }
|
||||||
strum_macros = { workspace = true }
|
strum_macros = { workspace = true }
|
||||||
stylo_traits = { workspace = true }
|
stylo_traits = { workspace = true }
|
||||||
|
stylo = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
webdriver = { workspace = true }
|
webdriver = { workspace = true }
|
||||||
webrender_api = { workspace = true }
|
webrender_api = { workspace = true }
|
||||||
|
|
|
@ -34,6 +34,7 @@ use pixels::Image;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use strum_macros::IntoStaticStr;
|
use strum_macros::IntoStaticStr;
|
||||||
|
use style::queries::values::PrefersColorScheme;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
|
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
|
||||||
|
@ -598,6 +599,16 @@ pub enum Theme {
|
||||||
/// Dark theme.
|
/// Dark theme.
|
||||||
Dark,
|
Dark,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Theme> for PrefersColorScheme {
|
||||||
|
fn from(value: Theme) -> Self {
|
||||||
|
match value {
|
||||||
|
Theme::Light => PrefersColorScheme::Light,
|
||||||
|
Theme::Dark => PrefersColorScheme::Dark,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The type of MediaSession action.
|
// The type of MediaSession action.
|
||||||
/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
|
/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
|
||||||
|
|
|
@ -68,6 +68,8 @@ pub struct NewLayoutInfo {
|
||||||
pub load_data: LoadData,
|
pub load_data: LoadData,
|
||||||
/// Initial [`ViewportDetails`] for this layout.
|
/// Initial [`ViewportDetails`] for this layout.
|
||||||
pub viewport_details: ViewportDetails,
|
pub viewport_details: ViewportDetails,
|
||||||
|
/// The [`Theme`] of the new layout.
|
||||||
|
pub theme: Theme,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When a pipeline is closed, should its browsing context be discarded too?
|
/// When a pipeline is closed, should its browsing context be discarded too?
|
||||||
|
@ -321,6 +323,8 @@ pub struct InitialScriptState {
|
||||||
pub devtools_server_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
pub devtools_server_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
||||||
/// Initial [`ViewportDetails`] for the frame that is initiating this `ScriptThread`.
|
/// Initial [`ViewportDetails`] for the frame that is initiating this `ScriptThread`.
|
||||||
pub viewport_details: ViewportDetails,
|
pub viewport_details: ViewportDetails,
|
||||||
|
/// Initial [`Theme`] for the frame that is initiating this `ScriptThread`.
|
||||||
|
pub theme: Theme,
|
||||||
/// The ID of the pipeline namespace for this script thread.
|
/// The ID of the pipeline namespace for this script thread.
|
||||||
pub pipeline_namespace_id: PipelineNamespaceId,
|
pub pipeline_namespace_id: PipelineNamespaceId,
|
||||||
/// A ping will be sent on this channel once the script thread shuts down.
|
/// A ping will be sent on this channel once the script thread shuts down.
|
||||||
|
|
|
@ -20,7 +20,7 @@ use base::Epoch;
|
||||||
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
use base::id::{BrowsingContextId, PipelineId, WebViewId};
|
||||||
use compositing_traits::CrossProcessCompositorApi;
|
use compositing_traits::CrossProcessCompositorApi;
|
||||||
use constellation_traits::{LoadData, ScrollState};
|
use constellation_traits::{LoadData, ScrollState};
|
||||||
use embedder_traits::{UntrustedNodeAddress, ViewportDetails};
|
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
|
||||||
use euclid::default::{Point2D, Rect};
|
use euclid::default::{Point2D, Rect};
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use fonts::{FontContext, SystemFontServiceProxy};
|
use fonts::{FontContext, SystemFontServiceProxy};
|
||||||
|
@ -46,7 +46,6 @@ use style::invalidation::element::restyle_hints::RestyleHint;
|
||||||
use style::media_queries::Device;
|
use style::media_queries::Device;
|
||||||
use style::properties::PropertyId;
|
use style::properties::PropertyId;
|
||||||
use style::properties::style_structs::Font;
|
use style::properties::style_structs::Font;
|
||||||
use style::queries::values::PrefersColorScheme;
|
|
||||||
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
||||||
use style::stylesheets::Stylesheet;
|
use style::stylesheets::Stylesheet;
|
||||||
use webrender_api::ImageKey;
|
use webrender_api::ImageKey;
|
||||||
|
@ -182,6 +181,7 @@ pub struct LayoutConfig {
|
||||||
pub time_profiler_chan: time::ProfilerChan,
|
pub time_profiler_chan: time::ProfilerChan,
|
||||||
pub compositor_api: CrossProcessCompositorApi,
|
pub compositor_api: CrossProcessCompositorApi,
|
||||||
pub viewport_details: ViewportDetails,
|
pub viewport_details: ViewportDetails,
|
||||||
|
pub theme: Theme,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LayoutFactory: Send + Sync {
|
pub trait LayoutFactory: Send + Sync {
|
||||||
|
@ -428,7 +428,7 @@ pub struct ReflowRequest {
|
||||||
/// The set of image animations.
|
/// The set of image animations.
|
||||||
pub node_to_image_animation_map: FxHashMap<OpaqueNode, ImageAnimationState>,
|
pub node_to_image_animation_map: FxHashMap<OpaqueNode, ImageAnimationState>,
|
||||||
/// The theme for the window
|
/// The theme for the window
|
||||||
pub theme: PrefersColorScheme,
|
pub theme: Theme,
|
||||||
/// The node highlighted by the devtools, if any
|
/// The node highlighted by the devtools, if any
|
||||||
pub highlighted_dom_node: Option<OpaqueNode>,
|
pub highlighted_dom_node: Option<OpaqueNode>,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue