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