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