servo/components/shared/constellation/lib.rs
Martin Robinson cbc363bedd
compositor: Tick animations for an entire WebView at once (#36662)
Previously, when processing animations, the compositor would sent a tick
message to each pipeline. This is an issue because now the
`ScriptThread` always processes rendering updates for all `Document`s in
order to ensure properly ordering. This change makes it so that tick
messages are sent for an entire WebView. This means that each
`ScriptThread` will always receive a single tick for every time that
animations are processed, no matter how many frames are animating. This
is the first step toward a refresh driver.

In addition, we discard the idea of ticking animation only for
animations and or only for request animation frame callbacks. The
`ScriptThread` can no longer make this distinction due to the
specification and the compositor shouldn't either.

This should not really change observable behavior, but should make Servo
more efficient when more than a single frame in a `ScriptThread` is
animting at once.

Testing: This is covered by existing WPT tests as it mainly just improve
animation efficiency in a particular case.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
2025-04-24 19:03:14 +00:00

174 lines
7 KiB
Rust

/* 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/. */
//! The interface to the `Constellation`, which prevents other crates from depending directly on
//! the `constellation` crate itself. In addition to all messages to the `Constellation`, this
//! crate is responsible for defining types that cross the process boundary from the
//! embedding/rendering layer all the way to script, thus it should have very minimal dependencies
//! on other parts of Servo.
mod from_script_message;
mod structured_data;
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::time::Duration;
use base::Epoch;
use base::cross_process_instant::CrossProcessInstant;
use base::id::{MessagePortId, PipelineId, WebViewId};
use embedder_traits::{
CompositorHitTestResult, Cursor, InputEvent, MediaSessionActionType, Theme, ViewportDetails,
WebDriverCommandMsg,
};
use euclid::Vector2D;
pub use from_script_message::*;
use ipc_channel::ipc::IpcSender;
use malloc_size_of_derive::MallocSizeOf;
use serde::{Deserialize, Serialize};
use servo_url::{ImmutableOrigin, ServoUrl};
pub use structured_data::*;
use strum_macros::IntoStaticStr;
use webrender_api::ExternalScrollId;
use webrender_api::units::LayoutPixel;
/// Messages to the Constellation from the embedding layer, whether from `ServoRenderer` or
/// from `libservo` itself.
#[derive(IntoStaticStr)]
pub enum EmbedderToConstellationMessage {
/// Exit the constellation.
Exit,
/// Request that the constellation send the current focused top-level browsing context id,
/// over a provided channel.
GetFocusTopLevelBrowsingContext(IpcSender<Option<WebViewId>>),
/// Query the constellation to see if the current compositor output is stable
IsReadyToSaveImage(HashMap<PipelineId, Epoch>),
/// Whether to allow script to navigate.
AllowNavigationResponse(PipelineId, bool),
/// Request to load a page.
LoadUrl(WebViewId, ServoUrl),
/// Clear the network cache.
ClearCache,
/// Request to traverse the joint session history of the provided browsing context.
TraverseHistory(WebViewId, TraversalDirection),
/// Inform the Constellation that a `WebView`'s [`ViewportDetails`] have changed.
ChangeViewportDetails(WebViewId, ViewportDetails, WindowSizeType),
/// Inform the constellation of a theme change.
ThemeChange(Theme),
/// Requests that the constellation instruct script/layout to try to layout again and tick
/// animations.
TickAnimation(Vec<WebViewId>),
/// Dispatch a webdriver command
WebDriverCommand(WebDriverCommandMsg),
/// Reload a top-level browsing context.
Reload(WebViewId),
/// A log entry, with the top-level browsing context id and thread name
LogEntry(Option<WebViewId>, Option<String>, LogEntry),
/// Create a new top level browsing context.
NewWebView(ServoUrl, WebViewId, ViewportDetails),
/// Close a top level browsing context.
CloseWebView(WebViewId),
/// Panic a top level browsing context.
SendError(Option<WebViewId>, String),
/// Make a webview focused.
FocusWebView(WebViewId),
/// Make none of the webviews focused.
BlurWebView,
/// Forward an input event to an appropriate ScriptTask.
ForwardInputEvent(WebViewId, InputEvent, Option<CompositorHitTestResult>),
/// Requesting a change to the onscreen cursor.
SetCursor(WebViewId, Cursor),
/// Enable the sampling profiler, with a given sampling rate and max total sampling duration.
ToggleProfiler(Duration, Duration),
/// Request to exit from fullscreen mode
ExitFullScreen(WebViewId),
/// Media session action.
MediaSessionAction(MediaSessionActionType),
/// Set whether to use less resources, by stopping animations and running timers at a heavily limited rate.
SetWebViewThrottled(WebViewId, bool),
/// The Servo renderer scrolled and is updating the scroll states of the nodes in the
/// given pipeline via the constellation.
SetScrollStates(PipelineId, Vec<ScrollState>),
/// Notify the constellation that a particular paint metric event has happened for the given pipeline.
PaintMetric(PipelineId, PaintMetricEvent),
}
/// A description of a paint metric that is sent from the Servo renderer to the
/// constellation.
pub enum PaintMetricEvent {
FirstPaint(CrossProcessInstant, bool /* first_reflow */),
FirstContentfulPaint(CrossProcessInstant, bool /* first_reflow */),
}
impl fmt::Debug for EmbedderToConstellationMessage {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let variant_string: &'static str = self.into();
write!(formatter, "ConstellationMsg::{variant_string}")
}
}
/// A log entry reported to the constellation
/// We don't report all log entries, just serious ones.
/// We need a separate type for this because `LogLevel` isn't serializable.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum LogEntry {
/// Panic, with a reason and backtrace
Panic(String, String),
/// Error, with a reason
Error(String),
/// warning, with a reason
Warn(String),
}
/// The type of window size change.
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum WindowSizeType {
/// Initial load.
Initial,
/// Window resize.
Resize,
}
/// The scroll state of a stacking context.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct ScrollState {
/// The ID of the scroll root.
pub scroll_id: ExternalScrollId,
/// The scrolling offset of this stacking context.
pub scroll_offset: Vector2D<f32, LayoutPixel>,
}
/// The direction of a history traversal
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum TraversalDirection {
/// Travel forward the given number of documents.
Forward(usize),
/// Travel backward the given number of documents.
Back(usize),
}
/// A task on the <https://html.spec.whatwg.org/multipage/#port-message-queue>
#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct PortMessageTask {
/// The origin of this task.
pub origin: ImmutableOrigin,
/// A data-holder for serialized data and transferred objects.
pub data: StructuredSerializedData,
}
/// Messages for communication between the constellation and a global managing ports.
#[derive(Debug, Deserialize, Serialize)]
#[allow(clippy::large_enum_variant)]
pub enum MessagePortMsg {
/// Complete the transfer for a batch of ports.
CompleteTransfer(HashMap<MessagePortId, VecDeque<PortMessageTask>>),
/// Complete the transfer of a single port,
/// whose transfer was pending because it had been requested
/// while a previous failed transfer was being rolled-back.
CompletePendingTransfer(MessagePortId, VecDeque<PortMessageTask>),
/// Remove a port, the entangled one doesn't exists anymore.
RemoveMessagePort(MessagePortId),
/// Handle a new port-message-task.
NewTask(MessagePortId, PortMessageTask),
}