blob: d53757d04e9ed622a28dfb9942dd83099a42297a [file] [log] [blame] [edit]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Types used by the embedding layer and/or exposed to the API. This crate is responsible for
//! defining types that cross the process boundary from the embedding/rendering layer all the way
//! to script, thus it should have very minimal dependencies on other parts of Servo. If a type
//! is not exposed in the API or doesn't involve messages sent to the embedding/libservo layer, it
//! is probably a better fit for the `constellation_traits` crate.
pub mod input_events;
pub mod resources;
pub mod user_content_manager;
pub mod webdriver;
use std::collections::HashMap;
use std::ffi::c_void;
use std::fmt::{Debug, Display, Error, Formatter};
use std::hash::Hash;
use std::ops::Range;
use std::path::PathBuf;
use std::sync::Arc;
use base::generic_channel::{GenericCallback, GenericSender, SendResult};
use base::id::{PipelineId, WebViewId};
use crossbeam_channel::Sender;
use euclid::{Point2D, Scale, Size2D};
use http::{HeaderMap, Method, StatusCode};
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
use log::warn;
use malloc_size_of::malloc_size_of_is_0;
use malloc_size_of_derive::MallocSizeOf;
use pixels::RasterImage;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
use servo_url::ServoUrl;
use strum_macros::IntoStaticStr;
use style::queries::values::PrefersColorScheme;
use style_traits::CSSPixel;
use url::Url;
use uuid::Uuid;
use webrender_api::ExternalScrollId;
use webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixel, LayoutSize};
pub use crate::input_events::*;
pub use crate::webdriver::*;
/// Tracks whether Servo isn't shutting down, is in the process of shutting down,
/// or has finished shutting down.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ShutdownState {
NotShuttingDown,
ShuttingDown,
FinishedShuttingDown,
}
/// A cursor for the window. This is different from a CSS cursor (see
/// `CursorKind`) in that it has no `Auto` value.
#[repr(u8)]
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum Cursor {
None,
#[default]
Default,
Pointer,
ContextMenu,
Help,
Progress,
Wait,
Cell,
Crosshair,
Text,
VerticalText,
Alias,
Copy,
Move,
NoDrop,
NotAllowed,
Grab,
Grabbing,
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
AllScroll,
ZoomIn,
ZoomOut,
}
pub trait EventLoopWaker: 'static + Send {
fn clone_box(&self) -> Box<dyn EventLoopWaker>;
fn wake(&self) {}
}
impl Clone for Box<dyn EventLoopWaker> {
fn clone(&self) -> Self {
self.clone_box()
}
}
/// Sends messages to the embedder.
pub struct EmbedderProxy {
pub sender: Sender<EmbedderMsg>,
pub event_loop_waker: Box<dyn EventLoopWaker>,
}
impl EmbedderProxy {
pub fn send(&self, message: EmbedderMsg) {
// Send a message and kick the OS event loop awake.
if let Err(err) = self.sender.send(message) {
warn!("Failed to send response ({:?}).", err);
}
self.event_loop_waker.wake();
}
}
impl Clone for EmbedderProxy {
fn clone(&self) -> EmbedderProxy {
EmbedderProxy {
sender: self.sender.clone(),
event_loop_waker: self.event_loop_waker.clone(),
}
}
}
#[derive(Deserialize, Serialize)]
pub enum ContextMenuResult {
Dismissed,
Ignored,
Selected(usize),
}
/// [Simple dialogs](https://html.spec.whatwg.org/multipage/#simple-dialogs) are synchronous dialogs
/// that can be opened by web content. Since their messages are controlled by web content, they
/// should be presented to the user in a way that makes them impossible to mistake for browser UI.
#[derive(Deserialize, Serialize)]
pub enum SimpleDialog {
/// [`alert()`](https://html.spec.whatwg.org/multipage/#dom-alert).
/// TODO: Include details about the document origin.
Alert {
message: String,
response_sender: GenericSender<AlertResponse>,
},
/// [`confirm()`](https://html.spec.whatwg.org/multipage/#dom-confirm).
/// TODO: Include details about the document origin.
Confirm {
message: String,
response_sender: GenericSender<ConfirmResponse>,
},
/// [`prompt()`](https://html.spec.whatwg.org/multipage/#dom-prompt).
/// TODO: Include details about the document origin.
Prompt {
message: String,
default: String,
response_sender: GenericSender<PromptResponse>,
},
}
impl SimpleDialog {
/// Returns the message of the dialog.
pub fn message(&self) -> &str {
match self {
SimpleDialog::Alert { message, .. } => message,
SimpleDialog::Confirm { message, .. } => message,
SimpleDialog::Prompt { message, .. } => message,
}
}
pub fn set_message(&mut self, text: String) {
match self {
SimpleDialog::Alert { message, .. } => *message = text,
SimpleDialog::Confirm { message, .. } => *message = text,
SimpleDialog::Prompt { message, .. } => *message = text,
}
}
pub fn dismiss(&self) {
match self {
SimpleDialog::Alert {
response_sender, ..
} => {
let _ = response_sender.send(AlertResponse::Ok);
},
SimpleDialog::Confirm {
response_sender, ..
} => {
let _ = response_sender.send(ConfirmResponse::Cancel);
},
SimpleDialog::Prompt {
response_sender, ..
} => {
let _ = response_sender.send(PromptResponse::Cancel);
},
}
}
pub fn accept(&self) {
match self {
SimpleDialog::Alert {
response_sender, ..
} => {
let _ = response_sender.send(AlertResponse::Ok);
},
SimpleDialog::Confirm {
response_sender, ..
} => {
let _ = response_sender.send(ConfirmResponse::Ok);
},
SimpleDialog::Prompt {
default,
response_sender,
..
} => {
let _ = response_sender.send(PromptResponse::Ok(default.clone()));
},
}
}
}
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct AuthenticationResponse {
/// Username for http request authentication
pub username: String,
/// Password for http request authentication
pub password: String,
}
#[derive(Deserialize, PartialEq, Serialize)]
pub enum AlertResponse {
/// The user chose Ok, or the dialog was otherwise dismissed or ignored.
Ok,
}
impl Default for AlertResponse {
fn default() -> Self {
// Per <https://html.spec.whatwg.org/multipage/#dom-alert>,
// if we **cannot show simple dialogs**, including cases where the user or user agent decides to ignore
// all modal dialogs, we need to return (which represents Ok).
Self::Ok
}
}
#[derive(Deserialize, PartialEq, Serialize)]
pub enum ConfirmResponse {
/// The user chose Ok.
Ok,
/// The user chose Cancel, or the dialog was otherwise dismissed or ignored.
Cancel,
}
impl Default for ConfirmResponse {
fn default() -> Self {
// Per <https://html.spec.whatwg.org/multipage/#dom-confirm>,
// if we **cannot show simple dialogs**, including cases where the user or user agent decides to ignore
// all modal dialogs, we need to return false (which represents Cancel), not true (Ok).
Self::Cancel
}
}
#[derive(Deserialize, PartialEq, Serialize)]
pub enum PromptResponse {
/// The user chose Ok, with the given input.
Ok(String),
/// The user chose Cancel, or the dialog was otherwise dismissed or ignored.
Cancel,
}
impl Default for PromptResponse {
fn default() -> Self {
// Per <https://html.spec.whatwg.org/multipage/#dom-prompt>,
// if we **cannot show simple dialogs**, including cases where the user or user agent decides to ignore
// all modal dialogs, we need to return null (which represents Cancel), not the default input.
Self::Cancel
}
}
/// A response to a request to allow or deny an action.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum AllowOrDeny {
Allow,
Deny,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SelectElementOption {
/// A unique identifier for the option that can be used to select it.
pub id: usize,
/// The label that should be used to display the option to the user.
pub label: String,
/// Whether or not the option is selectable
pub is_disabled: bool,
}
/// Represents the contents of either an `<option>` or an `<optgroup>` element
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum SelectElementOptionOrOptgroup {
Option(SelectElementOption),
Optgroup {
label: String,
options: Vec<SelectElementOption>,
},
}
/// Data about a `WebView` or `<iframe>` viewport: its size and also the
/// HiDPI scale factor to use when rendering the contents.
#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub struct ViewportDetails {
/// The size of the layout viewport.
pub size: Size2D<f32, CSSPixel>,
/// The scale factor to use to account for HiDPI scaling. This does not take into account
/// any page or pinch zoom applied by the compositor to the contents.
pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>,
}
impl ViewportDetails {
/// Convert this [`ViewportDetails`] size to a [`LayoutSize`]. This is the same numerical
/// value as [`Self::size`], because a `LayoutPixel` is the same as a `CSSPixel`.
pub fn layout_size(&self) -> LayoutSize {
Size2D::from_untyped(self.size.to_untyped())
}
}
/// Unlike [`ScreenGeometry`], the data is in device-independent pixels
/// to be used by DOM APIs
#[derive(Default, Deserialize, Serialize)]
pub struct ScreenMetrics {
pub screen_size: DeviceIndependentIntSize,
pub available_size: DeviceIndependentIntSize,
}
/// An opaque identifier for a single webview focus operation.
#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct FocusId(String);
impl FocusId {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self(Uuid::new_v4().to_string())
}
}
/// An opaque identifier for a single history traversal operation.
#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct TraversalId(String);
impl TraversalId {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self(Uuid::new_v4().to_string())
}
}
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum PixelFormat {
/// Luminance channel only
K8,
/// Luminance + alpha
KA8,
/// RGB, 8 bits per channel
RGB8,
/// RGB + alpha, 8 bits per channel
RGBA8,
/// BGR + alpha, 8 bits per channel
BGRA8,
}
/// A raster image buffer.
#[derive(Clone, Deserialize, Serialize)]
pub struct Image {
pub width: u32,
pub height: u32,
pub format: PixelFormat,
/// A shared memory block containing the data of one or more image frames.
data: IpcSharedMemory,
range: Range<usize>,
}
impl Image {
pub fn new(
width: u32,
height: u32,
data: IpcSharedMemory,
range: Range<usize>,
format: PixelFormat,
) -> Self {
Self {
width,
height,
format,
data,
range,
}
}
/// Return the bytes belonging to the first image frame.
pub fn data(&self) -> &[u8] {
&self.data[self.range.clone()]
}
}
#[derive(Deserialize, IntoStaticStr, Serialize)]
pub enum EmbedderMsg {
/// A status message to be displayed by the browser chrome.
Status(WebViewId, Option<String>),
/// Alerts the embedder that the current page has changed its title.
ChangePageTitle(WebViewId, Option<String>),
/// Move the window to a point
MoveTo(WebViewId, DeviceIntPoint),
/// Resize the window to size
ResizeTo(WebViewId, DeviceIntSize),
/// Show the user a [simple dialog](https://html.spec.whatwg.org/multipage/#simple-dialogs) (`alert()`, `confirm()`,
/// or `prompt()`). Since their messages are controlled by web content, they should be presented to the user in a
/// way that makes them impossible to mistake for browser UI.
ShowSimpleDialog(WebViewId, SimpleDialog),
/// Request authentication for a load or navigation from the embedder.
RequestAuthentication(
WebViewId,
ServoUrl,
bool, /* for proxy */
GenericSender<Option<AuthenticationResponse>>,
),
/// Show a context menu to the user
ShowContextMenu(
WebViewId,
GenericSender<ContextMenuResult>,
Option<String>,
Vec<String>,
),
/// Whether or not to allow a pipeline to load a url.
AllowNavigationRequest(WebViewId, PipelineId, ServoUrl),
/// Whether or not to allow script to open a new tab/browser
AllowOpeningWebView(
WebViewId,
GenericSender<Option<(WebViewId, ViewportDetails)>>,
),
/// A webview was destroyed.
WebViewClosed(WebViewId),
/// A webview potentially gained focus for keyboard events, as initiated
/// by the provided focus id. If the boolean value is false, the webiew
/// could not be focused.
WebViewFocused(WebViewId, FocusId, bool),
/// All webviews lost focus for keyboard events.
WebViewBlurred,
/// Wether or not to unload a document
AllowUnload(WebViewId, GenericSender<AllowOrDeny>),
/// Sends an unconsumed key event back to the embedder.
Keyboard(WebViewId, KeyboardEvent),
/// Inform embedder to clear the clipboard
ClearClipboard(WebViewId),
/// Gets system clipboard contents
GetClipboardText(WebViewId, IpcSender<Result<String, String>>),
/// Sets system clipboard contents
SetClipboardText(WebViewId, String),
/// Changes the cursor.
SetCursor(WebViewId, Cursor),
/// A favicon was detected
NewFavicon(WebViewId, Image),
/// The history state has changed.
HistoryChanged(WebViewId, Vec<ServoUrl>, usize),
/// A history traversal operation completed.
HistoryTraversalComplete(WebViewId, TraversalId),
/// Get the device independent window rectangle.
GetWindowRect(WebViewId, GenericSender<DeviceIndependentIntRect>),
/// Get the device independent screen size and available size.
GetScreenMetrics(WebViewId, GenericSender<ScreenMetrics>),
/// Entered or exited fullscreen.
NotifyFullscreenStateChanged(WebViewId, bool),
/// The [`LoadStatus`] of the Given `WebView` has changed.
NotifyLoadStatusChanged(WebViewId, LoadStatus),
WebResourceRequested(
Option<WebViewId>,
WebResourceRequest,
GenericSender<WebResourceResponseMsg>,
),
/// A pipeline panicked. First string is the reason, second one is the backtrace.
Panic(WebViewId, String, Option<String>),
/// Open dialog to select bluetooth device.
GetSelectedBluetoothDevice(WebViewId, Vec<String>, GenericSender<Option<String>>),
/// Open file dialog to select files. Set boolean flag to true allows to select multiple files.
SelectFiles(
WebViewId,
Vec<FilterPattern>,
bool,
GenericSender<Option<Vec<PathBuf>>>,
),
/// Open interface to request permission specified by prompt.
PromptPermission(WebViewId, PermissionFeature, GenericSender<AllowOrDeny>),
/// Request to present an IME to the user when an editable element is focused.
/// If the input is text, the second parameter defines the pre-existing string
/// text content and the zero-based index into the string locating the insertion point.
/// bool is true for multi-line and false otherwise.
ShowIME(
WebViewId,
InputMethodType,
Option<(String, i32)>,
bool,
DeviceIntRect,
),
/// Request to hide the IME when the editable element is blurred.
HideIME(WebViewId),
/// Report a complete sampled profile
ReportProfile(Vec<u8>),
/// Notifies the embedder about media session events
/// (i.e. when there is metadata for the active media session, playback state changes...).
MediaSessionEvent(WebViewId, MediaSessionEvent),
/// Report the status of Devtools Server with a token that can be used to bypass the permission prompt.
OnDevtoolsStarted(Result<u16, ()>, String),
/// Ask the user to allow a devtools client to connect.
RequestDevtoolsConnection(GenericSender<AllowOrDeny>),
/// Request to play a haptic effect on a connected gamepad.
PlayGamepadHapticEffect(WebViewId, usize, GamepadHapticEffectType, IpcSender<bool>),
/// Request to stop a haptic effect on a connected gamepad.
StopGamepadHapticEffect(WebViewId, usize, IpcSender<bool>),
/// Informs the embedder that the constellation has completed shutdown.
/// Required because the constellation can have pending calls to make
/// (e.g. SetFrameTree) at the time that we send it an ExitMsg.
ShutdownComplete,
/// Request to display a notification.
ShowNotification(Option<WebViewId>, Notification),
/// Request to display a form control to the embedder.
ShowFormControl(WebViewId, DeviceIntRect, FormControl),
/// Inform the embedding layer that a JavaScript evaluation has
/// finished with the given result.
FinishJavaScriptEvaluation(
JavaScriptEvaluationId,
Result<JSValue, JavaScriptEvaluationError>,
),
}
impl Debug for EmbedderMsg {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
let string: &'static str = self.into();
write!(formatter, "{string}")
}
}
#[derive(Deserialize, Serialize)]
pub enum FormControl {
/// Indicates that the user has activated a `<select>` element.
SelectElement(
Vec<SelectElementOptionOrOptgroup>,
Option<usize>,
GenericSender<Option<usize>>,
),
/// Indicates that the user has activated a `<input type=color>` element.
ColorPicker(RgbColor, GenericSender<Option<RgbColor>>),
}
/// Filter for file selection;
/// the `String` content is expected to be extension (e.g, "doc", without the prefixing ".")
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct FilterPattern(pub String);
/// <https://w3c.github.io/mediasession/#mediametadata>
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MediaMetadata {
/// Title
pub title: String,
/// Artist
pub artist: String,
/// Album
pub album: String,
}
impl MediaMetadata {
pub fn new(title: String) -> Self {
Self {
title,
artist: "".to_owned(),
album: "".to_owned(),
}
}
}
/// <https://w3c.github.io/mediasession/#enumdef-mediasessionplaybackstate>
#[repr(i32)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum MediaSessionPlaybackState {
/// The browsing context does not specify whether it’s playing or paused.
None_ = 1,
/// The browsing context is currently playing media and it can be paused.
Playing,
/// The browsing context has paused media and it can be resumed.
Paused,
}
/// <https://w3c.github.io/mediasession/#dictdef-mediapositionstate>
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MediaPositionState {
pub duration: f64,
pub playback_rate: f64,
pub position: f64,
}
impl MediaPositionState {
pub fn new(duration: f64, playback_rate: f64, position: f64) -> Self {
Self {
duration,
playback_rate,
position,
}
}
}
/// Type of events sent from script to the embedder about the media session.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum MediaSessionEvent {
/// Indicates that the media metadata is available.
SetMetadata(MediaMetadata),
/// Indicates that the playback state has changed.
PlaybackStateChange(MediaSessionPlaybackState),
/// Indicates that the position state is set.
SetPositionState(MediaPositionState),
}
/// Enum with variants that match the DOM PermissionName enum
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum PermissionFeature {
Geolocation,
Notifications,
Push,
Midi,
Camera,
Microphone,
Speaker,
DeviceInfo,
BackgroundSync,
Bluetooth,
PersistentStorage,
}
/// Used to specify the kind of input method editor appropriate to edit a field.
/// This is a subset of htmlinputelement::InputType because some variants of InputType
/// don't make sense in this context.
#[derive(Debug, Deserialize, Serialize)]
pub enum InputMethodType {
Color,
Date,
DatetimeLocal,
Email,
Month,
Number,
Password,
Search,
Tel,
Text,
Time,
Url,
Week,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype-dual-rumble>
pub struct DualRumbleEffectParams {
pub duration: f64,
pub start_delay: f64,
pub strong_magnitude: f64,
pub weak_magnitude: f64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
/// <https://w3.org/TR/gamepad/#dom-gamepadhapticeffecttype>
pub enum GamepadHapticEffectType {
DualRumble(DualRumbleEffectParams),
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct WebResourceRequest {
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub method: Method,
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub headers: HeaderMap,
pub url: Url,
pub is_for_main_frame: bool,
pub is_redirect: bool,
}
#[derive(Clone, Deserialize, Serialize)]
pub enum WebResourceResponseMsg {
/// Start an interception of this web resource load. It's expected that the client subsequently
/// send either a `CancelLoad` or `FinishLoad` message after optionally sending chunks of body
/// data via `SendBodyData`.
Start(WebResourceResponse),
/// Send a chunk of body data.
SendBodyData(Vec<u8>),
/// Signal that this load has been finished by the interceptor.
FinishLoad,
/// Signal that this load has been cancelled by the interceptor.
CancelLoad,
/// Signal that this load will not be intercepted.
DoNotIntercept,
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct WebResourceResponse {
pub url: Url,
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub headers: HeaderMap,
#[serde(
deserialize_with = "::hyper_serde::deserialize",
serialize_with = "::hyper_serde::serialize"
)]
#[ignore_malloc_size_of = "Defined in hyper"]
pub status_code: StatusCode,
pub status_message: Vec<u8>,
}
impl WebResourceResponse {
pub fn new(url: Url) -> WebResourceResponse {
WebResourceResponse {
url,
headers: HeaderMap::new(),
status_code: StatusCode::OK,
status_message: b"OK".to_vec(),
}
}
pub fn headers(mut self, headers: HeaderMap) -> WebResourceResponse {
self.headers = headers;
self
}
pub fn status_code(mut self, status_code: StatusCode) -> WebResourceResponse {
self.status_code = status_code;
self
}
pub fn status_message(mut self, status_message: Vec<u8>) -> WebResourceResponse {
self.status_message = status_message;
self
}
}
/// The type of platform theme.
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum Theme {
/// Light theme.
Light,
/// Dark theme.
Dark,
}
impl From<Theme> for PrefersColorScheme {
fn from(value: Theme) -> Self {
match value {
Theme::Light => PrefersColorScheme::Light,
Theme::Dark => PrefersColorScheme::Dark,
}
}
}
// The type of MediaSession action.
/// <https://w3c.github.io/mediasession/#enumdef-mediasessionaction>
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum MediaSessionActionType {
/// The action intent is to resume playback.
Play,
/// The action intent is to pause the currently active playback.
Pause,
/// The action intent is to move the playback time backward by a short period (i.e. a few
/// seconds).
SeekBackward,
/// The action intent is to move the playback time forward by a short period (i.e. a few
/// seconds).
SeekForward,
/// The action intent is to either start the current playback from the beginning if the
/// playback has a notion, of beginning, or move to the previous item in the playlist if the
/// playback has a notion of playlist.
PreviousTrack,
/// The action is to move to the playback to the next item in the playlist if the playback has
/// a notion of playlist.
NextTrack,
/// The action intent is to skip the advertisement that is currently playing.
SkipAd,
/// The action intent is to stop the playback and clear the state if appropriate.
Stop,
/// The action intent is to move the playback time to a specific time.
SeekTo,
}
/// The status of the load in this `WebView`.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum LoadStatus {
/// The load has started, but the headers have not yet been parsed.
Started,
/// The `<head>` tag has been parsed in the currently loading page. At this point the page's
/// `HTMLBodyElement` is now available in the DOM.
HeadParsed,
/// The `Document` and all subresources have loaded. This is equivalent to
/// `document.readyState` == `complete`.
/// See <https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState>
Complete,
}
/// Data that could be used to display a desktop notification to the end user
/// when the [Notification API](<https://notifications.spec.whatwg.org/#notifications>) is called.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Notification {
/// Title of the notification.
pub title: String,
/// Body string of the notification.
pub body: String,
/// An identifier tag for the notification. Notification with the same tag
/// can be replaced by another to avoid users' screen being filled up with similar notifications.
pub tag: String,
/// 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)
pub language: String,
/// A boolean value indicates the notification should remain readily available
/// until the end user activates or dismisses the notification.
pub require_interaction: bool,
/// When `true`, indicates no sounds or vibrations should be made. When `None`,
/// the device's default settings should be respected.
pub silent: Option<bool>,
/// The URL of an icon. The icon will be displayed as part of the notification.
pub icon_url: Option<ServoUrl>,
/// Icon's raw image data and metadata.
pub icon_resource: Option<Arc<RasterImage>>,
/// The URL of a badge. The badge is used when there is no enough space to display the notification,
/// such as on a mobile device's notification bar.
pub badge_url: Option<ServoUrl>,
/// Badge's raw image data and metadata.
pub badge_resource: Option<Arc<RasterImage>>,
/// The URL of an image. The image will be displayed as part of the notification.
pub image_url: Option<ServoUrl>,
/// Image's raw image data and metadata.
pub image_resource: Option<Arc<RasterImage>>,
/// Actions available for users to choose from for interacting with the notification.
pub actions: Vec<NotificationAction>,
}
/// Actions available for users to choose from for interacting with the notification.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NotificationAction {
/// A string that identifies the action.
pub name: String,
/// The title string of the action to be shown to the user.
pub title: String,
/// The URL of an icon. The icon will be displayed with the action.
pub icon_url: Option<ServoUrl>,
/// Icon's raw image data and metadata.
pub icon_resource: Option<Arc<RasterImage>>,
}
/// Information about a `WebView`'s screen geometry and offset. This is used
/// for the [Screen](https://drafts.csswg.org/cssom-view/#the-screen-interface) CSSOM APIs
/// and `window.screenLeft` / `window.screenX` / `window.screenTop` / `window.screenY` /
/// `window.moveBy`/ `window.resizeBy` / `window.outerWidth` / `window.outerHeight` /
/// `window.screen.availHeight` / `window.screen.availWidth`.
#[derive(Clone, Copy, Debug, Default)]
pub struct ScreenGeometry {
/// The size of the screen in device pixels. This will be converted to
/// CSS pixels based on the pixel scaling of the `WebView`.
pub size: DeviceIntSize,
/// The available size of the screen in device pixels for the purposes of
/// the `window.screen.availHeight` / `window.screen.availWidth`. This is the size
/// available for web content on the screen, and should be `size` minus any system
/// toolbars, docks, and interface elements. This will be converted to
/// CSS pixels based on the pixel scaling of the `WebView`.
pub available_size: DeviceIntSize,
/// The rectangle the `WebView`'s containing window (including OS decorations)
/// in device pixels for the purposes of the
/// `window.screenLeft`, `window.outerHeight` and similar APIs.
/// This will be converted to CSS pixels based on the pixel scaling of the `WebView`.
pub window_rect: DeviceIntRect,
}
impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
fn from(value: SelectElementOption) -> Self {
Self::Option(value)
}
}
/// The address of a node. Layout sends these back. They must be validated via
/// `from_untrusted_node_address` before they can be used, because we do not trust layout.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UntrustedNodeAddress(pub *const c_void);
malloc_size_of_is_0!(UntrustedNodeAddress);
#[allow(unsafe_code)]
unsafe impl Send for UntrustedNodeAddress {}
impl From<style_traits::dom::OpaqueNode> for UntrustedNodeAddress {
fn from(o: style_traits::dom::OpaqueNode) -> Self {
UntrustedNodeAddress(o.0 as *const c_void)
}
}
impl Serialize for UntrustedNodeAddress {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
(self.0 as usize).serialize(s)
}
}
impl<'de> Deserialize<'de> for UntrustedNodeAddress {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<UntrustedNodeAddress, D::Error> {
let value: usize = Deserialize::deserialize(d)?;
Ok(UntrustedNodeAddress::from_id(value))
}
}
impl UntrustedNodeAddress {
/// Creates an `UntrustedNodeAddress` from the given pointer address value.
#[inline]
pub fn from_id(id: usize) -> UntrustedNodeAddress {
UntrustedNodeAddress(id as *const c_void)
}
}
/// The result of a hit test in the compositor.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CompositorHitTestResult {
/// The pipeline id of the resulting item.
pub pipeline_id: PipelineId,
/// The hit test point in the item's viewport.
pub point_in_viewport: Point2D<f32, CSSPixel>,
/// The [`ExternalScrollId`] of the scroll tree node associated with this hit test item.
pub external_scroll_id: ExternalScrollId,
}
/// Whether the default action for a touch event was prevented by web content
#[derive(Debug, Deserialize, Serialize)]
pub enum TouchEventResult {
/// Allowed by web content
DefaultAllowed(TouchSequenceId, TouchEventType),
/// Prevented by web content
DefaultPrevented(TouchSequenceId, TouchEventType),
}
/// For a given pipeline, whether any animations are currently running
/// and any animation callbacks are queued
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum AnimationState {
/// Animations are active but no callbacks are queued
AnimationsPresent,
/// Animations are active and callbacks are queued
AnimationCallbacksPresent,
/// No animations are active and no callbacks are queued
NoAnimationsPresent,
/// No animations are active but callbacks are queued
NoAnimationCallbacksPresent,
}
/// A sequence number generated by a script thread for its pipelines. The
/// constellation attaches the target pipeline's last seen `FocusSequenceNumber`
/// to every focus-related message it sends.
///
/// This is used to resolve the inconsistency that occurs due to bidirectional
/// focus state synchronization and provide eventual consistency. Example:
///
/// ```text
/// script constellation
/// -----------------------------------------------------------------------
/// send ActivateDocument ----------> receive ActivateDocument
/// ,---- send FocusDocument
/// |
/// focus an iframe |
/// send Focus -----------------|---> receive Focus
/// | focus the iframe's content document
/// receive FocusDocument <-----' send FocusDocument to the content pipeline --> ...
/// unfocus the iframe
/// focus the document
///
/// Final state: Final state:
/// the iframe is not focused the iframe is focused
/// ```
///
/// When the above sequence completes, from the script thread's point of view,
/// the iframe is unfocused, but from the constellation's point of view, the
/// iframe is still focused.
///
/// This inconsistency can be resolved by associating a sequence number to each
/// message. Whenever a script thread initiates a focus operation, it generates
/// and sends a brand new sequence number. The constellation attaches the
/// last-received sequence number to each message it sends. This way, the script
/// thread can discard out-dated incoming focus messages, and eventually, all
/// actors converge to the consistent state which is determined based on the
/// last focus message received by the constellation.
///
/// ```text
/// script constellation
/// -----------------------------------------------------------------------
/// send ActivateDocument ----------> receive ActivateDocument
/// ,---- send FocusDocument (0)
/// |
/// seq_number += 1 |
/// focus an iframe |
/// send Focus (1) -------------|---> receive Focus (1)
/// | focus the iframe's content document
/// receive FocusDocument (0) <-' send FocusDocument to the content pipeline --> ...
/// ignore it because 0 < 1
///
/// Final state: Final state:
/// the iframe is focused the iframe is focused
/// ```
#[derive(
Clone,
Copy,
Debug,
Default,
Deserialize,
Eq,
Hash,
MallocSizeOf,
PartialEq,
Serialize,
PartialOrd,
)]
pub struct FocusSequenceNumber(pub u64);
impl Display for FocusSequenceNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
Display::fmt(&self.0, f)
}
}
/// An identifier for a particular JavaScript evaluation that is used to track the
/// evaluation from the embedding layer to the script layer and then back.
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct JavaScriptEvaluationId(pub usize);
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum JSValue {
Undefined,
Null,
Boolean(bool),
Number(f64),
String(String),
Element(String),
ShadowRoot(String),
Frame(String),
Window(String),
Array(Vec<JSValue>),
Object(HashMap<String, JSValue>),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum JavaScriptEvaluationError {
/// The script could not be compiled
CompilationFailure,
/// The script could not be evaluated
EvaluationFailure,
/// An internal Servo error prevented the JavaSript evaluation from completing properly.
/// This indicates a bug in Servo.
InternalError,
/// The `WebView` on which this evaluation request was triggered is not ready. This might
/// happen if the `WebView`'s `Document` is changing due to ongoing load events, for instance.
WebViewNotReady,
/// The script executed successfully, but Servo could not serialize the JavaScript return
/// value into a [`JSValue`].
SerializationError,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct RgbColor {
pub red: u8,
pub green: u8,
pub blue: u8,
}
/// A Script to Embedder Channel
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct ScriptToEmbedderChan(GenericCallback<EmbedderMsg>);
impl ScriptToEmbedderChan {
/// Create a new Channel allowing script to send messages to the Embedder
pub fn new(
embedder_chan: Sender<EmbedderMsg>,
waker: Box<dyn EventLoopWaker>,
) -> ScriptToEmbedderChan {
let embedder_callback = GenericCallback::new(move |embedder_msg| {
let msg = match embedder_msg {
Ok(embedder_msg) => embedder_msg,
Err(err) => {
log::warn!("Script to Embedder message error: {err}");
return;
},
};
let _ = embedder_chan.send(msg);
waker.wake();
})
.expect("Failed to create channel");
ScriptToEmbedderChan(embedder_callback)
}
/// Send a message to and wake the Embedder
pub fn send(&self, msg: EmbedderMsg) -> SendResult {
self.0.send(msg)
}
}