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