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}