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