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, Copy, 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 Table,
445}
446
447impl From<ConsoleLogLevel> for log::Level {
448 fn from(value: ConsoleLogLevel) -> Self {
449 match value {
450 ConsoleLogLevel::Log => log::Level::Info,
451 ConsoleLogLevel::Debug => log::Level::Debug,
452 ConsoleLogLevel::Info => log::Level::Info,
453 ConsoleLogLevel::Warn => log::Level::Warn,
454 ConsoleLogLevel::Error => log::Level::Error,
455 ConsoleLogLevel::Trace => log::Level::Trace,
456 ConsoleLogLevel::Dir => log::Level::Info,
457 ConsoleLogLevel::Table => log::Level::Info,
458 }
459 }
460}
461
462/// Information about a single Bluetooth device.
463#[derive(Clone, Deserialize, Serialize)]
464pub struct BluetoothDeviceDescription {
465 /// The unique address of this device.
466 pub address: String,
467 /// A human-readable name for this device.
468 pub name: String,
469}
470
471/// Messages towards the embedder.
472#[derive(Deserialize, IntoStaticStr, Serialize)]
473pub enum EmbedderMsg {
474 /// A status message to be displayed by the browser chrome.
475 Status(WebViewId, Option<String>),
476 /// Alerts the embedder that the current page has changed its title.
477 ChangePageTitle(WebViewId, Option<String>),
478 /// Move the window to a point
479 MoveTo(WebViewId, DeviceIntPoint),
480 /// Resize the window to size
481 ResizeTo(WebViewId, DeviceIntSize),
482 /// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`,
483 /// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a
484 /// way that makes them impossible to mistake for browser UI.
485 ShowSimpleDialog(WebViewId, SimpleDialogRequest),
486 /// Request to (un)register protocol handler by page content.
487 AllowProtocolHandlerRequest(
488 WebViewId,
489 ProtocolHandlerUpdateRegistration,
490 GenericSender<AllowOrDeny>,
491 ),
492 /// Wether or not to unload a document
493 AllowUnload(WebViewId, GenericSender<AllowOrDeny>),
494 /// Inform embedder to clear the clipboard
495 ClearClipboard(WebViewId),
496 /// Gets system clipboard contents
497 GetClipboardText(WebViewId, GenericCallback<Result<String, String>>),
498 /// Sets system clipboard contents
499 SetClipboardText(WebViewId, String),
500 /// Changes the cursor.
501 SetCursor(WebViewId, Cursor),
502 /// Inform the embedder that a new favicon was set for the current top-level frame. In the case
503 /// that there is no favicon, `None` is sent.
504 SetFavicon(WebViewId, Option<Image>),
505 /// Get the device independent window rectangle.
506 GetWindowRect(WebViewId, GenericSender<DeviceIndependentIntRect>),
507 /// Get the device independent screen size and available size.
508 GetScreenMetrics(WebViewId, GenericSender<ScreenMetrics>),
509 /// Entered or exited fullscreen.
510 NotifyFullscreenStateChanged(WebViewId, bool),
511 /// The [`LoadStatus`] of the Given `WebView` has changed.
512 NotifyLoadStatusChanged(WebViewId, LoadStatus),
513 /// Open dialog to select bluetooth device.
514 GetSelectedBluetoothDevice(
515 WebViewId,
516 Vec<BluetoothDeviceDescription>,
517 GenericSender<Option<String>>,
518 ),
519 /// Open interface to request permission specified by prompt.
520 PromptPermission(WebViewId, PermissionFeature, GenericSender<AllowOrDeny>),
521 /// Request permission without blocking the script thread. The callback is invoked with the user's
522 /// decision once it is known.
523 RequestPermission(WebViewId, PermissionFeature, GenericCallback<AllowOrDeny>),
524 /// Request a single geographic position fix. The callback is invoked exactly once.
525 RequestGeolocationPosition(
526 WebViewId,
527 GeolocationRequestOptions,
528 GenericCallback<GeolocationResult>,
529 ),
530 /// Begin delivering continuous position updates for the given watch.
531 StartGeolocationWatch(
532 GeolocationWatchId,
533 GeolocationRequestOptions,
534 GenericCallback<GeolocationResult>,
535 ),
536 /// Stop delivering updates for a watch started by [`EmbedderMsg::StartGeolocationWatch`].
537 StopGeolocationWatch(GeolocationWatchId),
538 /// Report the status of Devtools Server with a token that can be used to bypass the permission prompt.
539 OnDevtoolsStarted(Result<u16, ()>, String),
540 /// Ask the user to allow a devtools client to connect.
541 RequestDevtoolsConnection(GenericSender<AllowOrDeny>),
542 /// Request to play a haptic effect on a connected gamepad.
543 #[cfg(feature = "gamepad")]
544 PlayGamepadHapticEffect(
545 WebViewId,
546 usize,
547 GamepadHapticEffectType,
548 GenericCallback<bool>,
549 ),
550 /// Request to stop a haptic effect on a connected gamepad.
551 #[cfg(feature = "gamepad")]
552 StopGamepadHapticEffect(WebViewId, usize, GenericCallback<bool>),
553 /// Request to display a notification.
554 ShowNotification(Option<WebViewId>, Notification),
555 /// Let the embedder process a DOM Console API message.
556 /// <https://developer.mozilla.org/en-US/docs/Web/API/Console_API>
557 ShowConsoleApiMessage(Option<WebViewId>, ConsoleLogLevel, String),
558 /// Request to the embedder to display a user interace control.
559 ShowEmbedderControl(EmbedderControlId, DeviceIntRect, EmbedderControlRequest),
560 /// Request to the embedder to hide a user interface control.
561 HideEmbedderControl(EmbedderControlId),
562 /// Inform the embedding layer that a particular `InputEvent` was handled by Servo
563 /// and the embedder can continue processing it, if necessary.
564 InputEventsHandled(WebViewId, Vec<InputEventOutcome>),
565 /// Send the embedder an accessibility tree update.
566 AccessibilityTreeUpdate(WebViewId, TreeUpdate, Epoch),
567}
568
569impl Debug for EmbedderMsg {
570 fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
571 let string: &'static str = self.into();
572 write!(formatter, "{string}")
573 }
574}
575
576/// <https://w3c.github.io/mediasession/#mediametadata>
577#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
578pub struct MediaMetadata {
579 /// Title
580 pub title: String,
581 /// Artist
582 pub artist: String,
583 /// Album
584 pub album: String,
585}
586
587impl MediaMetadata {
588 pub fn new(title: String) -> Self {
589 Self {
590 title,
591 artist: String::new(),
592 album: String::new(),
593 }
594 }
595}
596
597/// <https://w3c.github.io/mediasession/#enumdef-mediasessionplaybackstate>
598#[repr(i32)]
599#[derive(Clone, Debug, Deserialize, Serialize)]
600pub enum MediaSessionPlaybackState {
601 /// The browsing context does not specify whether it’s playing or paused.
602 None_ = 1,
603 /// The browsing context is currently playing media and it can be paused.
604 Playing,
605 /// The browsing context has paused media and it can be resumed.
606 Paused,
607}
608
609/// <https://w3c.github.io/mediasession/#dictdef-mediapositionstate>
610#[derive(Clone, Debug, Deserialize, Serialize)]
611pub struct MediaPositionState {
612 pub duration: f64,
613 pub playback_rate: f64,
614 pub position: f64,
615}
616
617impl MediaPositionState {
618 pub fn new(duration: f64, playback_rate: f64, position: f64) -> Self {
619 Self {
620 duration,
621 playback_rate,
622 position,
623 }
624 }
625}
626
627/// Type of events sent from script to the embedder about the media session.
628#[derive(Clone, Debug, Deserialize, Serialize)]
629pub enum MediaSessionEvent {
630 /// Indicates that the media metadata is available.
631 SetMetadata(MediaMetadata),
632 /// Indicates that the playback state has changed.
633 PlaybackStateChange(MediaSessionPlaybackState),
634 /// Indicates that the position state is set.
635 SetPositionState(MediaPositionState),
636}
637
638/// Enum with variants that match the DOM PermissionName enum
639#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
640pub enum PermissionFeature {
641 Geolocation,
642 Notifications,
643 Push,
644 Midi,
645 Camera,
646 Microphone,
647 Speaker,
648 DeviceInfo,
649 BackgroundSync,
650 Bluetooth,
651 PersistentStorage,
652 ScreenWakeLock(WakeLockType),
653 Gamepad,
654}
655
656/// Used to specify the kind of input method editor appropriate to edit a field.
657/// This is a subset of htmlinputelement::InputType because some variants of InputType
658/// don't make sense in this context.
659#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
660pub enum InputMethodType {
661 Color,
662 Date,
663 DatetimeLocal,
664 Email,
665 Month,
666 Number,
667 Password,
668 Search,
669 Tel,
670 Text,
671 Time,
672 Url,
673 Week,
674}
675
676#[cfg(feature = "gamepad")]
677#[derive(Clone, Debug, Deserialize, Serialize)]
678/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype-dual-rumble>
679pub struct DualRumbleEffectParams {
680 pub duration: f64,
681 pub start_delay: f64,
682 pub strong_magnitude: f64,
683 pub weak_magnitude: f64,
684}
685
686#[cfg(feature = "gamepad")]
687#[derive(Clone, Debug, Deserialize, Serialize)]
688/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype>
689pub enum GamepadHapticEffectType {
690 DualRumble(DualRumbleEffectParams),
691}
692
693#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
694pub struct WebResourceRequest {
695 #[serde(
696 deserialize_with = "::hyper_serde::deserialize",
697 serialize_with = "::hyper_serde::serialize"
698 )]
699 pub method: Method,
700 #[serde(
701 deserialize_with = "::hyper_serde::deserialize",
702 serialize_with = "::hyper_serde::serialize"
703 )]
704 pub headers: HeaderMap,
705 pub url: ServoUrl,
706 pub destination: Destination,
707 pub referrer_url: Option<ServoUrl>,
708 pub is_for_main_frame: bool,
709 pub is_redirect: bool,
710}
711
712#[derive(Clone, Deserialize, Serialize)]
713pub enum WebResourceResponseMsg {
714 /// Start an interception of this web resource load. It's expected that the client subsequently
715 /// send either a `CancelLoad` or `FinishLoad` message after optionally sending chunks of body
716 /// data via `SendBodyData`.
717 Start(WebResourceResponse),
718 /// Send a chunk of body data.
719 SendBodyData(Vec<u8>),
720 /// Signal that this load has been finished by the interceptor.
721 FinishLoad,
722 /// Signal that this load has been cancelled by the interceptor.
723 CancelLoad,
724 /// Signal that this load will not be intercepted.
725 DoNotIntercept,
726}
727
728#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
729pub struct WebResourceResponse {
730 pub url: Url,
731 #[serde(
732 deserialize_with = "::hyper_serde::deserialize",
733 serialize_with = "::hyper_serde::serialize"
734 )]
735 pub headers: HeaderMap,
736 #[serde(
737 deserialize_with = "::hyper_serde::deserialize",
738 serialize_with = "::hyper_serde::serialize"
739 )]
740 pub status_code: StatusCode,
741 pub status_message: Vec<u8>,
742}
743
744impl WebResourceResponse {
745 pub fn new(url: Url) -> WebResourceResponse {
746 WebResourceResponse {
747 url,
748 headers: HeaderMap::new(),
749 status_code: StatusCode::OK,
750 status_message: b"OK".to_vec(),
751 }
752 }
753
754 pub fn headers(mut self, headers: HeaderMap) -> WebResourceResponse {
755 self.headers = headers;
756 self
757 }
758
759 pub fn status_code(mut self, status_code: StatusCode) -> WebResourceResponse {
760 self.status_code = status_code;
761 self
762 }
763
764 pub fn status_message(mut self, status_message: Vec<u8>) -> WebResourceResponse {
765 self.status_message = status_message;
766 self
767 }
768}
769
770/// The type of platform theme.
771#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
772pub enum Theme {
773 /// Light theme.
774 Light,
775 /// Dark theme.
776 Dark,
777}
778
779impl From<Theme> for PrefersColorScheme {
780 fn from(value: Theme) -> Self {
781 match value {
782 Theme::Light => PrefersColorScheme::Light,
783 Theme::Dark => PrefersColorScheme::Dark,
784 }
785 }
786}
787
788// The type of MediaSession action.
789/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
790#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
791pub enum MediaSessionActionType {
792 /// The action intent is to resume playback.
793 Play,
794 /// The action intent is to pause the currently active playback.
795 Pause,
796 /// The action intent is to move the playback time backward by a short period (i.e. a few
797 /// seconds).
798 SeekBackward,
799 /// The action intent is to move the playback time forward by a short period (i.e. a few
800 /// seconds).
801 SeekForward,
802 /// The action intent is to either start the current playback from the beginning if the
803 /// playback has a notion, of beginning, or move to the previous item in the playlist if the
804 /// playback has a notion of playlist.
805 PreviousTrack,
806 /// The action is to move to the playback to the next item in the playlist if the playback has
807 /// a notion of playlist.
808 NextTrack,
809 /// The action intent is to skip the advertisement that is currently playing.
810 SkipAd,
811 /// The action intent is to stop the playback and clear the state if appropriate.
812 Stop,
813 /// The action intent is to move the playback time to a specific time.
814 SeekTo,
815}
816
817/// The status of the load in this `WebView`.
818#[repr(i32)]
819#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
820pub enum LoadStatus {
821 /// The load has started, but the headers have not yet been parsed.
822 Started,
823 /// The `<head>` tag has been parsed in the currently loading page. At this point the page's
824 /// `HTMLBodyElement` is now available in the DOM.
825 HeadParsed,
826 /// The `Document` and all subresources have loaded. This is equivalent to
827 /// `document.readyState` == `complete`.
828 /// See <https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState>
829 Complete,
830 /// The current load was stopped, either by the embedder or by script on the page
831 /// (for instance, by calling `window.stop()`).
832 Stopped,
833}
834
835/// Data that could be used to display a desktop notification to the end user
836/// when the [Notification API](<https://notifications.spec.whatwg.org/#notifications>) is called.
837#[derive(Clone, Debug, Deserialize, Serialize)]
838pub struct Notification {
839 /// Title of the notification.
840 pub title: String,
841 /// Body string of the notification.
842 pub body: String,
843 /// An identifier tag for the notification. Notification with the same tag
844 /// can be replaced by another to avoid users' screen being filled up with similar notifications.
845 pub tag: String,
846 /// 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)
847 pub language: String,
848 /// A boolean value indicates the notification should remain readily available
849 /// until the end user activates or dismisses the notification.
850 pub require_interaction: bool,
851 /// When `true`, indicates no sounds or vibrations should be made. When `None`,
852 /// the device's default settings should be respected.
853 pub silent: Option<bool>,
854 /// The URL of an icon. The icon will be displayed as part of the notification.
855 pub icon_url: Option<ServoUrl>,
856 /// Icon's raw image data and metadata.
857 pub icon_resource: Option<Arc<SharedRasterImage>>,
858 /// The URL of a badge. The badge is used when there is no enough space to display the notification,
859 /// such as on a mobile device's notification bar.
860 pub badge_url: Option<ServoUrl>,
861 /// Badge's raw image data and metadata.
862 pub badge_resource: Option<Arc<SharedRasterImage>>,
863 /// The URL of an image. The image will be displayed as part of the notification.
864 pub image_url: Option<ServoUrl>,
865 /// Image's raw image data and metadata.
866 pub image_resource: Option<Arc<SharedRasterImage>>,
867 /// Actions available for users to choose from for interacting with the notification.
868 pub actions: Vec<NotificationAction>,
869}
870
871/// Actions available for users to choose from for interacting with the notification.
872#[derive(Clone, Debug, Deserialize, Serialize)]
873pub struct NotificationAction {
874 /// A string that identifies the action.
875 pub name: String,
876 /// The title string of the action to be shown to the user.
877 pub title: String,
878 /// The URL of an icon. The icon will be displayed with the action.
879 pub icon_url: Option<ServoUrl>,
880 /// Icon's raw image data and metadata.
881 pub icon_resource: Option<Arc<SharedRasterImage>>,
882}
883
884/// Information about a `WebView`'s screen geometry and offset. This is used
885/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface) CSSOM APIs
886/// and `window.screenLeft` / `window.screenX` / `window.screenTop` / `window.screenY` /
887/// `window.moveBy`/ `window.resizeBy` / `window.outerWidth` / `window.outerHeight` /
888/// `window.screen.availHeight` / `window.screen.availWidth`.
889#[derive(Clone, Copy, Debug, Default)]
890pub struct ScreenGeometry {
891 /// The size of the screen in device pixels. This will be converted to
892 /// CSS pixels based on the pixel scaling of the `WebView`.
893 pub size: DeviceIntSize,
894 /// The available size of the screen in device pixels for the purposes of
895 /// the `window.screen.availHeight` / `window.screen.availWidth`. This is the size
896 /// available for web content on the screen, and should be `size` minus any system
897 /// toolbars, docks, and interface elements. This will be converted to
898 /// CSS pixels based on the pixel scaling of the `WebView`.
899 pub available_size: DeviceIntSize,
900 /// The rectangle the `WebView`'s containing window (including OS decorations)
901 /// in device pixels for the purposes of the
902 /// `window.screenLeft`, `window.outerHeight` and similar APIs.
903 /// This will be converted to CSS pixels based on the pixel scaling of the `WebView`.
904 pub window_rect: DeviceIntRect,
905}
906
907impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
908 fn from(value: SelectElementOption) -> Self {
909 Self::Option(value)
910 }
911}
912
913/// The address of a node. Layout sends these back. They must be validated via
914/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
915#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
916pub struct UntrustedNodeAddress(pub *const c_void);
917
918malloc_size_of_is_0!(UntrustedNodeAddress);
919
920#[expect(unsafe_code)]
921unsafe impl Send for UntrustedNodeAddress {}
922
923impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress {
924 fn from(o: style_traits::dom::OpaqueNode) -> Self {
925 UntrustedNodeAddress(o.0 as *const c_void)
926 }
927}
928
929impl Serialize for UntrustedNodeAddress {
930 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
931 (self.0 as usize).serialize(s)
932 }
933}
934
935impl<'de> Deserialize<'de> for UntrustedNodeAddress {
936 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> {
937 let value: usize = Deserialize::deserialize(d)?;
938 Ok(UntrustedNodeAddress::from_id(value))
939 }
940}
941
942impl UntrustedNodeAddress {
943 /// Creates an `UntrustedNodeAddress` from the given pointer address value.
944 #[inline]
945 pub fn from_id(id: usize) -> UntrustedNodeAddress {
946 UntrustedNodeAddress(id as *const c_void)
947 }
948}
949
950/// The result of a hit test in `Paint`.
951#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
952pub struct PaintHitTestResult {
953 /// The pipeline id of the resulting item.
954 pub pipeline_id: PipelineId,
955
956 /// The hit test point in the item's viewport.
957 pub point_in_viewport: Point2D<f32, CSSPixel>,
958
959 /// The [`ExternalScrollId`] of the scroll tree node associated with this hit test item.
960 pub external_scroll_id: ExternalScrollId,
961}
962
963/// For a given pipeline, whether any animations are currently running
964/// and any animation callbacks are queued
965#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
966pub enum AnimationState {
967 /// Animations are active but no callbacks are queued
968 AnimationsPresent,
969 /// Animations are active and callbacks are queued
970 AnimationCallbacksPresent,
971 /// No animations are active and no callbacks are queued
972 NoAnimationsPresent,
973 /// No animations are active but callbacks are queued
974 AnimationCallbacksAbsent,
975}
976
977/// A sequence number generated by a script thread for its pipelines. The
978/// constellation attaches the target pipeline's last seen `FocusSequenceNumber`
979/// to every focus-related message it sends.
980///
981/// This is used to resolve the inconsistency that occurs due to bidirectional
982/// focus state synchronization and provide eventual consistency. Example:
983///
984/// ```text
985/// script constellation
986/// -----------------------------------------------------------------------
987/// send ActivateDocument ----------> receive ActivateDocument
988/// ,---- send FocusDocument
989/// |
990/// focus an iframe |
991/// send Focus -----------------|---> receive Focus
992/// | focus the iframe's content document
993/// receive FocusDocument <-----' send FocusDocument to the content pipeline --> ...
994/// unfocus the iframe
995/// focus the document
996///
997/// Final state: Final state:
998/// the iframe is not focused the iframe is focused
999/// ```
1000///
1001/// When the above sequence completes, from the script thread's point of view,
1002/// the iframe is unfocused, but from the constellation's point of view, the
1003/// iframe is still focused.
1004///
1005/// This inconsistency can be resolved by associating a sequence number to each
1006/// message. Whenever a script thread initiates a focus operation, it generates
1007/// and sends a brand new sequence number. The constellation attaches the
1008/// last-received sequence number to each message it sends. This way, the script
1009/// thread can discard out-dated incoming focus messages, and eventually, all
1010/// actors converge to the consistent state which is determined based on the
1011/// last focus message received by the constellation.
1012///
1013/// ```text
1014/// script constellation
1015/// -----------------------------------------------------------------------
1016/// send ActivateDocument ----------> receive ActivateDocument
1017/// ,---- send FocusDocument (0)
1018/// |
1019/// seq_number += 1 |
1020/// focus an iframe |
1021/// send Focus (1) -------------|---> receive Focus (1)
1022/// | focus the iframe's content document
1023/// receive FocusDocument (0) <-' send FocusDocument to the content pipeline --> ...
1024/// ignore it because 0 < 1
1025///
1026/// Final state: Final state:
1027/// the iframe is focused the iframe is focused
1028/// ```
1029#[derive(
1030 Clone,
1031 Copy,
1032 Debug,
1033 Default,
1034 Deserialize,
1035 Eq,
1036 Hash,
1037 MallocSizeOf,
1038 PartialEq,
1039 Serialize,
1040 PartialOrd,
1041)]
1042pub struct FocusSequenceNumber(pub u64);
1043
1044impl Display for FocusSequenceNumber {
1045 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
1046 Display::fmt(&self.0, f)
1047 }
1048}
1049
1050/// An identifier for a particular JavaScript evaluation that is used to track the
1051/// evaluation from the embedding layer to the script layer and then back.
1052#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
1053pub struct JavaScriptEvaluationId(pub usize);
1054
1055/// A JavaScript value produced by evaluation of a script.
1056#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1057pub enum JSValue {
1058 Undefined,
1059 Null,
1060 Boolean(bool),
1061 Number(f64),
1062 String(String),
1063 Element(String),
1064 ShadowRoot(String),
1065 Frame(String),
1066 Window(String),
1067 Array(Vec<JSValue>),
1068 Object(HashMap<String, JSValue>),
1069}
1070
1071/// Information about a JavaScript error that occured during the evaluation of a script.
1072#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1073pub struct JavaScriptErrorInfo {
1074 pub message: String,
1075 pub filename: String,
1076 pub stack: Option<String>,
1077 pub line_number: u64,
1078 pub column: u64,
1079}
1080
1081/// Indicates the reason that JavaScript evaluation failed due serializing issues the
1082/// result of the evaluation.
1083#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1084pub enum JavaScriptEvaluationResultSerializationError {
1085 /// Serialization could not complete because a JavaScript value contained a detached
1086 /// shadow root according to <https://w3c.github.io/webdriver/#dfn-internal-json-clone>.
1087 DetachedShadowRoot,
1088 /// Serialization could not complete because a JavaScript value contained a "stale"
1089 /// element reference according to <https://w3c.github.io/webdriver/#dfn-get-a-known-element>.
1090 StaleElementReference,
1091 /// Serialization could not complete because a JavaScript value of an unknown type
1092 /// was encountered.
1093 UnknownType,
1094 /// This is a catch all for other kinds of errors that can happen during JavaScript value
1095 /// serialization. For instances where this can happen, see:
1096 /// <https://w3c.github.io/webdriver/#dfn-clone-an-object>.
1097 OtherJavaScriptError,
1098}
1099
1100/// An error that happens when trying to evaluate JavaScript on a `WebView`.
1101#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
1102pub enum JavaScriptEvaluationError {
1103 /// The `Document` of frame that the script was going to execute in no longer exists.
1104 DocumentNotFound,
1105 /// The script could not be compiled.
1106 CompilationFailure,
1107 /// The script could not be evaluated.
1108 EvaluationFailure(Option<JavaScriptErrorInfo>),
1109 /// An internal Servo error prevented the JavaSript evaluation from completing properly.
1110 /// This indicates a bug in Servo.
1111 InternalError,
1112 /// The `WebView` on which this evaluation request was triggered is not ready. This might
1113 /// happen if the `WebView`'s `Document` is changing due to ongoing load events, for instance.
1114 WebViewNotReady,
1115 /// The script executed successfully, but Servo could not serialize the JavaScript return
1116 /// value into a [`JSValue`].
1117 SerializationError(JavaScriptEvaluationResultSerializationError),
1118}
1119
1120#[repr(i32)]
1121#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
1122pub enum ScreenshotCaptureError {
1123 /// The screenshot request failed to read the screenshot image from the `WebView`'s
1124 /// `RenderingContext`.
1125 CouldNotReadImage,
1126 /// The WebView that this screenshot request was made for no longer exists.
1127 WebViewDoesNotExist,
1128}
1129
1130#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
1131pub struct RgbColor {
1132 pub red: u8,
1133 pub green: u8,
1134 pub blue: u8,
1135}
1136
1137/// A Script to Embedder Channel
1138#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
1139pub struct ScriptToEmbedderChan(GenericCallback<EmbedderMsg>);
1140
1141impl ScriptToEmbedderChan {
1142 /// Create a new Channel allowing script to send messages to the Embedder
1143 pub fn new(
1144 embedder_chan: Sender<EmbedderMsg>,
1145 waker: Box<dyn EventLoopWaker>,
1146 ) -> ScriptToEmbedderChan {
1147 let embedder_callback = GenericCallback::new(move |embedder_msg| {
1148 let msg = match embedder_msg {
1149 Ok(embedder_msg) => embedder_msg,
1150 Err(err) => {
1151 log::warn!("Script to Embedder message error: {err}");
1152 return;
1153 },
1154 };
1155 let _ = embedder_chan.send(msg);
1156 waker.wake();
1157 })
1158 .expect("Failed to create channel");
1159 ScriptToEmbedderChan(embedder_callback)
1160 }
1161
1162 /// Send a message to and wake the Embedder
1163 pub fn send(&self, msg: EmbedderMsg) -> SendResult {
1164 self.0.send(msg)
1165 }
1166}
1167
1168/// Used for communicating the details of a new `WebView` created by the embedder
1169/// back to the constellation.
1170#[derive(Deserialize, Serialize)]
1171pub struct NewWebViewDetails {
1172 pub webview_id: WebViewId,
1173 pub viewport_details: ViewportDetails,
1174 pub user_content_manager_id: Option<UserContentManagerId>,
1175}
1176
1177#[derive(Serialize, Deserialize, Debug)]
1178/// A request to load a URL. This can be used to trigger a configurable load in a `WebView`.
1179///
1180/// ```
1181/// let mut headers = http::HeaderMap::new();
1182/// headers.append(HeaderName::from_static("CustomHeader"), "Value".parse().unwrap());
1183/// let url_request = URLRequest::new(url).headers(headers);
1184/// webview.load_request(url_request);
1185/// ```
1186pub struct UrlRequest {
1187 pub url: ServoUrl,
1188 #[serde(
1189 deserialize_with = "hyper_serde::deserialize",
1190 serialize_with = "hyper_serde::serialize"
1191 )]
1192 pub headers: HeaderMap,
1193}
1194
1195impl UrlRequest {
1196 pub fn new(url: Url) -> Self {
1197 UrlRequest {
1198 url: url.into(),
1199 headers: HeaderMap::new(),
1200 }
1201 }
1202
1203 /// Set headers that will be added to the Headers
1204 pub fn headers(mut self, headers: HeaderMap) -> Self {
1205 self.headers = headers;
1206 self
1207 }
1208}
1209
1210/// The type of wake lock to acquire or release.
1211#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1212pub enum WakeLockType {
1213 Screen,
1214}
1215
1216/// Trait for platform-specific wake lock support.
1217///
1218/// Implementations are responsible for interacting with the OS to prevent
1219/// the screen (or other resources) from sleeping while a wake lock is held.
1220pub trait WakeLockDelegate: Send + Sync {
1221 /// Acquire a wake lock of the given type, preventing the associated
1222 /// resource from sleeping. Called when the aggregate lock count transitions
1223 /// from 0 to 1. Returns an error if the OS fails to grant the lock.
1224 fn acquire(&self, type_: WakeLockType) -> Result<(), Box<dyn std::error::Error>>;
1225
1226 /// Release a previously acquired wake lock of the given type, allowing
1227 /// the resource to sleep. Called when the aggregate lock count transitions
1228 /// from N to 0.
1229 fn release(&self, type_: WakeLockType) -> Result<(), Box<dyn std::error::Error>>;
1230}