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