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:
Martin Robinson 2025-05-26 14:05:38 +02:00 committed by GitHub
parent c96de69e80
commit d3e57a513c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 201 additions and 74 deletions

View file

@ -16,7 +16,7 @@ use canvas_traits::canvas::{CanvasId, CanvasMsg};
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use embedder_traits::{
AnimationState, EmbedderMsg, FocusSequenceNumber, JSValue, JavaScriptEvaluationError,
JavaScriptEvaluationId, MediaSessionEvent, TouchEventResult, ViewportDetails,
JavaScriptEvaluationId, MediaSessionEvent, Theme, TouchEventResult, ViewportDetails,
WebDriverMessageId,
};
use euclid::default::Size2D as UntypedSize2D;
@ -417,6 +417,8 @@ pub struct IFrameLoadInfoWithData {
pub sandbox: IFrameSandboxState,
/// The initial viewport size for this iframe.
pub viewport_details: ViewportDetails,
/// The [`Theme`] to use within this iframe.
pub theme: Theme,
}
/// Resources required by workerglobalscopes

View file

@ -55,7 +55,7 @@ pub enum EmbedderToConstellationMessage {
/// Inform the Constellation that a `WebView`'s [`ViewportDetails`] have changed.
ChangeViewportDetails(WebViewId, ViewportDetails, WindowSizeType),
/// 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
/// animations.
TickAnimation(Vec<WebViewId>),

View file

@ -35,6 +35,7 @@ serde = { workspace = true }
servo_url = { path = "../../url" }
strum_macros = { workspace = true }
stylo_traits = { workspace = true }
stylo = { workspace = true }
url = { workspace = true }
webdriver = { workspace = true }
webrender_api = { workspace = true }

View file

@ -34,6 +34,7 @@ use pixels::Image;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_url::ServoUrl;
use strum_macros::IntoStaticStr;
use style::queries::values::PrefersColorScheme;
use style_traits::CSSPixel;
use url::Url;
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel};
@ -598,6 +599,16 @@ pub enum Theme {
/// Dark theme.
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.
/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]

View file

@ -68,6 +68,8 @@ pub struct NewLayoutInfo {
pub load_data: LoadData,
/// Initial [`ViewportDetails`] for this layout.
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?
@ -321,6 +323,8 @@ pub struct InitialScriptState {
pub devtools_server_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// Initial [`ViewportDetails`] for the frame that is initiating this `ScriptThread`.
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.
pub pipeline_namespace_id: PipelineNamespaceId,
/// A ping will be sent on this channel once the script thread shuts down.

View file

@ -20,7 +20,7 @@ use base::Epoch;
use base::id::{BrowsingContextId, PipelineId, WebViewId};
use compositing_traits::CrossProcessCompositorApi;
use constellation_traits::{LoadData, ScrollState};
use embedder_traits::{UntrustedNodeAddress, ViewportDetails};
use embedder_traits::{Theme, UntrustedNodeAddress, ViewportDetails};
use euclid::default::{Point2D, Rect};
use fnv::FnvHashMap;
use fonts::{FontContext, SystemFontServiceProxy};
@ -46,7 +46,6 @@ use style::invalidation::element::restyle_hints::RestyleHint;
use style::media_queries::Device;
use style::properties::PropertyId;
use style::properties::style_structs::Font;
use style::queries::values::PrefersColorScheme;
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
use style::stylesheets::Stylesheet;
use webrender_api::ImageKey;
@ -182,6 +181,7 @@ pub struct LayoutConfig {
pub time_profiler_chan: time::ProfilerChan,
pub compositor_api: CrossProcessCompositorApi,
pub viewport_details: ViewportDetails,
pub theme: Theme,
}
pub trait LayoutFactory: Send + Sync {
@ -428,7 +428,7 @@ pub struct ReflowRequest {
/// The set of image animations.
pub node_to_image_animation_map: FxHashMap<OpaqueNode, ImageAnimationState>,
/// The theme for the window
pub theme: PrefersColorScheme,
pub theme: Theme,
/// The node highlighted by the devtools, if any
pub highlighted_dom_node: Option<OpaqueNode>,
}