embedder_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//! Types used by the embedding layer and/or exposed to the API. This crate is responsible for
6//! defining types that cross the process boundary from the embedding/rendering layer all the way
7//! to script, thus it should have very minimal dependencies on other parts of Servo. If a type
8//! is not exposed in the API or doesn't involve messages sent to the embedding/libservo layer, it
9//! is probably a better fit for the `constellation_traits` crate.
10
11pub mod embedder_controls;
12pub mod input_events;
13pub mod resources;
14pub mod user_contents;
15pub mod webdriver;
16
17use std::collections::HashMap;
18use std::ffi::c_void;
19use std::fmt::{Debug, Display, Error, Formatter};
20use std::hash::Hash;
21use std::ops::Range;
22use std::sync::Arc;
23
24use base::generic_channel::{GenericCallback, GenericSender, GenericSharedMemory, SendResult};
25use base::id::{PipelineId, WebViewId};
26use crossbeam_channel::Sender;
27use euclid::{Box2D, Point2D, Scale, Size2D, Vector2D};
28use http::{HeaderMap, Method, StatusCode};
29use log::warn;
30use malloc_size_of::malloc_size_of_is_0;
31use malloc_size_of_derive::MallocSizeOf;
32use pixels::SharedRasterImage;
33use serde::{Deserialize, Deserializer, Serialize, Serializer};
34use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
35use servo_url::ServoUrl;
36use strum::{EnumMessage, IntoStaticStr};
37use style::queries::values::PrefersColorScheme;
38use style_traits::CSSPixel;
39use url::Url;
40use uuid::Uuid;
41use webrender_api::ExternalScrollId;
42use webrender_api::units::{
43    DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, DeviceRect,
44    DeviceVector2D, LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D,
45};
46
47pub use crate::embedder_controls::*;
48pub use crate::input_events::*;
49use crate::user_contents::UserContentManagerId;
50pub use crate::webdriver::*;
51
52/// A point in a `WebView`, either expressed in device pixels or page pixels.
53/// Page pixels are CSS pixels, which take into account device pixel scale,
54/// page zoom, and pinch zoom.
55#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
56pub enum WebViewPoint {
57    Device(DevicePoint),
58    Page(Point2D<f32, CSSPixel>),
59}
60
61impl WebViewPoint {
62    pub fn as_device_point(&self, scale: Scale<f32, CSSPixel, DevicePixel>) -> DevicePoint {
63        match self {
64            Self::Device(point) => *point,
65            Self::Page(point) => *point * scale,
66        }
67    }
68}
69
70impl From<DevicePoint> for WebViewPoint {
71    fn from(point: DevicePoint) -> Self {
72        Self::Device(point)
73    }
74}
75
76impl From<LayoutPoint> for WebViewPoint {
77    fn from(point: LayoutPoint) -> Self {
78        Self::Page(Point2D::new(point.x, point.y))
79    }
80}
81
82impl From<Point2D<f32, CSSPixel>> for WebViewPoint {
83    fn from(point: Point2D<f32, CSSPixel>) -> Self {
84        Self::Page(point)
85    }
86}
87
88/// A rectangle in a `WebView`, either expressed in device pixels or page pixels.
89/// Page pixels are CSS pixels, which take into account device pixel scale,
90/// page zoom, and pinch zoom.
91#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
92pub enum WebViewRect {
93    Device(DeviceRect),
94    Page(Box2D<f32, CSSPixel>),
95}
96
97impl WebViewRect {
98    pub fn as_device_rect(&self, scale: Scale<f32, CSSPixel, DevicePixel>) -> DeviceRect {
99        match self {
100            Self::Device(rect) => *rect,
101            Self::Page(rect) => *rect * scale,
102        }
103    }
104}
105
106impl From<DeviceRect> for WebViewRect {
107    fn from(rect: DeviceRect) -> Self {
108        Self::Device(rect)
109    }
110}
111
112impl From<LayoutRect> for WebViewRect {
113    fn from(rect: LayoutRect) -> Self {
114        Self::Page(Box2D::new(
115            Point2D::new(rect.min.x, rect.min.y),
116            Point2D::new(rect.max.x, rect.max.y),
117        ))
118    }
119}
120
121impl From<Box2D<f32, CSSPixel>> for WebViewRect {
122    fn from(rect: Box2D<f32, CSSPixel>) -> Self {
123        Self::Page(rect)
124    }
125}
126
127#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
128pub enum WebViewVector {
129    Device(DeviceVector2D),
130    Page(Vector2D<f32, CSSPixel>),
131}
132
133impl WebViewVector {
134    pub fn as_device_vector(&self, scale: Scale<f32, CSSPixel, DevicePixel>) -> DeviceVector2D {
135        match self {
136            Self::Device(vector) => *vector,
137            Self::Page(vector) => *vector * scale,
138        }
139    }
140}
141
142impl From<DeviceVector2D> for WebViewVector {
143    fn from(vector: DeviceVector2D) -> Self {
144        Self::Device(vector)
145    }
146}
147
148impl From<LayoutVector2D> for WebViewVector {
149    fn from(vector: LayoutVector2D) -> Self {
150        Self::Page(Vector2D::new(vector.x, vector.y))
151    }
152}
153
154impl From<Vector2D<f32, CSSPixel>> for WebViewVector {
155    fn from(vector: Vector2D<f32, CSSPixel>) -> Self {
156        Self::Page(vector)
157    }
158}
159
160#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
161pub enum Scroll {
162    Delta(WebViewVector),
163    Start,
164    End,
165}
166
167/// Tracks whether Servo isn't shutting down, is in the process of shutting down,
168/// or has finished shutting down.
169#[derive(Clone, Copy, Debug, PartialEq)]
170pub enum ShutdownState {
171    NotShuttingDown,
172    ShuttingDown,
173    FinishedShuttingDown,
174}
175
176/// A cursor for the window. This is different from a CSS cursor (see
177/// `CursorKind`) in that it has no `Auto` value.
178#[repr(u8)]
179#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
180pub enum Cursor {
181    None,
182    #[default]
183    Default,
184    Pointer,
185    ContextMenu,
186    Help,
187    Progress,
188    Wait,
189    Cell,
190    Crosshair,
191    Text,
192    VerticalText,
193    Alias,
194    Copy,
195    Move,
196    NoDrop,
197    NotAllowed,
198    Grab,
199    Grabbing,
200    EResize,
201    NResize,
202    NeResize,
203    NwResize,
204    SResize,
205    SeResize,
206    SwResize,
207    WResize,
208    EwResize,
209    NsResize,
210    NeswResize,
211    NwseResize,
212    ColResize,
213    RowResize,
214    AllScroll,
215    ZoomIn,
216    ZoomOut,
217}
218
219pub trait EventLoopWaker: 'static + Send + Sync {
220    fn clone_box(&self) -> Box<dyn EventLoopWaker>;
221    fn wake(&self) {}
222}
223
224impl Clone for Box<dyn EventLoopWaker> {
225    fn clone(&self) -> Self {
226        self.clone_box()
227    }
228}
229
230/// Sends messages to the embedder.
231pub struct GenericEmbedderProxy<T> {
232    pub sender: Sender<T>,
233    pub event_loop_waker: Box<dyn EventLoopWaker>,
234}
235
236impl<T> GenericEmbedderProxy<T> {
237    pub fn send(&self, message: T) {
238        // Send a message and kick the OS event loop awake.
239        if let Err(err) = self.sender.send(message) {
240            warn!("Failed to send response ({:?}).", err);
241        }
242        self.event_loop_waker.wake();
243    }
244}
245
246impl<T> Clone for GenericEmbedderProxy<T> {
247    fn clone(&self) -> Self {
248        Self {
249            sender: self.sender.clone(),
250            event_loop_waker: self.event_loop_waker.clone(),
251        }
252    }
253}
254
255pub type EmbedderProxy = GenericEmbedderProxy<EmbedderMsg>;
256
257/// A [`RefreshDriver`] is a trait that can be implemented by Servo embedders in
258/// order to drive let Servo know when to start preparing the next frame. For example,
259/// on systems that support Vsync notifications, an embedder may want to implement
260/// this trait to drive Servo animations via those notifications.
261pub trait RefreshDriver {
262    /// Servo will call this method when it wants to be informed of the next frame start
263    /// time. Implementors should call the callback when it is time to start preparing
264    /// the new frame.
265    ///
266    /// Multiple callbacks may be registered for the same frame. It is up to the implementation
267    /// to call *all* callbacks that have been registered since the last frame.
268    fn observe_next_frame(&self, start_frame_callback: Box<dyn Fn() + Send + 'static>);
269}
270
271#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
272pub struct AuthenticationResponse {
273    /// Username for http request authentication
274    pub username: String,
275    /// Password for http request authentication
276    pub password: String,
277}
278
279/// A response to a request to allow or deny an action.
280#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
281pub enum AllowOrDeny {
282    Allow,
283    Deny,
284}
285
286#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
287/// Whether a protocol handler is requested to be registered or unregistered.
288pub enum RegisterOrUnregister {
289    Register,
290    Unregister,
291}
292
293#[derive(Clone, Debug, Deserialize, Serialize)]
294pub struct ProtocolHandlerUpdateRegistration {
295    /// The scheme for the protocol handler
296    pub scheme: String,
297    /// The URL to navigate to when handling requests for scheme
298    pub url: ServoUrl,
299    /// Whether this update is to register or unregister the protocol handler
300    pub register_or_unregister: RegisterOrUnregister,
301}
302
303/// Data about a `WebView` or `<iframe>` viewport: its size and also the
304/// HiDPI scale factor to use when rendering the contents.
305#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)]
306pub struct ViewportDetails {
307    /// The size of the layout viewport.
308    pub size: Size2D<f32, CSSPixel>,
309
310    /// The scale factor to use to account for HiDPI scaling. This does not take into account
311    /// any page or pinch zoom applied by `Paint` to the contents.
312    pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>,
313}
314
315impl ViewportDetails {
316    /// Convert this [`ViewportDetails`] size to a [`LayoutSize`]. This is the same numerical
317    /// value as [`Self::size`], because a `LayoutPixel` is the same as a `CSSPixel`.
318    pub fn layout_size(&self) -> LayoutSize {
319        Size2D::from_untyped(self.size.to_untyped())
320    }
321}
322
323/// Unlike [`ScreenGeometry`], the data is in device-independent pixels
324/// to be used by DOM APIs
325#[derive(Default, Deserialize, Serialize)]
326pub struct ScreenMetrics {
327    pub screen_size: DeviceIndependentIntSize,
328    pub available_size: DeviceIndependentIntSize,
329}
330
331/// An opaque identifier for a single history traversal operation.
332#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
333pub struct TraversalId(String);
334
335impl TraversalId {
336    #[expect(clippy::new_without_default)]
337    pub fn new() -> Self {
338        Self(Uuid::new_v4().to_string())
339    }
340}
341
342#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize, MallocSizeOf)]
343pub enum PixelFormat {
344    /// Luminance channel only
345    K8,
346    /// Luminance + alpha
347    KA8,
348    /// RGB, 8 bits per channel
349    RGB8,
350    /// RGB + alpha, 8 bits per channel
351    RGBA8,
352    /// BGR + alpha, 8 bits per channel
353    BGRA8,
354}
355
356/// A raster image buffer.
357#[derive(Clone, Deserialize, Serialize, MallocSizeOf)]
358pub struct Image {
359    pub width: u32,
360    pub height: u32,
361    pub format: PixelFormat,
362    /// A shared memory block containing the data of one or more image frames.
363    #[conditional_malloc_size_of]
364    data: Arc<GenericSharedMemory>,
365    range: Range<usize>,
366}
367
368impl Image {
369    pub fn new(
370        width: u32,
371        height: u32,
372        data: Arc<GenericSharedMemory>,
373        range: Range<usize>,
374        format: PixelFormat,
375    ) -> Self {
376        Self {
377            width,
378            height,
379            format,
380            data,
381            range,
382        }
383    }
384
385    /// Return the bytes belonging to the first image frame.
386    pub fn data(&self) -> &[u8] {
387        &self.data[self.range.clone()]
388    }
389}
390
391#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
392#[serde(rename_all = "lowercase")]
393pub enum ConsoleLogLevel {
394    Log,
395    Debug,
396    Info,
397    Warn,
398    Error,
399    Trace,
400}
401
402impl From<ConsoleLogLevel> for log::Level {
403    fn from(value: ConsoleLogLevel) -> Self {
404        match value {
405            ConsoleLogLevel::Log => log::Level::Info,
406            ConsoleLogLevel::Debug => log::Level::Debug,
407            ConsoleLogLevel::Info => log::Level::Info,
408            ConsoleLogLevel::Warn => log::Level::Warn,
409            ConsoleLogLevel::Error => log::Level::Error,
410            ConsoleLogLevel::Trace => log::Level::Trace,
411        }
412    }
413}
414
415/// Messages towards the embedder.
416#[derive(Deserialize, IntoStaticStr, Serialize)]
417pub enum EmbedderMsg {
418    /// A status message to be displayed by the browser chrome.
419    Status(WebViewId, Option<String>),
420    /// Alerts the embedder that the current page has changed its title.
421    ChangePageTitle(WebViewId, Option<String>),
422    /// Move the window to a point
423    MoveTo(WebViewId, DeviceIntPoint),
424    /// Resize the window to size
425    ResizeTo(WebViewId, DeviceIntSize),
426    /// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`,
427    /// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a
428    /// way that makes them impossible to mistake for browser UI.
429    ShowSimpleDialog(WebViewId, SimpleDialogRequest),
430    /// Whether or not to allow a pipeline to load a url.
431    AllowNavigationRequest(WebViewId, PipelineId, ServoUrl),
432    /// Request to (un)register protocol handler by page content.
433    AllowProtocolHandlerRequest(
434        WebViewId,
435        ProtocolHandlerUpdateRegistration,
436        GenericSender<AllowOrDeny>,
437    ),
438    /// Whether or not to allow script to open a new tab/browser
439    AllowOpeningWebView(WebViewId, GenericSender<Option<NewWebViewDetails>>),
440    /// A webview was destroyed.
441    WebViewClosed(WebViewId),
442    /// A webview potentially gained focus for keyboard events.
443    /// If the boolean value is false, the webiew could not be focused.
444    WebViewFocused(WebViewId, bool),
445    /// All webviews lost focus for keyboard events.
446    WebViewBlurred,
447    /// Wether or not to unload a document
448    AllowUnload(WebViewId, GenericSender<AllowOrDeny>),
449    /// Inform embedder to clear the clipboard
450    ClearClipboard(WebViewId),
451    /// Gets system clipboard contents
452    GetClipboardText(WebViewId, GenericCallback<Result<String, String>>),
453    /// Sets system clipboard contents
454    SetClipboardText(WebViewId, String),
455    /// Changes the cursor.
456    SetCursor(WebViewId, Cursor),
457    /// A favicon was detected
458    NewFavicon(WebViewId, Image),
459    /// The history state has changed.
460    HistoryChanged(WebViewId, Vec<ServoUrl>, usize),
461    /// A history traversal operation completed.
462    HistoryTraversalComplete(WebViewId, TraversalId),
463    /// Get the device independent window rectangle.
464    GetWindowRect(WebViewId, GenericSender<DeviceIndependentIntRect>),
465    /// Get the device independent screen size and available size.
466    GetScreenMetrics(WebViewId, GenericSender<ScreenMetrics>),
467    /// Entered or exited fullscreen.
468    NotifyFullscreenStateChanged(WebViewId, bool),
469    /// The [`LoadStatus`] of the Given `WebView` has changed.
470    NotifyLoadStatusChanged(WebViewId, LoadStatus),
471    /// A pipeline panicked. First string is the reason, second one is the backtrace.
472    Panic(WebViewId, String, Option<String>),
473    /// Open dialog to select bluetooth device.
474    GetSelectedBluetoothDevice(WebViewId, Vec<String>, GenericSender<Option<String>>),
475    /// Open interface to request permission specified by prompt.
476    PromptPermission(WebViewId, PermissionFeature, GenericSender<AllowOrDeny>),
477    /// Report a complete sampled profile
478    ReportProfile(Vec<u8>),
479    /// Notifies the embedder about media session events
480    /// (i.e. when there is metadata for the active media session, playback state changes...).
481    MediaSessionEvent(WebViewId, MediaSessionEvent),
482    /// Report the status of Devtools Server with a token that can be used to bypass the permission prompt.
483    OnDevtoolsStarted(Result<u16, ()>, String),
484    /// Ask the user to allow a devtools client to connect.
485    RequestDevtoolsConnection(GenericSender<AllowOrDeny>),
486    /// Request to play a haptic effect on a connected gamepad.
487    #[cfg(feature = "gamepad")]
488    PlayGamepadHapticEffect(
489        WebViewId,
490        usize,
491        GamepadHapticEffectType,
492        GenericCallback<bool>,
493    ),
494    /// Request to stop a haptic effect on a connected gamepad.
495    #[cfg(feature = "gamepad")]
496    StopGamepadHapticEffect(WebViewId, usize, GenericCallback<bool>),
497    /// Informs the embedder that the constellation has completed shutdown.
498    /// Required because the constellation can have pending calls to make
499    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
500    ShutdownComplete,
501    /// Request to display a notification.
502    ShowNotification(Option<WebViewId>, Notification),
503    /// Let the embedder process a DOM Console API message.
504    /// <https://developer.mozilla.org/en-US/docs/Web/API/Console_API>
505    ShowConsoleApiMessage(Option<WebViewId>, ConsoleLogLevel, String),
506    /// Request to display a form control to the embedder.
507    ShowEmbedderControl(EmbedderControlId, DeviceIntRect, EmbedderControlRequest),
508    /// Request to display a form control to the embedder.
509    HideEmbedderControl(EmbedderControlId),
510    /// Inform the embedding layer that a JavaScript evaluation has
511    /// finished with the given result.
512    FinishJavaScriptEvaluation(
513        JavaScriptEvaluationId,
514        Result<JSValue, JavaScriptEvaluationError>,
515    ),
516    /// Inform the embedding layer that a particular `InputEvent` was handled by Servo
517    /// and the embedder can continue processing it, if necessary.
518    InputEventHandled(WebViewId, InputEventId, InputEventResult),
519    /// Send the embedder an accessibility tree update.
520    AccessibilityTreeUpdate(WebViewId, accesskit::TreeUpdate),
521}
522
523impl Debug for EmbedderMsg {
524    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
525        let string: &'static str = self.into();
526        write!(formatter, "{string}")
527    }
528}
529
530/// <https://w3c.github.io/mediasession/#mediametadata>
531#[derive(Clone, Debug, Deserialize, Serialize)]
532pub struct MediaMetadata {
533    /// Title
534    pub title: String,
535    /// Artist
536    pub artist: String,
537    /// Album
538    pub album: String,
539}
540
541impl MediaMetadata {
542    pub fn new(title: String) -> Self {
543        Self {
544            title,
545            artist: "".to_owned(),
546            album: "".to_owned(),
547        }
548    }
549}
550
551/// <https://w3c.github.io/mediasession/#enumdef-mediasessionplaybackstate>
552#[repr(i32)]
553#[derive(Clone, Debug, Deserialize, Serialize)]
554pub enum MediaSessionPlaybackState {
555    /// The browsing context does not specify whether it’s playing or paused.
556    None_ = 1,
557    /// The browsing context is currently playing media and it can be paused.
558    Playing,
559    /// The browsing context has paused media and it can be resumed.
560    Paused,
561}
562
563/// <https://w3c.github.io/mediasession/#dictdef-mediapositionstate>
564#[derive(Clone, Debug, Deserialize, Serialize)]
565pub struct MediaPositionState {
566    pub duration: f64,
567    pub playback_rate: f64,
568    pub position: f64,
569}
570
571impl MediaPositionState {
572    pub fn new(duration: f64, playback_rate: f64, position: f64) -> Self {
573        Self {
574            duration,
575            playback_rate,
576            position,
577        }
578    }
579}
580
581/// Type of events sent from script to the embedder about the media session.
582#[derive(Clone, Debug, Deserialize, Serialize)]
583pub enum MediaSessionEvent {
584    /// Indicates that the media metadata is available.
585    SetMetadata(MediaMetadata),
586    /// Indicates that the playback state has changed.
587    PlaybackStateChange(MediaSessionPlaybackState),
588    /// Indicates that the position state is set.
589    SetPositionState(MediaPositionState),
590}
591
592/// Enum with variants that match the DOM PermissionName enum
593#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
594pub enum PermissionFeature {
595    Geolocation,
596    Notifications,
597    Push,
598    Midi,
599    Camera,
600    Microphone,
601    Speaker,
602    DeviceInfo,
603    BackgroundSync,
604    Bluetooth,
605    PersistentStorage,
606}
607
608/// Used to specify the kind of input method editor appropriate to edit a field.
609/// This is a subset of htmlinputelement::InputType because some variants of InputType
610/// don't make sense in this context.
611#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
612pub enum InputMethodType {
613    Color,
614    Date,
615    DatetimeLocal,
616    Email,
617    Month,
618    Number,
619    Password,
620    Search,
621    Tel,
622    Text,
623    Time,
624    Url,
625    Week,
626}
627
628#[cfg(feature = "gamepad")]
629#[derive(Clone, Debug, Deserialize, Serialize)]
630/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype-dual-rumble>
631pub struct DualRumbleEffectParams {
632    pub duration: f64,
633    pub start_delay: f64,
634    pub strong_magnitude: f64,
635    pub weak_magnitude: f64,
636}
637
638#[cfg(feature = "gamepad")]
639#[derive(Clone, Debug, Deserialize, Serialize)]
640/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype>
641pub enum GamepadHapticEffectType {
642    DualRumble(DualRumbleEffectParams),
643}
644
645#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
646pub struct WebResourceRequest {
647    #[serde(
648        deserialize_with = "::hyper_serde::deserialize",
649        serialize_with = "::hyper_serde::serialize"
650    )]
651    #[ignore_malloc_size_of = "Defined in hyper"]
652    pub method: Method,
653    #[serde(
654        deserialize_with = "::hyper_serde::deserialize",
655        serialize_with = "::hyper_serde::serialize"
656    )]
657    #[ignore_malloc_size_of = "Defined in hyper"]
658    pub headers: HeaderMap,
659    pub url: Url,
660    pub is_for_main_frame: bool,
661    pub is_redirect: bool,
662}
663
664#[derive(Clone, Deserialize, Serialize)]
665pub enum WebResourceResponseMsg {
666    /// Start an interception of this web resource load. It's expected that the client subsequently
667    /// send either a `CancelLoad` or `FinishLoad` message after optionally sending chunks of body
668    /// data via `SendBodyData`.
669    Start(WebResourceResponse),
670    /// Send a chunk of body data.
671    SendBodyData(Vec<u8>),
672    /// Signal that this load has been finished by the interceptor.
673    FinishLoad,
674    /// Signal that this load has been cancelled by the interceptor.
675    CancelLoad,
676    /// Signal that this load will not be intercepted.
677    DoNotIntercept,
678}
679
680#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
681pub struct WebResourceResponse {
682    pub url: Url,
683    #[serde(
684        deserialize_with = "::hyper_serde::deserialize",
685        serialize_with = "::hyper_serde::serialize"
686    )]
687    #[ignore_malloc_size_of = "Defined in hyper"]
688    pub headers: HeaderMap,
689    #[serde(
690        deserialize_with = "::hyper_serde::deserialize",
691        serialize_with = "::hyper_serde::serialize"
692    )]
693    #[ignore_malloc_size_of = "Defined in hyper"]
694    pub status_code: StatusCode,
695    pub status_message: Vec<u8>,
696}
697
698impl WebResourceResponse {
699    pub fn new(url: Url) -> WebResourceResponse {
700        WebResourceResponse {
701            url,
702            headers: HeaderMap::new(),
703            status_code: StatusCode::OK,
704            status_message: b"OK".to_vec(),
705        }
706    }
707
708    pub fn headers(mut self, headers: HeaderMap) -> WebResourceResponse {
709        self.headers = headers;
710        self
711    }
712
713    pub fn status_code(mut self, status_code: StatusCode) -> WebResourceResponse {
714        self.status_code = status_code;
715        self
716    }
717
718    pub fn status_message(mut self, status_message: Vec<u8>) -> WebResourceResponse {
719        self.status_message = status_message;
720        self
721    }
722}
723
724/// The type of platform theme.
725#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
726pub enum Theme {
727    /// Light theme.
728    Light,
729    /// Dark theme.
730    Dark,
731}
732
733impl From<Theme> for PrefersColorScheme {
734    fn from(value: Theme) -> Self {
735        match value {
736            Theme::Light => PrefersColorScheme::Light,
737            Theme::Dark => PrefersColorScheme::Dark,
738        }
739    }
740}
741
742// The type of MediaSession action.
743/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
744#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
745pub enum MediaSessionActionType {
746    /// The action intent is to resume playback.
747    Play,
748    /// The action intent is to pause the currently active playback.
749    Pause,
750    /// The action intent is to move the playback time backward by a short period (i.e. a few
751    /// seconds).
752    SeekBackward,
753    /// The action intent is to move the playback time forward by a short period (i.e. a few
754    /// seconds).
755    SeekForward,
756    /// The action intent is to either start the current playback from the beginning if the
757    /// playback has a notion, of beginning, or move to the previous item in the playlist if the
758    /// playback has a notion of playlist.
759    PreviousTrack,
760    /// The action is to move to the playback to the next item in the playlist if the playback has
761    /// a notion of playlist.
762    NextTrack,
763    /// The action intent is to skip the advertisement that is currently playing.
764    SkipAd,
765    /// The action intent is to stop the playback and clear the state if appropriate.
766    Stop,
767    /// The action intent is to move the playback time to a specific time.
768    SeekTo,
769}
770
771/// The status of the load in this `WebView`.
772#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
773pub enum LoadStatus {
774    /// The load has started, but the headers have not yet been parsed.
775    Started,
776    /// The `<head>` tag has been parsed in the currently loading page. At this point the page's
777    /// `HTMLBodyElement` is now available in the DOM.
778    HeadParsed,
779    /// The `Document` and all subresources have loaded. This is equivalent to
780    /// `document.readyState` == `complete`.
781    /// See <https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState>
782    Complete,
783}
784
785/// Data that could be used to display a desktop notification to the end user
786/// when the [Notification API](<https://notifications.spec.whatwg.org/#notifications>) is called.
787#[derive(Clone, Debug, Deserialize, Serialize)]
788pub struct Notification {
789    /// Title of the notification.
790    pub title: String,
791    /// Body string of the notification.
792    pub body: String,
793    /// An identifier tag for the notification. Notification with the same tag
794    /// can be replaced by another to avoid users' screen being filled up with similar notifications.
795    pub tag: String,
796    /// The tag for the language used in the notification's title, body, and the title of each its actions. [RFC 5646](https://datatracker.ietf.org/doc/html/rfc5646)
797    pub language: String,
798    /// A boolean value indicates the notification should remain readily available
799    /// until the end user activates or dismisses the notification.
800    pub require_interaction: bool,
801    /// When `true`, indicates no sounds or vibrations should be made. When `None`,
802    /// the device's default settings should be respected.
803    pub silent: Option<bool>,
804    /// The URL of an icon. The icon will be displayed as part of the notification.
805    pub icon_url: Option<ServoUrl>,
806    /// Icon's raw image data and metadata.
807    pub icon_resource: Option<Arc<SharedRasterImage>>,
808    /// The URL of a badge. The badge is used when there is no enough space to display the notification,
809    /// such as on a mobile device's notification bar.
810    pub badge_url: Option<ServoUrl>,
811    /// Badge's raw image data and metadata.
812    pub badge_resource: Option<Arc<SharedRasterImage>>,
813    /// The URL of an image. The image will be displayed as part of the notification.
814    pub image_url: Option<ServoUrl>,
815    /// Image's raw image data and metadata.
816    pub image_resource: Option<Arc<SharedRasterImage>>,
817    /// Actions available for users to choose from for interacting with the notification.
818    pub actions: Vec<NotificationAction>,
819}
820
821/// Actions available for users to choose from for interacting with the notification.
822#[derive(Clone, Debug, Deserialize, Serialize)]
823pub struct NotificationAction {
824    /// A string that identifies the action.
825    pub name: String,
826    /// The title string of the action to be shown to the user.
827    pub title: String,
828    /// The URL of an icon. The icon will be displayed with the action.
829    pub icon_url: Option<ServoUrl>,
830    /// Icon's raw image data and metadata.
831    pub icon_resource: Option<Arc<SharedRasterImage>>,
832}
833
834/// Information about a `WebView`'s screen geometry and offset. This is used
835/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface) CSSOM APIs
836/// and `window.screenLeft` / `window.screenX` / `window.screenTop` / `window.screenY` /
837/// `window.moveBy`/ `window.resizeBy` / `window.outerWidth` / `window.outerHeight` /
838/// `window.screen.availHeight` / `window.screen.availWidth`.
839#[derive(Clone, Copy, Debug, Default)]
840pub struct ScreenGeometry {
841    /// The size of the screen in device pixels. This will be converted to
842    /// CSS pixels based on the pixel scaling of the `WebView`.
843    pub size: DeviceIntSize,
844    /// The available size of the screen in device pixels for the purposes of
845    /// the `window.screen.availHeight` / `window.screen.availWidth`. This is the size
846    /// available for web content on the screen, and should be `size` minus any system
847    /// toolbars, docks, and interface elements. This will be converted to
848    /// CSS pixels based on the pixel scaling of the `WebView`.
849    pub available_size: DeviceIntSize,
850    /// The rectangle the `WebView`'s containing window (including OS decorations)
851    /// in device pixels for the purposes of the
852    /// `window.screenLeft`, `window.outerHeight` and similar APIs.
853    /// This will be converted to CSS pixels based on the pixel scaling of the `WebView`.
854    pub window_rect: DeviceIntRect,
855}
856
857impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
858    fn from(value: SelectElementOption) -> Self {
859        Self::Option(value)
860    }
861}
862
863/// The address of a node. Layout sends these back. They must be validated via
864/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
865#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
866pub struct UntrustedNodeAddress(pub *const c_void);
867
868malloc_size_of_is_0!(UntrustedNodeAddress);
869
870#[expect(unsafe_code)]
871unsafe impl Send for UntrustedNodeAddress {}
872
873impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress {
874    fn from(o: style_traits::dom::OpaqueNode) -> Self {
875        UntrustedNodeAddress(o.0 as *const c_void)
876    }
877}
878
879impl Serialize for UntrustedNodeAddress {
880    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
881        (self.0 as usize).serialize(s)
882    }
883}
884
885impl<'de> Deserialize<'de> for UntrustedNodeAddress {
886    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> {
887        let value: usize = Deserialize::deserialize(d)?;
888        Ok(UntrustedNodeAddress::from_id(value))
889    }
890}
891
892impl UntrustedNodeAddress {
893    /// Creates an `UntrustedNodeAddress` from the given pointer address value.
894    #[inline]
895    pub fn from_id(id: usize) -> UntrustedNodeAddress {
896        UntrustedNodeAddress(id as *const c_void)
897    }
898}
899
900/// The result of a hit test in `Paint`.
901#[derive(Clone, Debug, Deserialize, Serialize)]
902pub struct PaintHitTestResult {
903    /// The pipeline id of the resulting item.
904    pub pipeline_id: PipelineId,
905
906    /// The hit test point in the item's viewport.
907    pub point_in_viewport: Point2D<f32, CSSPixel>,
908
909    /// The [`ExternalScrollId`] of the scroll tree node associated with this hit test item.
910    pub external_scroll_id: ExternalScrollId,
911}
912
913/// For a given pipeline, whether any animations are currently running
914/// and any animation callbacks are queued
915#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
916pub enum AnimationState {
917    /// Animations are active but no callbacks are queued
918    AnimationsPresent,
919    /// Animations are active and callbacks are queued
920    AnimationCallbacksPresent,
921    /// No animations are active and no callbacks are queued
922    NoAnimationsPresent,
923    /// No animations are active but callbacks are queued
924    NoAnimationCallbacksPresent,
925}
926
927/// A sequence number generated by a script thread for its pipelines. The
928/// constellation attaches the target pipeline's last seen `FocusSequenceNumber`
929/// to every focus-related message it sends.
930///
931/// This is used to resolve the inconsistency that occurs due to bidirectional
932/// focus state synchronization and provide eventual consistency. Example:
933///
934/// ```text
935/// script                            constellation
936/// -----------------------------------------------------------------------
937/// send ActivateDocument ----------> receive ActivateDocument
938///                             ,---- send FocusDocument
939///                             |
940/// focus an iframe             |
941/// send Focus -----------------|---> receive Focus
942///                             |     focus the iframe's content document
943/// receive FocusDocument <-----'     send FocusDocument to the content pipeline --> ...
944/// unfocus the iframe
945/// focus the document
946///
947/// Final state:                      Final state:
948///  the iframe is not focused         the iframe is focused
949/// ```
950///
951/// When the above sequence completes, from the script thread's point of view,
952/// the iframe is unfocused, but from the constellation's point of view, the
953/// iframe is still focused.
954///
955/// This inconsistency can be resolved by associating a sequence number to each
956/// message. Whenever a script thread initiates a focus operation, it generates
957/// and sends a brand new sequence number. The constellation attaches the
958/// last-received sequence number to each message it sends. This way, the script
959/// thread can discard out-dated incoming focus messages, and eventually, all
960/// actors converge to the consistent state which is determined based on the
961/// last focus message received by the constellation.
962///
963/// ```text
964/// script                            constellation
965/// -----------------------------------------------------------------------
966/// send ActivateDocument ----------> receive ActivateDocument
967///                             ,---- send FocusDocument (0)
968///                             |
969/// seq_number += 1             |
970/// focus an iframe             |
971/// send Focus (1) -------------|---> receive Focus (1)
972///                             |     focus the iframe's content document
973/// receive FocusDocument (0) <-'     send FocusDocument to the content pipeline --> ...
974/// ignore it because 0 < 1
975///
976/// Final state:                      Final state:
977///  the iframe is focused             the iframe is focused
978/// ```
979#[derive(
980    Clone,
981    Copy,
982    Debug,
983    Default,
984    Deserialize,
985    Eq,
986    Hash,
987    MallocSizeOf,
988    PartialEq,
989    Serialize,
990    PartialOrd,
991)]
992pub struct FocusSequenceNumber(pub u64);
993
994impl Display for FocusSequenceNumber {
995    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
996        Display::fmt(&self.0, f)
997    }
998}
999
1000/// An identifier for a particular JavaScript evaluation that is used to track the
1001/// evaluation from the embedding layer to the script layer and then back.
1002#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
1003pub struct JavaScriptEvaluationId(pub usize);
1004
1005#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1006pub enum JSValue {
1007    Undefined,
1008    Null,
1009    Boolean(bool),
1010    Number(f64),
1011    String(String),
1012    Element(String),
1013    ShadowRoot(String),
1014    Frame(String),
1015    Window(String),
1016    Array(Vec<JSValue>),
1017    Object(HashMap<String, JSValue>),
1018}
1019
1020#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1021pub struct JavaScriptErrorInfo {
1022    pub message: String,
1023    pub filename: String,
1024    pub stack: Option<String>,
1025    pub line_number: u64,
1026    pub column: u64,
1027}
1028
1029/// Indicates the reason that JavaScript evaluation failed due serializing issues the
1030/// result of the evaluation.
1031#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1032pub enum JavaScriptEvaluationResultSerializationError {
1033    /// Serialization could not complete because a JavaScript value contained a detached
1034    /// shadow root according to <https://w3c.github.io/webdriver/#dfn-internal-json-clone>.
1035    DetachedShadowRoot,
1036    /// Serialization could not complete because a JavaScript value contained a "stale"
1037    /// element reference according to <https://w3c.github.io/webdriver/#dfn-get-a-known-element>.
1038    StaleElementReference,
1039    /// Serialization could not complete because a JavaScript value of an unknown type
1040    /// was encountered.
1041    UnknownType,
1042    /// This is a catch all for other kinds of errors that can happen during JavaScript value
1043    /// serialization. For instances where this can happen, see:
1044    /// <https://w3c.github.io/webdriver/#dfn-clone-an-object>.
1045    OtherJavaScriptError,
1046}
1047
1048/// An error that happens when trying to evaluate JavaScript on a `WebView`.
1049#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1050pub enum JavaScriptEvaluationError {
1051    /// The `Document` of frame that the script was going to execute in no longer exists.
1052    DocumentNotFound,
1053    /// The script could not be compiled.
1054    CompilationFailure,
1055    /// The script could not be evaluated.
1056    EvaluationFailure(Option<JavaScriptErrorInfo>),
1057    /// An internal Servo error prevented the JavaSript evaluation from completing properly.
1058    /// This indicates a bug in Servo.
1059    InternalError,
1060    /// The `WebView` on which this evaluation request was triggered is not ready. This might
1061    /// happen if the `WebView`'s `Document` is changing due to ongoing load events, for instance.
1062    WebViewNotReady,
1063    /// The script executed successfully, but Servo could not serialize the JavaScript return
1064    /// value into a [`JSValue`].
1065    SerializationError(JavaScriptEvaluationResultSerializationError),
1066}
1067
1068#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1069pub enum ScreenshotCaptureError {
1070    /// The screenshot request failed to read the screenshot image from the `WebView`'s
1071    /// `RenderingContext`.
1072    CouldNotReadImage,
1073    /// The WebView that this screenshot request was made for no longer exists.
1074    WebViewDoesNotExist,
1075}
1076
1077#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
1078pub struct RgbColor {
1079    pub red: u8,
1080    pub green: u8,
1081    pub blue: u8,
1082}
1083
1084/// A Script to Embedder Channel
1085#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
1086pub struct ScriptToEmbedderChan(GenericCallback<EmbedderMsg>);
1087
1088impl ScriptToEmbedderChan {
1089    /// Create a new Channel allowing script to send messages to the Embedder
1090    pub fn new(
1091        embedder_chan: Sender<EmbedderMsg>,
1092        waker: Box<dyn EventLoopWaker>,
1093    ) -> ScriptToEmbedderChan {
1094        let embedder_callback = GenericCallback::new(move |embedder_msg| {
1095            let msg = match embedder_msg {
1096                Ok(embedder_msg) => embedder_msg,
1097                Err(err) => {
1098                    log::warn!("Script to Embedder message error: {err}");
1099                    return;
1100                },
1101            };
1102            let _ = embedder_chan.send(msg);
1103            waker.wake();
1104        })
1105        .expect("Failed to create channel");
1106        ScriptToEmbedderChan(embedder_callback)
1107    }
1108
1109    /// Send a message to and wake the Embedder
1110    pub fn send(&self, msg: EmbedderMsg) -> SendResult {
1111        self.0.send(msg)
1112    }
1113}
1114
1115/// Used for communicating the details of a new `WebView` created by the embedder
1116/// back to the constellation.
1117#[derive(Deserialize, Serialize)]
1118pub struct NewWebViewDetails {
1119    pub webview_id: WebViewId,
1120    pub viewport_details: ViewportDetails,
1121    pub user_content_manager_id: Option<UserContentManagerId>,
1122}