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