embedder_traits/
lib.rs

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