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_content_manager;
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, SendResult};
26use base::id::{PipelineId, WebViewId};
27use crossbeam_channel::Sender;
28use euclid::{Box2D, Point2D, Scale, Size2D, Vector2D};
29use http::{HeaderMap, Method, StatusCode};
30use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
31use log::warn;
32use malloc_size_of::malloc_size_of_is_0;
33use malloc_size_of_derive::MallocSizeOf;
34use pixels::SharedRasterImage;
35use serde::{Deserialize, Deserializer, Serialize, Serializer};
36use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
37use servo_url::ServoUrl;
38use strum::{EnumMessage, IntoStaticStr};
39use style::queries::values::PrefersColorScheme;
40use style_traits::CSSPixel;
41use url::Url;
42use uuid::Uuid;
43use webrender_api::ExternalScrollId;
44use webrender_api::units::{
45    DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, DevicePoint, DeviceRect,
46    DeviceVector2D, LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D,
47};
48
49pub use crate::embedder_controls::*;
50pub use crate::input_events::*;
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 the compositor 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    #[allow(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<IpcSharedMemory>,
362    range: Range<usize>,
363}
364
365impl Image {
366    pub fn new(
367        width: u32,
368        height: u32,
369        data: Arc<IpcSharedMemory>,
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(Deserialize, IntoStaticStr, Serialize)]
389pub enum EmbedderMsg {
390    /// A status message to be displayed by the browser chrome.
391    Status(WebViewId, Option<String>),
392    /// Alerts the embedder that the current page has changed its title.
393    ChangePageTitle(WebViewId, Option<String>),
394    /// Move the window to a point
395    MoveTo(WebViewId, DeviceIntPoint),
396    /// Resize the window to size
397    ResizeTo(WebViewId, DeviceIntSize),
398    /// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`,
399    /// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a
400    /// way that makes them impossible to mistake for browser UI.
401    ShowSimpleDialog(WebViewId, SimpleDialogRequest),
402    /// Request authentication for a load or navigation from the embedder.
403    RequestAuthentication(
404        WebViewId,
405        ServoUrl,
406        bool, /* for proxy */
407        GenericSender<Option<AuthenticationResponse>>,
408    ),
409    /// Whether or not to allow a pipeline to load a url.
410    AllowNavigationRequest(WebViewId, PipelineId, ServoUrl),
411    /// Request to (un)register protocol handler by page content.
412    AllowProtocolHandlerRequest(
413        WebViewId,
414        ProtocolHandlerUpdateRegistration,
415        GenericSender<AllowOrDeny>,
416    ),
417    /// Whether or not to allow script to open a new tab/browser
418    AllowOpeningWebView(
419        WebViewId,
420        GenericSender<Option<(WebViewId, ViewportDetails)>>,
421    ),
422    /// A webview was destroyed.
423    WebViewClosed(WebViewId),
424    /// A webview potentially gained focus for keyboard events.
425    /// If the boolean value is false, the webiew could not be focused.
426    WebViewFocused(WebViewId, bool),
427    /// All webviews lost focus for keyboard events.
428    WebViewBlurred,
429    /// Wether or not to unload a document
430    AllowUnload(WebViewId, GenericSender<AllowOrDeny>),
431    /// Inform embedder to clear the clipboard
432    ClearClipboard(WebViewId),
433    /// Gets system clipboard contents
434    GetClipboardText(WebViewId, IpcSender<Result<String, String>>),
435    /// Sets system clipboard contents
436    SetClipboardText(WebViewId, String),
437    /// Changes the cursor.
438    SetCursor(WebViewId, Cursor),
439    /// A favicon was detected
440    NewFavicon(WebViewId, Image),
441    /// The history state has changed.
442    HistoryChanged(WebViewId, Vec<ServoUrl>, usize),
443    /// A history traversal operation completed.
444    HistoryTraversalComplete(WebViewId, TraversalId),
445    /// Get the device independent window rectangle.
446    GetWindowRect(WebViewId, GenericSender<DeviceIndependentIntRect>),
447    /// Get the device independent screen size and available size.
448    GetScreenMetrics(WebViewId, GenericSender<ScreenMetrics>),
449    /// Entered or exited fullscreen.
450    NotifyFullscreenStateChanged(WebViewId, bool),
451    /// The [`LoadStatus`] of the Given `WebView` has changed.
452    NotifyLoadStatusChanged(WebViewId, LoadStatus),
453    WebResourceRequested(
454        Option<WebViewId>,
455        WebResourceRequest,
456        GenericSender<WebResourceResponseMsg>,
457    ),
458    /// A pipeline panicked. First string is the reason, second one is the backtrace.
459    Panic(WebViewId, String, Option<String>),
460    /// Open dialog to select bluetooth device.
461    GetSelectedBluetoothDevice(WebViewId, Vec<String>, GenericSender<Option<String>>),
462    /// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
463    SelectFiles(
464        EmbedderControlId,
465        FilePickerRequest,
466        GenericSender<Option<Vec<PathBuf>>>,
467    ),
468    /// Open interface to request permission specified by prompt.
469    PromptPermission(WebViewId, PermissionFeature, GenericSender<AllowOrDeny>),
470    /// Report a complete sampled profile
471    ReportProfile(Vec<u8>),
472    /// Notifies the embedder about media session events
473    /// (i.e. when there is metadata for the active media session, playback state changes...).
474    MediaSessionEvent(WebViewId, MediaSessionEvent),
475    /// Report the status of Devtools Server with a token that can be used to bypass the permission prompt.
476    OnDevtoolsStarted(Result<u16, ()>, String),
477    /// Ask the user to allow a devtools client to connect.
478    RequestDevtoolsConnection(GenericSender<AllowOrDeny>),
479    /// Request to play a haptic effect on a connected gamepad.
480    PlayGamepadHapticEffect(WebViewId, usize, GamepadHapticEffectType, IpcSender<bool>),
481    /// Request to stop a haptic effect on a connected gamepad.
482    StopGamepadHapticEffect(WebViewId, usize, IpcSender<bool>),
483    /// Informs the embedder that the constellation has completed shutdown.
484    /// Required because the constellation can have pending calls to make
485    /// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
486    ShutdownComplete,
487    /// Request to display a notification.
488    ShowNotification(Option<WebViewId>, Notification),
489    /// Request to display a form control to the embedder.
490    ShowEmbedderControl(EmbedderControlId, DeviceIntRect, EmbedderControlRequest),
491    /// Request to display a form control to the embedder.
492    HideEmbedderControl(EmbedderControlId),
493    /// Inform the embedding layer that a JavaScript evaluation has
494    /// finished with the given result.
495    FinishJavaScriptEvaluation(
496        JavaScriptEvaluationId,
497        Result<JSValue, JavaScriptEvaluationError>,
498    ),
499    /// Inform the embedding layer that a particular `InputEvent` was handled by Servo
500    /// and the embedder can continue processing it, if necessary.
501    InputEventHandled(WebViewId, InputEventId, InputEventResult),
502}
503
504impl Debug for EmbedderMsg {
505    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
506        let string: &'static str = self.into();
507        write!(formatter, "{string}")
508    }
509}
510
511/// <https://w3c.github.io/mediasession/#mediametadata>
512#[derive(Clone, Debug, Deserialize, Serialize)]
513pub struct MediaMetadata {
514    /// Title
515    pub title: String,
516    /// Artist
517    pub artist: String,
518    /// Album
519    pub album: String,
520}
521
522impl MediaMetadata {
523    pub fn new(title: String) -> Self {
524        Self {
525            title,
526            artist: "".to_owned(),
527            album: "".to_owned(),
528        }
529    }
530}
531
532/// <https://w3c.github.io/mediasession/#enumdef-mediasessionplaybackstate>
533#[repr(i32)]
534#[derive(Clone, Debug, Deserialize, Serialize)]
535pub enum MediaSessionPlaybackState {
536    /// The browsing context does not specify whether it’s playing or paused.
537    None_ = 1,
538    /// The browsing context is currently playing media and it can be paused.
539    Playing,
540    /// The browsing context has paused media and it can be resumed.
541    Paused,
542}
543
544/// <https://w3c.github.io/mediasession/#dictdef-mediapositionstate>
545#[derive(Clone, Debug, Deserialize, Serialize)]
546pub struct MediaPositionState {
547    pub duration: f64,
548    pub playback_rate: f64,
549    pub position: f64,
550}
551
552impl MediaPositionState {
553    pub fn new(duration: f64, playback_rate: f64, position: f64) -> Self {
554        Self {
555            duration,
556            playback_rate,
557            position,
558        }
559    }
560}
561
562/// Type of events sent from script to the embedder about the media session.
563#[derive(Clone, Debug, Deserialize, Serialize)]
564pub enum MediaSessionEvent {
565    /// Indicates that the media metadata is available.
566    SetMetadata(MediaMetadata),
567    /// Indicates that the playback state has changed.
568    PlaybackStateChange(MediaSessionPlaybackState),
569    /// Indicates that the position state is set.
570    SetPositionState(MediaPositionState),
571}
572
573/// Enum with variants that match the DOM PermissionName enum
574#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
575pub enum PermissionFeature {
576    Geolocation,
577    Notifications,
578    Push,
579    Midi,
580    Camera,
581    Microphone,
582    Speaker,
583    DeviceInfo,
584    BackgroundSync,
585    Bluetooth,
586    PersistentStorage,
587}
588
589/// Used to specify the kind of input method editor appropriate to edit a field.
590/// This is a subset of htmlinputelement::InputType because some variants of InputType
591/// don't make sense in this context.
592#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
593pub enum InputMethodType {
594    Color,
595    Date,
596    DatetimeLocal,
597    Email,
598    Month,
599    Number,
600    Password,
601    Search,
602    Tel,
603    Text,
604    Time,
605    Url,
606    Week,
607}
608
609#[derive(Clone, Debug, Deserialize, Serialize)]
610/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype-dual-rumble>
611pub struct DualRumbleEffectParams {
612    pub duration: f64,
613    pub start_delay: f64,
614    pub strong_magnitude: f64,
615    pub weak_magnitude: f64,
616}
617
618#[derive(Clone, Debug, Deserialize, Serialize)]
619/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype>
620pub enum GamepadHapticEffectType {
621    DualRumble(DualRumbleEffectParams),
622}
623
624#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
625pub struct WebResourceRequest {
626    #[serde(
627        deserialize_with = "::hyper_serde::deserialize",
628        serialize_with = "::hyper_serde::serialize"
629    )]
630    #[ignore_malloc_size_of = "Defined in hyper"]
631    pub method: Method,
632    #[serde(
633        deserialize_with = "::hyper_serde::deserialize",
634        serialize_with = "::hyper_serde::serialize"
635    )]
636    #[ignore_malloc_size_of = "Defined in hyper"]
637    pub headers: HeaderMap,
638    pub url: Url,
639    pub is_for_main_frame: bool,
640    pub is_redirect: bool,
641}
642
643#[derive(Clone, Deserialize, Serialize)]
644pub enum WebResourceResponseMsg {
645    /// Start an interception of this web resource load. It's expected that the client subsequently
646    /// send either a `CancelLoad` or `FinishLoad` message after optionally sending chunks of body
647    /// data via `SendBodyData`.
648    Start(WebResourceResponse),
649    /// Send a chunk of body data.
650    SendBodyData(Vec<u8>),
651    /// Signal that this load has been finished by the interceptor.
652    FinishLoad,
653    /// Signal that this load has been cancelled by the interceptor.
654    CancelLoad,
655    /// Signal that this load will not be intercepted.
656    DoNotIntercept,
657}
658
659#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
660pub struct WebResourceResponse {
661    pub url: Url,
662    #[serde(
663        deserialize_with = "::hyper_serde::deserialize",
664        serialize_with = "::hyper_serde::serialize"
665    )]
666    #[ignore_malloc_size_of = "Defined in hyper"]
667    pub headers: HeaderMap,
668    #[serde(
669        deserialize_with = "::hyper_serde::deserialize",
670        serialize_with = "::hyper_serde::serialize"
671    )]
672    #[ignore_malloc_size_of = "Defined in hyper"]
673    pub status_code: StatusCode,
674    pub status_message: Vec<u8>,
675}
676
677impl WebResourceResponse {
678    pub fn new(url: Url) -> WebResourceResponse {
679        WebResourceResponse {
680            url,
681            headers: HeaderMap::new(),
682            status_code: StatusCode::OK,
683            status_message: b"OK".to_vec(),
684        }
685    }
686
687    pub fn headers(mut self, headers: HeaderMap) -> WebResourceResponse {
688        self.headers = headers;
689        self
690    }
691
692    pub fn status_code(mut self, status_code: StatusCode) -> WebResourceResponse {
693        self.status_code = status_code;
694        self
695    }
696
697    pub fn status_message(mut self, status_message: Vec<u8>) -> WebResourceResponse {
698        self.status_message = status_message;
699        self
700    }
701}
702
703/// The type of platform theme.
704#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
705pub enum Theme {
706    /// Light theme.
707    Light,
708    /// Dark theme.
709    Dark,
710}
711
712impl From<Theme> for PrefersColorScheme {
713    fn from(value: Theme) -> Self {
714        match value {
715            Theme::Light => PrefersColorScheme::Light,
716            Theme::Dark => PrefersColorScheme::Dark,
717        }
718    }
719}
720
721// The type of MediaSession action.
722/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
723#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
724pub enum MediaSessionActionType {
725    /// The action intent is to resume playback.
726    Play,
727    /// The action intent is to pause the currently active playback.
728    Pause,
729    /// The action intent is to move the playback time backward by a short period (i.e. a few
730    /// seconds).
731    SeekBackward,
732    /// The action intent is to move the playback time forward by a short period (i.e. a few
733    /// seconds).
734    SeekForward,
735    /// The action intent is to either start the current playback from the beginning if the
736    /// playback has a notion, of beginning, or move to the previous item in the playlist if the
737    /// playback has a notion of playlist.
738    PreviousTrack,
739    /// The action is to move to the playback to the next item in the playlist if the playback has
740    /// a notion of playlist.
741    NextTrack,
742    /// The action intent is to skip the advertisement that is currently playing.
743    SkipAd,
744    /// The action intent is to stop the playback and clear the state if appropriate.
745    Stop,
746    /// The action intent is to move the playback time to a specific time.
747    SeekTo,
748}
749
750/// The status of the load in this `WebView`.
751#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
752pub enum LoadStatus {
753    /// The load has started, but the headers have not yet been parsed.
754    Started,
755    /// The `<head>` tag has been parsed in the currently loading page. At this point the page's
756    /// `HTMLBodyElement` is now available in the DOM.
757    HeadParsed,
758    /// The `Document` and all subresources have loaded. This is equivalent to
759    /// `document.readyState` == `complete`.
760    /// See <https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState>
761    Complete,
762}
763
764/// Data that could be used to display a desktop notification to the end user
765/// when the [Notification API](<https://notifications.spec.whatwg.org/#notifications>) is called.
766#[derive(Clone, Debug, Deserialize, Serialize)]
767pub struct Notification {
768    /// Title of the notification.
769    pub title: String,
770    /// Body string of the notification.
771    pub body: String,
772    /// An identifier tag for the notification. Notification with the same tag
773    /// can be replaced by another to avoid users' screen being filled up with similar notifications.
774    pub tag: String,
775    /// 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)
776    pub language: String,
777    /// A boolean value indicates the notification should remain readily available
778    /// until the end user activates or dismisses the notification.
779    pub require_interaction: bool,
780    /// When `true`, indicates no sounds or vibrations should be made. When `None`,
781    /// the device's default settings should be respected.
782    pub silent: Option<bool>,
783    /// The URL of an icon. The icon will be displayed as part of the notification.
784    pub icon_url: Option<ServoUrl>,
785    /// Icon's raw image data and metadata.
786    pub icon_resource: Option<Arc<SharedRasterImage>>,
787    /// The URL of a badge. The badge is used when there is no enough space to display the notification,
788    /// such as on a mobile device's notification bar.
789    pub badge_url: Option<ServoUrl>,
790    /// Badge's raw image data and metadata.
791    pub badge_resource: Option<Arc<SharedRasterImage>>,
792    /// The URL of an image. The image will be displayed as part of the notification.
793    pub image_url: Option<ServoUrl>,
794    /// Image's raw image data and metadata.
795    pub image_resource: Option<Arc<SharedRasterImage>>,
796    /// Actions available for users to choose from for interacting with the notification.
797    pub actions: Vec<NotificationAction>,
798}
799
800/// Actions available for users to choose from for interacting with the notification.
801#[derive(Clone, Debug, Deserialize, Serialize)]
802pub struct NotificationAction {
803    /// A string that identifies the action.
804    pub name: String,
805    /// The title string of the action to be shown to the user.
806    pub title: String,
807    /// The URL of an icon. The icon will be displayed with the action.
808    pub icon_url: Option<ServoUrl>,
809    /// Icon's raw image data and metadata.
810    pub icon_resource: Option<Arc<SharedRasterImage>>,
811}
812
813/// Information about a `WebView`'s screen geometry and offset. This is used
814/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface) CSSOM APIs
815/// and `window.screenLeft` / `window.screenX` / `window.screenTop` / `window.screenY` /
816/// `window.moveBy`/ `window.resizeBy` / `window.outerWidth` / `window.outerHeight` /
817/// `window.screen.availHeight` / `window.screen.availWidth`.
818#[derive(Clone, Copy, Debug, Default)]
819pub struct ScreenGeometry {
820    /// The size of the screen in device pixels. This will be converted to
821    /// CSS pixels based on the pixel scaling of the `WebView`.
822    pub size: DeviceIntSize,
823    /// The available size of the screen in device pixels for the purposes of
824    /// the `window.screen.availHeight` / `window.screen.availWidth`. This is the size
825    /// available for web content on the screen, and should be `size` minus any system
826    /// toolbars, docks, and interface elements. This will be converted to
827    /// CSS pixels based on the pixel scaling of the `WebView`.
828    pub available_size: DeviceIntSize,
829    /// The rectangle the `WebView`'s containing window (including OS decorations)
830    /// in device pixels for the purposes of the
831    /// `window.screenLeft`, `window.outerHeight` and similar APIs.
832    /// This will be converted to CSS pixels based on the pixel scaling of the `WebView`.
833    pub window_rect: DeviceIntRect,
834}
835
836impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
837    fn from(value: SelectElementOption) -> Self {
838        Self::Option(value)
839    }
840}
841
842/// The address of a node. Layout sends these back. They must be validated via
843/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
844#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
845pub struct UntrustedNodeAddress(pub *const c_void);
846
847malloc_size_of_is_0!(UntrustedNodeAddress);
848
849#[expect(unsafe_code)]
850unsafe impl Send for UntrustedNodeAddress {}
851
852impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress {
853    fn from(o: style_traits::dom::OpaqueNode) -> Self {
854        UntrustedNodeAddress(o.0 as *const c_void)
855    }
856}
857
858impl Serialize for UntrustedNodeAddress {
859    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
860        (self.0 as usize).serialize(s)
861    }
862}
863
864impl<'de> Deserialize<'de> for UntrustedNodeAddress {
865    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> {
866        let value: usize = Deserialize::deserialize(d)?;
867        Ok(UntrustedNodeAddress::from_id(value))
868    }
869}
870
871impl UntrustedNodeAddress {
872    /// Creates an `UntrustedNodeAddress` from the given pointer address value.
873    #[inline]
874    pub fn from_id(id: usize) -> UntrustedNodeAddress {
875        UntrustedNodeAddress(id as *const c_void)
876    }
877}
878
879/// The result of a hit test in the compositor.
880#[derive(Clone, Debug, Deserialize, Serialize)]
881pub struct CompositorHitTestResult {
882    /// The pipeline id of the resulting item.
883    pub pipeline_id: PipelineId,
884
885    /// The hit test point in the item's viewport.
886    pub point_in_viewport: Point2D<f32, CSSPixel>,
887
888    /// The [`ExternalScrollId`] of the scroll tree node associated with this hit test item.
889    pub external_scroll_id: ExternalScrollId,
890}
891
892/// For a given pipeline, whether any animations are currently running
893/// and any animation callbacks are queued
894#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
895pub enum AnimationState {
896    /// Animations are active but no callbacks are queued
897    AnimationsPresent,
898    /// Animations are active and callbacks are queued
899    AnimationCallbacksPresent,
900    /// No animations are active and no callbacks are queued
901    NoAnimationsPresent,
902    /// No animations are active but callbacks are queued
903    NoAnimationCallbacksPresent,
904}
905
906/// A sequence number generated by a script thread for its pipelines. The
907/// constellation attaches the target pipeline's last seen `FocusSequenceNumber`
908/// to every focus-related message it sends.
909///
910/// This is used to resolve the inconsistency that occurs due to bidirectional
911/// focus state synchronization and provide eventual consistency. Example:
912///
913/// ```text
914/// script                            constellation
915/// -----------------------------------------------------------------------
916/// send ActivateDocument ----------> receive ActivateDocument
917///                             ,---- send FocusDocument
918///                             |
919/// focus an iframe             |
920/// send Focus -----------------|---> receive Focus
921///                             |     focus the iframe's content document
922/// receive FocusDocument <-----'     send FocusDocument to the content pipeline --> ...
923/// unfocus the iframe
924/// focus the document
925///
926/// Final state:                      Final state:
927///  the iframe is not focused         the iframe is focused
928/// ```
929///
930/// When the above sequence completes, from the script thread's point of view,
931/// the iframe is unfocused, but from the constellation's point of view, the
932/// iframe is still focused.
933///
934/// This inconsistency can be resolved by associating a sequence number to each
935/// message. Whenever a script thread initiates a focus operation, it generates
936/// and sends a brand new sequence number. The constellation attaches the
937/// last-received sequence number to each message it sends. This way, the script
938/// thread can discard out-dated incoming focus messages, and eventually, all
939/// actors converge to the consistent state which is determined based on the
940/// last focus message received by the constellation.
941///
942/// ```text
943/// script                            constellation
944/// -----------------------------------------------------------------------
945/// send ActivateDocument ----------> receive ActivateDocument
946///                             ,---- send FocusDocument (0)
947///                             |
948/// seq_number += 1             |
949/// focus an iframe             |
950/// send Focus (1) -------------|---> receive Focus (1)
951///                             |     focus the iframe's content document
952/// receive FocusDocument (0) <-'     send FocusDocument to the content pipeline --> ...
953/// ignore it because 0 < 1
954///
955/// Final state:                      Final state:
956///  the iframe is focused             the iframe is focused
957/// ```
958#[derive(
959    Clone,
960    Copy,
961    Debug,
962    Default,
963    Deserialize,
964    Eq,
965    Hash,
966    MallocSizeOf,
967    PartialEq,
968    Serialize,
969    PartialOrd,
970)]
971pub struct FocusSequenceNumber(pub u64);
972
973impl Display for FocusSequenceNumber {
974    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
975        Display::fmt(&self.0, f)
976    }
977}
978
979/// An identifier for a particular JavaScript evaluation that is used to track the
980/// evaluation from the embedding layer to the script layer and then back.
981#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
982pub struct JavaScriptEvaluationId(pub usize);
983
984#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
985pub enum JSValue {
986    Undefined,
987    Null,
988    Boolean(bool),
989    Number(f64),
990    String(String),
991    Element(String),
992    ShadowRoot(String),
993    Frame(String),
994    Window(String),
995    Array(Vec<JSValue>),
996    Object(HashMap<String, JSValue>),
997}
998
999#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1000pub struct JavaScriptErrorInfo {
1001    pub message: String,
1002    pub filename: String,
1003    pub stack: Option<String>,
1004    pub line_number: u64,
1005    pub column: u64,
1006}
1007
1008/// Indicates the reason that JavaScript evaluation failed due serializing issues the
1009/// result of the evaluation.
1010#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1011pub enum JavaScriptEvaluationResultSerializationError {
1012    /// Serialization could not complete because a JavaScript value contained a detached
1013    /// shadow root according to <https://w3c.github.io/webdriver/#dfn-internal-json-clone>.
1014    DetachedShadowRoot,
1015    /// Serialization could not complete because a JavaScript value contained a "stale"
1016    /// element reference according to <https://w3c.github.io/webdriver/#dfn-get-a-known-element>.
1017    StaleElementReference,
1018    /// Serialization could not complete because a JavaScript value of an unknown type
1019    /// was encountered.
1020    UnknownType,
1021    /// This is a catch all for other kinds of errors that can happen during JavaScript value
1022    /// serialization. For instances where this can happen, see:
1023    /// <https://w3c.github.io/webdriver/#dfn-clone-an-object>.
1024    OtherJavaScriptError,
1025}
1026
1027/// An error that happens when trying to evaluate JavaScript on a `WebView`.
1028#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1029pub enum JavaScriptEvaluationError {
1030    /// The `Document` of frame that the script was going to execute in no longer exists.
1031    DocumentNotFound,
1032    /// The script could not be compiled.
1033    CompilationFailure,
1034    /// The script could not be evaluated.
1035    EvaluationFailure(Option<JavaScriptErrorInfo>),
1036    /// An internal Servo error prevented the JavaSript evaluation from completing properly.
1037    /// This indicates a bug in Servo.
1038    InternalError,
1039    /// The `WebView` on which this evaluation request was triggered is not ready. This might
1040    /// happen if the `WebView`'s `Document` is changing due to ongoing load events, for instance.
1041    WebViewNotReady,
1042    /// The script executed successfully, but Servo could not serialize the JavaScript return
1043    /// value into a [`JSValue`].
1044    SerializationError(JavaScriptEvaluationResultSerializationError),
1045}
1046
1047#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1048pub enum ScreenshotCaptureError {
1049    /// The screenshot request failed to read the screenshot image from the `WebView`'s
1050    /// `RenderingContext`.
1051    CouldNotReadImage,
1052    /// The WebView that this screenshot request was made for no longer exists.
1053    WebViewDoesNotExist,
1054}
1055
1056#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
1057pub struct RgbColor {
1058    pub red: u8,
1059    pub green: u8,
1060    pub blue: u8,
1061}
1062
1063/// A Script to Embedder Channel
1064#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
1065pub struct ScriptToEmbedderChan(GenericCallback<EmbedderMsg>);
1066
1067impl ScriptToEmbedderChan {
1068    /// Create a new Channel allowing script to send messages to the Embedder
1069    pub fn new(
1070        embedder_chan: Sender<EmbedderMsg>,
1071        waker: Box<dyn EventLoopWaker>,
1072    ) -> ScriptToEmbedderChan {
1073        let embedder_callback = GenericCallback::new(move |embedder_msg| {
1074            let msg = match embedder_msg {
1075                Ok(embedder_msg) => embedder_msg,
1076                Err(err) => {
1077                    log::warn!("Script to Embedder message error: {err}");
1078                    return;
1079                },
1080            };
1081            let _ = embedder_chan.send(msg);
1082            waker.wake();
1083        })
1084        .expect("Failed to create channel");
1085        ScriptToEmbedderChan(embedder_callback)
1086    }
1087
1088    /// Send a message to and wake the Embedder
1089    pub fn send(&self, msg: EmbedderMsg) -> SendResult {
1090        self.0.send(msg)
1091    }
1092}