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    pub method: Method,
643    #[serde(
644        deserialize_with = "::hyper_serde::deserialize",
645        serialize_with = "::hyper_serde::serialize"
646    )]
647    pub headers: HeaderMap,
648    pub url: Url,
649    pub is_for_main_frame: bool,
650    pub is_redirect: bool,
651}
652
653#[derive(Clone, Deserialize, Serialize)]
654pub enum WebResourceResponseMsg {
655    /// Start an interception of this web resource load. It's expected that the client subsequently
656    /// send either a `CancelLoad` or `FinishLoad` message after optionally sending chunks of body
657    /// data via `SendBodyData`.
658    Start(WebResourceResponse),
659    /// Send a chunk of body data.
660    SendBodyData(Vec<u8>),
661    /// Signal that this load has been finished by the interceptor.
662    FinishLoad,
663    /// Signal that this load has been cancelled by the interceptor.
664    CancelLoad,
665    /// Signal that this load will not be intercepted.
666    DoNotIntercept,
667}
668
669#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
670pub struct WebResourceResponse {
671    pub url: Url,
672    #[serde(
673        deserialize_with = "::hyper_serde::deserialize",
674        serialize_with = "::hyper_serde::serialize"
675    )]
676    #[ignore_malloc_size_of = "Defined in hyper"]
677    pub headers: HeaderMap,
678    #[serde(
679        deserialize_with = "::hyper_serde::deserialize",
680        serialize_with = "::hyper_serde::serialize"
681    )]
682    #[ignore_malloc_size_of = "Defined in hyper"]
683    pub status_code: StatusCode,
684    pub status_message: Vec<u8>,
685}
686
687impl WebResourceResponse {
688    pub fn new(url: Url) -> WebResourceResponse {
689        WebResourceResponse {
690            url,
691            headers: HeaderMap::new(),
692            status_code: StatusCode::OK,
693            status_message: b"OK".to_vec(),
694        }
695    }
696
697    pub fn headers(mut self, headers: HeaderMap) -> WebResourceResponse {
698        self.headers = headers;
699        self
700    }
701
702    pub fn status_code(mut self, status_code: StatusCode) -> WebResourceResponse {
703        self.status_code = status_code;
704        self
705    }
706
707    pub fn status_message(mut self, status_message: Vec<u8>) -> WebResourceResponse {
708        self.status_message = status_message;
709        self
710    }
711}
712
713/// The type of platform theme.
714#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
715pub enum Theme {
716    /// Light theme.
717    Light,
718    /// Dark theme.
719    Dark,
720}
721
722impl From<Theme> for PrefersColorScheme {
723    fn from(value: Theme) -> Self {
724        match value {
725            Theme::Light => PrefersColorScheme::Light,
726            Theme::Dark => PrefersColorScheme::Dark,
727        }
728    }
729}
730
731// The type of MediaSession action.
732/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
733#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
734pub enum MediaSessionActionType {
735    /// The action intent is to resume playback.
736    Play,
737    /// The action intent is to pause the currently active playback.
738    Pause,
739    /// The action intent is to move the playback time backward by a short period (i.e. a few
740    /// seconds).
741    SeekBackward,
742    /// The action intent is to move the playback time forward by a short period (i.e. a few
743    /// seconds).
744    SeekForward,
745    /// The action intent is to either start the current playback from the beginning if the
746    /// playback has a notion, of beginning, or move to the previous item in the playlist if the
747    /// playback has a notion of playlist.
748    PreviousTrack,
749    /// The action is to move to the playback to the next item in the playlist if the playback has
750    /// a notion of playlist.
751    NextTrack,
752    /// The action intent is to skip the advertisement that is currently playing.
753    SkipAd,
754    /// The action intent is to stop the playback and clear the state if appropriate.
755    Stop,
756    /// The action intent is to move the playback time to a specific time.
757    SeekTo,
758}
759
760/// The status of the load in this `WebView`.
761#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
762pub enum LoadStatus {
763    /// The load has started, but the headers have not yet been parsed.
764    Started,
765    /// The `<head>` tag has been parsed in the currently loading page. At this point the page's
766    /// `HTMLBodyElement` is now available in the DOM.
767    HeadParsed,
768    /// The `Document` and all subresources have loaded. This is equivalent to
769    /// `document.readyState` == `complete`.
770    /// See <https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState>
771    Complete,
772}
773
774/// Data that could be used to display a desktop notification to the end user
775/// when the [Notification API](<https://notifications.spec.whatwg.org/#notifications>) is called.
776#[derive(Clone, Debug, Deserialize, Serialize)]
777pub struct Notification {
778    /// Title of the notification.
779    pub title: String,
780    /// Body string of the notification.
781    pub body: String,
782    /// An identifier tag for the notification. Notification with the same tag
783    /// can be replaced by another to avoid users' screen being filled up with similar notifications.
784    pub tag: String,
785    /// 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)
786    pub language: String,
787    /// A boolean value indicates the notification should remain readily available
788    /// until the end user activates or dismisses the notification.
789    pub require_interaction: bool,
790    /// When `true`, indicates no sounds or vibrations should be made. When `None`,
791    /// the device's default settings should be respected.
792    pub silent: Option<bool>,
793    /// The URL of an icon. The icon will be displayed as part of the notification.
794    pub icon_url: Option<ServoUrl>,
795    /// Icon's raw image data and metadata.
796    pub icon_resource: Option<Arc<SharedRasterImage>>,
797    /// The URL of a badge. The badge is used when there is no enough space to display the notification,
798    /// such as on a mobile device's notification bar.
799    pub badge_url: Option<ServoUrl>,
800    /// Badge's raw image data and metadata.
801    pub badge_resource: Option<Arc<SharedRasterImage>>,
802    /// The URL of an image. The image will be displayed as part of the notification.
803    pub image_url: Option<ServoUrl>,
804    /// Image's raw image data and metadata.
805    pub image_resource: Option<Arc<SharedRasterImage>>,
806    /// Actions available for users to choose from for interacting with the notification.
807    pub actions: Vec<NotificationAction>,
808}
809
810/// Actions available for users to choose from for interacting with the notification.
811#[derive(Clone, Debug, Deserialize, Serialize)]
812pub struct NotificationAction {
813    /// A string that identifies the action.
814    pub name: String,
815    /// The title string of the action to be shown to the user.
816    pub title: String,
817    /// The URL of an icon. The icon will be displayed with the action.
818    pub icon_url: Option<ServoUrl>,
819    /// Icon's raw image data and metadata.
820    pub icon_resource: Option<Arc<SharedRasterImage>>,
821}
822
823/// Information about a `WebView`'s screen geometry and offset. This is used
824/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface) CSSOM APIs
825/// and `window.screenLeft` / `window.screenX` / `window.screenTop` / `window.screenY` /
826/// `window.moveBy`/ `window.resizeBy` / `window.outerWidth` / `window.outerHeight` /
827/// `window.screen.availHeight` / `window.screen.availWidth`.
828#[derive(Clone, Copy, Debug, Default)]
829pub struct ScreenGeometry {
830    /// The size of the screen in device pixels. This will be converted to
831    /// CSS pixels based on the pixel scaling of the `WebView`.
832    pub size: DeviceIntSize,
833    /// The available size of the screen in device pixels for the purposes of
834    /// the `window.screen.availHeight` / `window.screen.availWidth`. This is the size
835    /// available for web content on the screen, and should be `size` minus any system
836    /// toolbars, docks, and interface elements. This will be converted to
837    /// CSS pixels based on the pixel scaling of the `WebView`.
838    pub available_size: DeviceIntSize,
839    /// The rectangle the `WebView`'s containing window (including OS decorations)
840    /// in device pixels for the purposes of the
841    /// `window.screenLeft`, `window.outerHeight` and similar APIs.
842    /// This will be converted to CSS pixels based on the pixel scaling of the `WebView`.
843    pub window_rect: DeviceIntRect,
844}
845
846impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
847    fn from(value: SelectElementOption) -> Self {
848        Self::Option(value)
849    }
850}
851
852/// The address of a node. Layout sends these back. They must be validated via
853/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
854#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
855pub struct UntrustedNodeAddress(pub *const c_void);
856
857malloc_size_of_is_0!(UntrustedNodeAddress);
858
859#[expect(unsafe_code)]
860unsafe impl Send for UntrustedNodeAddress {}
861
862impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress {
863    fn from(o: style_traits::dom::OpaqueNode) -> Self {
864        UntrustedNodeAddress(o.0 as *const c_void)
865    }
866}
867
868impl Serialize for UntrustedNodeAddress {
869    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
870        (self.0 as usize).serialize(s)
871    }
872}
873
874impl<'de> Deserialize<'de> for UntrustedNodeAddress {
875    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> {
876        let value: usize = Deserialize::deserialize(d)?;
877        Ok(UntrustedNodeAddress::from_id(value))
878    }
879}
880
881impl UntrustedNodeAddress {
882    /// Creates an `UntrustedNodeAddress` from the given pointer address value.
883    #[inline]
884    pub fn from_id(id: usize) -> UntrustedNodeAddress {
885        UntrustedNodeAddress(id as *const c_void)
886    }
887}
888
889/// The result of a hit test in `Paint`.
890#[derive(Clone, Debug, Deserialize, Serialize)]
891pub struct PaintHitTestResult {
892    /// The pipeline id of the resulting item.
893    pub pipeline_id: PipelineId,
894
895    /// The hit test point in the item's viewport.
896    pub point_in_viewport: Point2D<f32, CSSPixel>,
897
898    /// The [`ExternalScrollId`] of the scroll tree node associated with this hit test item.
899    pub external_scroll_id: ExternalScrollId,
900}
901
902/// For a given pipeline, whether any animations are currently running
903/// and any animation callbacks are queued
904#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
905pub enum AnimationState {
906    /// Animations are active but no callbacks are queued
907    AnimationsPresent,
908    /// Animations are active and callbacks are queued
909    AnimationCallbacksPresent,
910    /// No animations are active and no callbacks are queued
911    NoAnimationsPresent,
912    /// No animations are active but callbacks are queued
913    NoAnimationCallbacksPresent,
914}
915
916/// A sequence number generated by a script thread for its pipelines. The
917/// constellation attaches the target pipeline's last seen `FocusSequenceNumber`
918/// to every focus-related message it sends.
919///
920/// This is used to resolve the inconsistency that occurs due to bidirectional
921/// focus state synchronization and provide eventual consistency. Example:
922///
923/// ```text
924/// script                            constellation
925/// -----------------------------------------------------------------------
926/// send ActivateDocument ----------> receive ActivateDocument
927///                             ,---- send FocusDocument
928///                             |
929/// focus an iframe             |
930/// send Focus -----------------|---> receive Focus
931///                             |     focus the iframe's content document
932/// receive FocusDocument <-----'     send FocusDocument to the content pipeline --> ...
933/// unfocus the iframe
934/// focus the document
935///
936/// Final state:                      Final state:
937///  the iframe is not focused         the iframe is focused
938/// ```
939///
940/// When the above sequence completes, from the script thread's point of view,
941/// the iframe is unfocused, but from the constellation's point of view, the
942/// iframe is still focused.
943///
944/// This inconsistency can be resolved by associating a sequence number to each
945/// message. Whenever a script thread initiates a focus operation, it generates
946/// and sends a brand new sequence number. The constellation attaches the
947/// last-received sequence number to each message it sends. This way, the script
948/// thread can discard out-dated incoming focus messages, and eventually, all
949/// actors converge to the consistent state which is determined based on the
950/// last focus message received by the constellation.
951///
952/// ```text
953/// script                            constellation
954/// -----------------------------------------------------------------------
955/// send ActivateDocument ----------> receive ActivateDocument
956///                             ,---- send FocusDocument (0)
957///                             |
958/// seq_number += 1             |
959/// focus an iframe             |
960/// send Focus (1) -------------|---> receive Focus (1)
961///                             |     focus the iframe's content document
962/// receive FocusDocument (0) <-'     send FocusDocument to the content pipeline --> ...
963/// ignore it because 0 < 1
964///
965/// Final state:                      Final state:
966///  the iframe is focused             the iframe is focused
967/// ```
968#[derive(
969    Clone,
970    Copy,
971    Debug,
972    Default,
973    Deserialize,
974    Eq,
975    Hash,
976    MallocSizeOf,
977    PartialEq,
978    Serialize,
979    PartialOrd,
980)]
981pub struct FocusSequenceNumber(pub u64);
982
983impl Display for FocusSequenceNumber {
984    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
985        Display::fmt(&self.0, f)
986    }
987}
988
989/// An identifier for a particular JavaScript evaluation that is used to track the
990/// evaluation from the embedding layer to the script layer and then back.
991#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
992pub struct JavaScriptEvaluationId(pub usize);
993
994#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
995pub enum JSValue {
996    Undefined,
997    Null,
998    Boolean(bool),
999    Number(f64),
1000    String(String),
1001    Element(String),
1002    ShadowRoot(String),
1003    Frame(String),
1004    Window(String),
1005    Array(Vec<JSValue>),
1006    Object(HashMap<String, JSValue>),
1007}
1008
1009#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1010pub struct JavaScriptErrorInfo {
1011    pub message: String,
1012    pub filename: String,
1013    pub stack: Option<String>,
1014    pub line_number: u64,
1015    pub column: u64,
1016}
1017
1018/// Indicates the reason that JavaScript evaluation failed due serializing issues the
1019/// result of the evaluation.
1020#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1021pub enum JavaScriptEvaluationResultSerializationError {
1022    /// Serialization could not complete because a JavaScript value contained a detached
1023    /// shadow root according to <https://w3c.github.io/webdriver/#dfn-internal-json-clone>.
1024    DetachedShadowRoot,
1025    /// Serialization could not complete because a JavaScript value contained a "stale"
1026    /// element reference according to <https://w3c.github.io/webdriver/#dfn-get-a-known-element>.
1027    StaleElementReference,
1028    /// Serialization could not complete because a JavaScript value of an unknown type
1029    /// was encountered.
1030    UnknownType,
1031    /// This is a catch all for other kinds of errors that can happen during JavaScript value
1032    /// serialization. For instances where this can happen, see:
1033    /// <https://w3c.github.io/webdriver/#dfn-clone-an-object>.
1034    OtherJavaScriptError,
1035}
1036
1037/// An error that happens when trying to evaluate JavaScript on a `WebView`.
1038#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1039pub enum JavaScriptEvaluationError {
1040    /// The `Document` of frame that the script was going to execute in no longer exists.
1041    DocumentNotFound,
1042    /// The script could not be compiled.
1043    CompilationFailure,
1044    /// The script could not be evaluated.
1045    EvaluationFailure(Option<JavaScriptErrorInfo>),
1046    /// An internal Servo error prevented the JavaSript evaluation from completing properly.
1047    /// This indicates a bug in Servo.
1048    InternalError,
1049    /// The `WebView` on which this evaluation request was triggered is not ready. This might
1050    /// happen if the `WebView`'s `Document` is changing due to ongoing load events, for instance.
1051    WebViewNotReady,
1052    /// The script executed successfully, but Servo could not serialize the JavaScript return
1053    /// value into a [`JSValue`].
1054    SerializationError(JavaScriptEvaluationResultSerializationError),
1055}
1056
1057#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1058pub enum ScreenshotCaptureError {
1059    /// The screenshot request failed to read the screenshot image from the `WebView`'s
1060    /// `RenderingContext`.
1061    CouldNotReadImage,
1062    /// The WebView that this screenshot request was made for no longer exists.
1063    WebViewDoesNotExist,
1064}
1065
1066#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
1067pub struct RgbColor {
1068    pub red: u8,
1069    pub green: u8,
1070    pub blue: u8,
1071}
1072
1073/// A Script to Embedder Channel
1074#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
1075pub struct ScriptToEmbedderChan(GenericCallback<EmbedderMsg>);
1076
1077impl ScriptToEmbedderChan {
1078    /// Create a new Channel allowing script to send messages to the Embedder
1079    pub fn new(
1080        embedder_chan: Sender<EmbedderMsg>,
1081        waker: Box<dyn EventLoopWaker>,
1082    ) -> ScriptToEmbedderChan {
1083        let embedder_callback = GenericCallback::new(move |embedder_msg| {
1084            let msg = match embedder_msg {
1085                Ok(embedder_msg) => embedder_msg,
1086                Err(err) => {
1087                    log::warn!("Script to Embedder message error: {err}");
1088                    return;
1089                },
1090            };
1091            let _ = embedder_chan.send(msg);
1092            waker.wake();
1093        })
1094        .expect("Failed to create channel");
1095        ScriptToEmbedderChan(embedder_callback)
1096    }
1097
1098    /// Send a message to and wake the Embedder
1099    pub fn send(&self, msg: EmbedderMsg) -> SendResult {
1100        self.0.send(msg)
1101    }
1102}
1103
1104/// Used for communicating the details of a new `WebView` created by the embedder
1105/// back to the constellation.
1106#[derive(Deserialize, Serialize)]
1107pub struct NewWebViewDetails {
1108    pub webview_id: WebViewId,
1109    pub viewport_details: ViewportDetails,
1110    pub user_content_manager_id: Option<UserContentManagerId>,
1111}