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