Skip to main content

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