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