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