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