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