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