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}