script_traits/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! This module contains traits in script used generically in the rest of Servo.
6//! The traits are here instead of in script so that these modules won't have
7//! to depend on script.
8
9#![deny(missing_docs)]
10#![deny(unsafe_code)]
11
12use std::collections::HashMap;
13use std::fmt;
14use std::sync::Arc;
15
16use background_hang_monitor_api::BackgroundHangMonitorRegister;
17use base::cross_process_instant::CrossProcessInstant;
18use base::generic_channel::{GenericReceiver, GenericSender};
19use base::id::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId, WebViewId};
20#[cfg(feature = "bluetooth")]
21use bluetooth_traits::BluetoothRequest;
22use canvas_traits::webgl::WebGLPipeline;
23use compositing_traits::CrossProcessCompositorApi;
24use constellation_traits::{
25    LoadData, NavigationHistoryBehavior, ScriptToConstellationChan, StructuredSerializedData,
26    WindowSizeType,
27};
28use crossbeam_channel::{RecvTimeoutError, Sender};
29use devtools_traits::ScriptToDevtoolsControlMsg;
30use embedder_traits::user_content_manager::UserContentManager;
31use embedder_traits::{
32    CompositorHitTestResult, FocusSequenceNumber, InputEvent, JavaScriptEvaluationId,
33    MediaSessionActionType, Theme, ViewportDetails, WebDriverScriptCommand,
34};
35use euclid::{Rect, Scale, Size2D, UnknownUnit};
36use ipc_channel::ipc::{IpcReceiver, IpcSender};
37use keyboard_types::Modifiers;
38use malloc_size_of_derive::MallocSizeOf;
39use media::WindowGLContext;
40use net_traits::ResourceThreads;
41use net_traits::image_cache::ImageCache;
42use net_traits::storage_thread::StorageType;
43use pixels::PixelFormat;
44use profile_traits::mem;
45use serde::{Deserialize, Serialize};
46use servo_config::prefs::PrefValue;
47use servo_url::{ImmutableOrigin, ServoUrl};
48use strum_macros::IntoStaticStr;
49use style_traits::{CSSPixel, SpeculativePainter};
50use stylo_atoms::Atom;
51#[cfg(feature = "webgpu")]
52use webgpu_traits::WebGPUMsg;
53use webrender_api::units::{DevicePixel, LayoutVector2D};
54use webrender_api::{ExternalScrollId, ImageKey};
55
56/// The initial data required to create a new layout attached to an existing script thread.
57#[derive(Debug, Deserialize, Serialize)]
58pub struct NewLayoutInfo {
59    /// The ID of the parent pipeline and frame type, if any.
60    /// If `None`, this is a root pipeline.
61    pub parent_info: Option<PipelineId>,
62    /// Id of the newly-created pipeline.
63    pub new_pipeline_id: PipelineId,
64    /// Id of the browsing context associated with this pipeline.
65    pub browsing_context_id: BrowsingContextId,
66    /// Id of the top-level browsing context associated with this pipeline.
67    pub webview_id: WebViewId,
68    /// Id of the opener, if any
69    pub opener: Option<BrowsingContextId>,
70    /// Network request data which will be initiated by the script thread.
71    pub load_data: LoadData,
72    /// Initial [`ViewportDetails`] for this layout.
73    pub viewport_details: ViewportDetails,
74    /// The [`Theme`] of the new layout.
75    pub theme: Theme,
76}
77
78/// When a pipeline is closed, should its browsing context be discarded too?
79#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
80pub enum DiscardBrowsingContext {
81    /// Discard the browsing context
82    Yes,
83    /// Don't discard the browsing context
84    No,
85}
86
87/// Is a document fully active, active or inactive?
88/// A document is active if it is the current active document in its session history,
89/// it is fuly active if it is active and all of its ancestors are active,
90/// and it is inactive otherwise.
91///
92/// * <https://html.spec.whatwg.org/multipage/#active-document>
93/// * <https://html.spec.whatwg.org/multipage/#fully-active>
94#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
95pub enum DocumentActivity {
96    /// An inactive document
97    Inactive,
98    /// An active but not fully active document
99    Active,
100    /// A fully active document
101    FullyActive,
102}
103
104/// Type of recorded progressive web metric
105#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
106pub enum ProgressiveWebMetricType {
107    /// Time to first Paint
108    FirstPaint,
109    /// Time to first contentful paint
110    FirstContentfulPaint,
111    /// Time to interactive
112    TimeToInteractive,
113}
114
115/// The reason why the pipeline id of an iframe is being updated.
116#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
117pub enum UpdatePipelineIdReason {
118    /// The pipeline id is being updated due to a navigation.
119    Navigation,
120    /// The pipeline id is being updated due to a history traversal.
121    Traversal,
122}
123
124/// Messages sent to the `ScriptThread` event loop from the `Constellation`, `Compositor`, and (for
125/// now) `Layout`.
126#[derive(Deserialize, IntoStaticStr, Serialize)]
127pub enum ScriptThreadMessage {
128    /// Takes the associated window proxy out of "delaying-load-events-mode",
129    /// used if a scheduled navigated was refused by the embedder.
130    /// <https://html.spec.whatwg.org/multipage/#delaying-load-events-mode>
131    StopDelayingLoadEventsMode(PipelineId),
132    /// Gives a channel and ID to a layout, as well as the ID of that layout's parent
133    AttachLayout(NewLayoutInfo),
134    /// Window resized.  Sends a DOM event eventually, but first we combine events.
135    Resize(PipelineId, ViewportDetails, WindowSizeType),
136    /// Theme changed.
137    ThemeChange(PipelineId, Theme),
138    /// Notifies script that window has been resized but to not take immediate action.
139    ResizeInactive(PipelineId, ViewportDetails),
140    /// Window switched from fullscreen mode.
141    ExitFullScreen(PipelineId),
142    /// Notifies the script that the document associated with this pipeline should 'unload'.
143    UnloadDocument(PipelineId),
144    /// Notifies the script that a pipeline should be closed.
145    ExitPipeline(WebViewId, PipelineId, DiscardBrowsingContext),
146    /// Notifies the script that the whole thread should be closed.
147    ExitScriptThread,
148    /// Sends a DOM event.
149    SendInputEvent(PipelineId, ConstellationInputEvent),
150    /// Request that the given pipeline refresh the cursor by doing a hit test at the most
151    /// recently hovered cursor position and resetting the cursor. This happens after a
152    /// display list update is rendered.
153    RefreshCursor(PipelineId),
154    /// Notifies script of the viewport.
155    Viewport(PipelineId, Rect<f32, UnknownUnit>),
156    /// Requests that the script thread immediately send the constellation the title of a pipeline.
157    GetTitle(PipelineId),
158    /// Notifies script thread of a change to one of its document's activity
159    SetDocumentActivity(PipelineId, DocumentActivity),
160    /// Set whether to use less resources by running timers at a heavily limited rate.
161    SetThrottled(PipelineId, bool),
162    /// Notify the containing iframe (in PipelineId) that the nested browsing context (BrowsingContextId) is throttled.
163    SetThrottledInContainingIframe(PipelineId, BrowsingContextId, bool),
164    /// Notifies script thread that a url should be loaded in this iframe.
165    /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
166    NavigateIframe(
167        PipelineId,
168        BrowsingContextId,
169        LoadData,
170        NavigationHistoryBehavior,
171    ),
172    /// Post a message to a given window.
173    PostMessage {
174        /// The target of the message.
175        target: PipelineId,
176        /// The source of the message.
177        source: PipelineId,
178        /// The top level browsing context associated with the source pipeline.
179        source_browsing_context: WebViewId,
180        /// The expected origin of the target.
181        target_origin: Option<ImmutableOrigin>,
182        /// The source origin of the message.
183        /// <https://html.spec.whatwg.org/multipage/#dom-messageevent-origin>
184        source_origin: ImmutableOrigin,
185        /// The data to be posted.
186        data: Box<StructuredSerializedData>,
187    },
188    /// Updates the current pipeline ID of a given iframe.
189    /// First PipelineId is for the parent, second is the new PipelineId for the frame.
190    UpdatePipelineId(
191        PipelineId,
192        BrowsingContextId,
193        WebViewId,
194        PipelineId,
195        UpdatePipelineIdReason,
196    ),
197    /// Updates the history state and url of a given pipeline.
198    UpdateHistoryState(PipelineId, Option<HistoryStateId>, ServoUrl),
199    /// Removes inaccesible history states.
200    RemoveHistoryStates(PipelineId, Vec<HistoryStateId>),
201    /// Set an iframe to be focused. Used when an element in an iframe gains focus.
202    /// PipelineId is for the parent, BrowsingContextId is for the nested browsing context
203    FocusIFrame(PipelineId, BrowsingContextId, FocusSequenceNumber),
204    /// Focus the document. Used when the container gains focus.
205    FocusDocument(PipelineId, FocusSequenceNumber),
206    /// Notifies that the document's container (e.g., an iframe) is not included
207    /// in the top-level browsing context's focus chain (not considering system
208    /// focus) anymore.
209    ///
210    /// Obviously, this message is invalid for a top-level document.
211    Unfocus(PipelineId, FocusSequenceNumber),
212    /// Passes a webdriver command to the script thread for execution
213    WebDriverScriptCommand(PipelineId, WebDriverScriptCommand),
214    /// Notifies script thread that all animations are done
215    TickAllAnimations(Vec<WebViewId>),
216    /// Notifies the script thread that a new Web font has been loaded, and thus the page should be
217    /// reflowed.
218    WebFontLoaded(PipelineId, bool /* success */),
219    /// Cause a `load` event to be dispatched at the appropriate iframe element.
220    DispatchIFrameLoadEvent {
221        /// The frame that has been marked as loaded.
222        target: BrowsingContextId,
223        /// The pipeline that contains a frame loading the target pipeline.
224        parent: PipelineId,
225        /// The pipeline that has completed loading.
226        child: PipelineId,
227    },
228    /// Cause a `storage` event to be dispatched at the appropriate window.
229    /// The strings are key, old value and new value.
230    DispatchStorageEvent(
231        PipelineId,
232        StorageType,
233        ServoUrl,
234        Option<String>,
235        Option<String>,
236        Option<String>,
237    ),
238    /// Report an error from a CSS parser for the given pipeline
239    ReportCSSError(PipelineId, String, u32, u32, String),
240    /// Reload the given page.
241    Reload(PipelineId),
242    /// Notifies the script thread about a new recorded paint metric.
243    PaintMetric(
244        PipelineId,
245        ProgressiveWebMetricType,
246        CrossProcessInstant,
247        bool, /* first_reflow */
248    ),
249    /// Notifies the media session about a user requested media session action.
250    MediaSessionAction(PipelineId, MediaSessionActionType),
251    /// Notifies script thread that WebGPU server has started
252    #[cfg(feature = "webgpu")]
253    SetWebGPUPort(IpcReceiver<WebGPUMsg>),
254    /// The compositor scrolled and is updating the scroll states of the nodes in the given
255    /// pipeline via the Constellation.
256    SetScrollStates(PipelineId, HashMap<ExternalScrollId, LayoutVector2D>),
257    /// Evaluate the given JavaScript and return a result via a corresponding message
258    /// to the Constellation.
259    EvaluateJavaScript(PipelineId, JavaScriptEvaluationId, String),
260    /// A new batch of keys for the image cache for the specific pipeline.
261    SendImageKeysBatch(PipelineId, Vec<ImageKey>),
262    /// Preferences were updated in the parent process.
263    PreferencesUpdated(Vec<(String, PrefValue)>),
264    /// Notify the `ScriptThread` that the Servo renderer is no longer waiting on
265    /// asynchronous image uploads for the given `Pipeline`. These are mainly used
266    /// by canvas to perform uploads while the display list is being built.
267    NoLongerWaitingOnAsychronousImageUpdates(PipelineId),
268}
269
270impl fmt::Debug for ScriptThreadMessage {
271    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
272        let variant_string: &'static str = self.into();
273        write!(formatter, "ConstellationControlMsg::{variant_string}")
274    }
275}
276
277/// Used to determine if a script has any pending asynchronous activity.
278#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
279pub enum DocumentState {
280    /// The document has been loaded and is idle.
281    Idle,
282    /// The document is either loading or waiting on an event.
283    Pending,
284}
285
286/// Input events from the embedder that are sent via the `Constellation`` to the `ScriptThread`.
287#[derive(Clone, Debug, Deserialize, Serialize)]
288pub struct ConstellationInputEvent {
289    /// The hit test result of this input event, if any.
290    pub hit_test_result: Option<CompositorHitTestResult>,
291    /// The pressed mouse button state of the constellation when this input
292    /// event was triggered.
293    pub pressed_mouse_buttons: u16,
294    /// The currently active keyboard modifiers.
295    pub active_keyboard_modifiers: Modifiers,
296    /// The [`InputEvent`] itself.
297    pub event: InputEvent,
298}
299
300/// Data needed to construct a script thread.
301///
302/// NB: *DO NOT* add any Senders or Receivers here! pcwalton will have to rewrite your code if you
303/// do! Use IPC senders and receivers instead.
304pub struct InitialScriptState {
305    /// The ID of the pipeline with which this script thread is associated.
306    pub id: PipelineId,
307    /// The subpage ID of this pipeline to create in its pipeline parent.
308    /// If `None`, this is the root.
309    pub parent_info: Option<PipelineId>,
310    /// The ID of the browsing context this script is part of.
311    pub browsing_context_id: BrowsingContextId,
312    /// The ID of the top-level browsing context this script is part of.
313    pub webview_id: WebViewId,
314    /// The ID of the opener, if any.
315    pub opener: Option<BrowsingContextId>,
316    /// Loading into a Secure Context
317    pub inherited_secure_context: Option<bool>,
318    /// A channel with which messages can be sent to us (the script thread).
319    pub constellation_sender: GenericSender<ScriptThreadMessage>,
320    /// A port on which messages sent by the constellation to script can be received.
321    pub constellation_receiver: GenericReceiver<ScriptThreadMessage>,
322    /// A channel on which messages can be sent to the constellation from script.
323    pub pipeline_to_constellation_sender: ScriptToConstellationChan,
324    /// A handle to register script-(and associated layout-)threads for hang monitoring.
325    pub background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
326    /// A channel to the resource manager thread.
327    pub resource_threads: ResourceThreads,
328    /// A channel to the bluetooth thread.
329    #[cfg(feature = "bluetooth")]
330    pub bluetooth_sender: IpcSender<BluetoothRequest>,
331    /// The image cache for this script thread.
332    pub image_cache: Arc<dyn ImageCache>,
333    /// A channel to the time profiler thread.
334    pub time_profiler_sender: profile_traits::time::ProfilerChan,
335    /// A channel to the memory profiler thread.
336    pub memory_profiler_sender: mem::ProfilerChan,
337    /// A channel to the developer tools, if applicable.
338    pub devtools_server_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
339    /// Initial [`ViewportDetails`] for the frame that is initiating this `ScriptThread`.
340    pub viewport_details: ViewportDetails,
341    /// Initial [`Theme`] for the frame that is initiating this `ScriptThread`.
342    pub theme: Theme,
343    /// The ID of the pipeline namespace for this script thread.
344    pub pipeline_namespace_id: PipelineNamespaceId,
345    /// A ping will be sent on this channel once the script thread shuts down.
346    pub content_process_shutdown_sender: Sender<()>,
347    /// A channel to the WebGL thread used in this pipeline.
348    pub webgl_chan: Option<WebGLPipeline>,
349    /// The XR device registry
350    pub webxr_registry: Option<webxr_api::Registry>,
351    /// Access to the compositor across a process boundary.
352    pub compositor_api: CrossProcessCompositorApi,
353    /// Application window's GL Context for Media player
354    pub player_context: WindowGLContext,
355    /// User content manager
356    pub user_content_manager: UserContentManager,
357    /// A list of URLs that can access privileged internal APIs.
358    pub privileged_urls: Vec<ServoUrl>,
359}
360
361/// Errors from executing a paint worklet
362#[derive(Clone, Debug, Deserialize, Serialize)]
363pub enum PaintWorkletError {
364    /// Execution timed out.
365    Timeout,
366    /// No such worklet.
367    WorkletNotFound,
368}
369
370impl From<RecvTimeoutError> for PaintWorkletError {
371    fn from(_: RecvTimeoutError) -> PaintWorkletError {
372        PaintWorkletError::Timeout
373    }
374}
375
376/// Execute paint code in the worklet thread pool.
377pub trait Painter: SpeculativePainter {
378    /// <https://drafts.css-houdini.org/css-paint-api/#draw-a-paint-image>
379    fn draw_a_paint_image(
380        &self,
381        size: Size2D<f32, CSSPixel>,
382        zoom: Scale<f32, CSSPixel, DevicePixel>,
383        properties: Vec<(Atom, String)>,
384        arguments: Vec<String>,
385    ) -> Result<DrawAPaintImageResult, PaintWorkletError>;
386}
387
388impl fmt::Debug for dyn Painter {
389    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
390        fmt.debug_tuple("Painter")
391            .field(&format_args!(".."))
392            .finish()
393    }
394}
395
396/// The result of executing paint code: the image together with any image URLs that need to be loaded.
397///
398/// TODO: this should return a WR display list. <https://github.com/servo/servo/issues/17497>
399#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
400pub struct DrawAPaintImageResult {
401    /// The image height
402    pub width: u32,
403    /// The image width
404    pub height: u32,
405    /// The image format
406    pub format: PixelFormat,
407    /// The image drawn, or None if an invalid paint image was drawn
408    pub image_key: Option<ImageKey>,
409    /// Drawing the image might have requested loading some image URLs.
410    pub missing_image_urls: Vec<ServoUrl>,
411}