pub mod embedder_controls;
pub mod input_events;
pub mod resources;
pub mod user_contents;
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::sync::Arc;
use accesskit::TreeUpdate;
use crossbeam_channel::Sender;
use euclid::{Box2D, Point2D, Scale, Size2D, Vector2D};
use http::{HeaderMap, Method, StatusCode};
use log::warn;
use malloc_size_of::malloc_size_of_is_0;
use malloc_size_of_derive::MallocSizeOf;
use pixels::SharedRasterImage;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_base::generic_channel::{
GenericCallback, GenericSender, GenericSharedMemory, SendResult,
};
use servo_base::id::{PipelineId, WebViewId};
use servo_geometry::{DeviceIndependentIntRect, DeviceIndependentIntSize};
use servo_url::ServoUrl;
use strum::{EnumMessage, 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, DevicePoint, DeviceRect,
DeviceVector2D, LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D,
};
pub use crate::embedder_controls::*;
pub use crate::input_events::*;
use crate::user_contents::UserContentManagerId;
pub use crate::webdriver::*;
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub enum WebViewPoint {
Device(DevicePoint),
Page(Point2D<f32, CSSPixel>),
}
impl WebViewPoint {
pub fn as_device_point(&self, scale: Scale<f32, CSSPixel, DevicePixel>) -> DevicePoint {
match self {
Self::Device(point) => *point,
Self::Page(point) => *point * scale,
}
}
}
impl From<DevicePoint> for WebViewPoint {
fn from(point: DevicePoint) -> Self {
Self::Device(point)
}
}
impl From<LayoutPoint> for WebViewPoint {
fn from(point: LayoutPoint) -> Self {
Self::Page(Point2D::new(point.x, point.y))
}
}
impl From<Point2D<f32, CSSPixel>> for WebViewPoint {
fn from(point: Point2D<f32, CSSPixel>) -> Self {
Self::Page(point)
}
}
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub enum WebViewRect {
Device(DeviceRect),
Page(Box2D<f32, CSSPixel>),
}
impl WebViewRect {
pub fn as_device_rect(&self, scale: Scale<f32, CSSPixel, DevicePixel>) -> DeviceRect {
match self {
Self::Device(rect) => *rect,
Self::Page(rect) => *rect * scale,
}
}
}
impl From<DeviceRect> for WebViewRect {
fn from(rect: DeviceRect) -> Self {
Self::Device(rect)
}
}
impl From<LayoutRect> for WebViewRect {
fn from(rect: LayoutRect) -> Self {
Self::Page(Box2D::new(
Point2D::new(rect.min.x, rect.min.y),
Point2D::new(rect.max.x, rect.max.y),
))
}
}
impl From<Box2D<f32, CSSPixel>> for WebViewRect {
fn from(rect: Box2D<f32, CSSPixel>) -> Self {
Self::Page(rect)
}
}
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub enum WebViewVector {
Device(DeviceVector2D),
Page(Vector2D<f32, CSSPixel>),
}
impl WebViewVector {
pub fn as_device_vector(&self, scale: Scale<f32, CSSPixel, DevicePixel>) -> DeviceVector2D {
match self {
Self::Device(vector) => *vector,
Self::Page(vector) => *vector * scale,
}
}
}
impl From<DeviceVector2D> for WebViewVector {
fn from(vector: DeviceVector2D) -> Self {
Self::Device(vector)
}
}
impl From<LayoutVector2D> for WebViewVector {
fn from(vector: LayoutVector2D) -> Self {
Self::Page(Vector2D::new(vector.x, vector.y))
}
}
impl From<Vector2D<f32, CSSPixel>> for WebViewVector {
fn from(vector: Vector2D<f32, CSSPixel>) -> Self {
Self::Page(vector)
}
}
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub enum Scroll {
Delta(WebViewVector),
Start,
End,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ShutdownState {
NotShuttingDown,
ShuttingDown,
FinishedShuttingDown,
}
#[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 + Sync {
fn clone_box(&self) -> Box<dyn EventLoopWaker>;
fn wake(&self);
}
impl Clone for Box<dyn EventLoopWaker> {
fn clone(&self) -> Self {
self.clone_box()
}
}
pub struct GenericEmbedderProxy<T> {
pub sender: Sender<T>,
pub event_loop_waker: Box<dyn EventLoopWaker>,
}
impl<T> GenericEmbedderProxy<T> {
pub fn send(&self, message: T) {
if let Err(err) = self.sender.send(message) {
warn!("Failed to send response ({:?}).", err);
}
self.event_loop_waker.wake();
}
}
impl<T> Clone for GenericEmbedderProxy<T> {
fn clone(&self) -> Self {
Self {
sender: self.sender.clone(),
event_loop_waker: self.event_loop_waker.clone(),
}
}
}
pub type EmbedderProxy = GenericEmbedderProxy<EmbedderMsg>;
pub trait RefreshDriver {
fn observe_next_frame(&self, start_frame_callback: Box<dyn Fn() + Send + 'static>);
}
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct AuthenticationResponse {
pub username: String,
pub password: String,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum AllowOrDeny {
Allow,
Deny,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum RegisterOrUnregister {
Register,
Unregister,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ProtocolHandlerUpdateRegistration {
pub scheme: String,
pub url: ServoUrl,
pub register_or_unregister: RegisterOrUnregister,
}
#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)]
pub struct ViewportDetails {
pub size: Size2D<f32, CSSPixel>,
pub hidpi_scale_factor: Scale<f32, CSSPixel, DevicePixel>,
}
impl ViewportDetails {
pub fn layout_size(&self) -> LayoutSize {
Size2D::from_untyped(self.size.to_untyped())
}
}
#[derive(Default, Deserialize, Serialize)]
pub struct ScreenMetrics {
pub screen_size: DeviceIndependentIntSize,
pub available_size: DeviceIndependentIntSize,
}
#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct TraversalId(String);
impl TraversalId {
#[expect(clippy::new_without_default)]
pub fn new() -> Self {
Self(Uuid::new_v4().to_string())
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, MallocSizeOf)]
pub enum PixelFormat {
K8,
KA8,
RGB8,
RGBA8,
BGRA8,
}
#[derive(Clone, Deserialize, Serialize, MallocSizeOf)]
pub struct Image {
pub width: u32,
pub height: u32,
pub format: PixelFormat,
#[conditional_malloc_size_of]
data: Arc<GenericSharedMemory>,
range: Range<usize>,
}
impl Image {
pub fn new(
width: u32,
height: u32,
data: Arc<GenericSharedMemory>,
range: Range<usize>,
format: PixelFormat,
) -> Self {
Self {
width,
height,
format,
data,
range,
}
}
pub fn data(&self) -> &[u8] {
&self.data[self.range.clone()]
}
}
#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
#[serde(rename_all = "lowercase")]
pub enum ConsoleLogLevel {
Log,
Debug,
Info,
Warn,
Error,
Trace,
}
impl From<ConsoleLogLevel> for log::Level {
fn from(value: ConsoleLogLevel) -> Self {
match value {
ConsoleLogLevel::Log => log::Level::Info,
ConsoleLogLevel::Debug => log::Level::Debug,
ConsoleLogLevel::Info => log::Level::Info,
ConsoleLogLevel::Warn => log::Level::Warn,
ConsoleLogLevel::Error => log::Level::Error,
ConsoleLogLevel::Trace => log::Level::Trace,
}
}
}
#[derive(Clone, Deserialize, Serialize)]
pub struct BluetoothDeviceDescription {
pub address: String,
pub name: String,
}
#[derive(Deserialize, IntoStaticStr, Serialize)]
pub enum EmbedderMsg {
Status(WebViewId, Option<String>),
ChangePageTitle(WebViewId, Option<String>),
MoveTo(WebViewId, DeviceIntPoint),
ResizeTo(WebViewId, DeviceIntSize),
ShowSimpleDialog(WebViewId, SimpleDialogRequest),
AllowProtocolHandlerRequest(
WebViewId,
ProtocolHandlerUpdateRegistration,
GenericSender<AllowOrDeny>,
),
AllowUnload(WebViewId, GenericSender<AllowOrDeny>),
ClearClipboard(WebViewId),
GetClipboardText(WebViewId, GenericCallback<Result<String, String>>),
SetClipboardText(WebViewId, String),
SetCursor(WebViewId, Cursor),
NewFavicon(WebViewId, Image),
GetWindowRect(WebViewId, GenericSender<DeviceIndependentIntRect>),
GetScreenMetrics(WebViewId, GenericSender<ScreenMetrics>),
NotifyFullscreenStateChanged(WebViewId, bool),
NotifyLoadStatusChanged(WebViewId, LoadStatus),
GetSelectedBluetoothDevice(
WebViewId,
Vec<BluetoothDeviceDescription>,
GenericSender<Option<String>>,
),
PromptPermission(WebViewId, PermissionFeature, GenericSender<AllowOrDeny>),
OnDevtoolsStarted(Result<u16, ()>, String),
RequestDevtoolsConnection(GenericSender<AllowOrDeny>),
#[cfg(feature = "gamepad")]
PlayGamepadHapticEffect(
WebViewId,
usize,
GamepadHapticEffectType,
GenericCallback<bool>,
),
#[cfg(feature = "gamepad")]
StopGamepadHapticEffect(WebViewId, usize, GenericCallback<bool>),
ShowNotification(Option<WebViewId>, Notification),
ShowConsoleApiMessage(Option<WebViewId>, ConsoleLogLevel, String),
ShowEmbedderControl(EmbedderControlId, DeviceIntRect, EmbedderControlRequest),
HideEmbedderControl(EmbedderControlId),
InputEventsHandled(WebViewId, Vec<InputEventOutcome>),
AccessibilityTreeUpdate(WebViewId, TreeUpdate),
}
impl Debug for EmbedderMsg {
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
let string: &'static str = self.into();
write!(formatter, "{string}")
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MediaMetadata {
pub title: String,
pub artist: String,
pub album: String,
}
impl MediaMetadata {
pub fn new(title: String) -> Self {
Self {
title,
artist: "".to_owned(),
album: "".to_owned(),
}
}
}
#[repr(i32)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum MediaSessionPlaybackState {
None_ = 1,
Playing,
Paused,
}
#[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,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum MediaSessionEvent {
SetMetadata(MediaMetadata),
PlaybackStateChange(MediaSessionPlaybackState),
SetPositionState(MediaPositionState),
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum PermissionFeature {
Geolocation,
Notifications,
Push,
Midi,
Camera,
Microphone,
Speaker,
DeviceInfo,
BackgroundSync,
Bluetooth,
PersistentStorage,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum InputMethodType {
Color,
Date,
DatetimeLocal,
Email,
Month,
Number,
Password,
Search,
Tel,
Text,
Time,
Url,
Week,
}
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DualRumbleEffectParams {
pub duration: f64,
pub start_delay: f64,
pub strong_magnitude: f64,
pub weak_magnitude: f64,
}
#[cfg(feature = "gamepad")]
#[derive(Clone, Debug, Deserialize, Serialize)]
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(WebResourceResponse),
SendBodyData(Vec<u8>),
FinishLoad,
CancelLoad,
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
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
pub enum Theme {
Light,
Dark,
}
impl From<Theme> for PrefersColorScheme {
fn from(value: Theme) -> Self {
match value {
Theme::Light => PrefersColorScheme::Light,
Theme::Dark => PrefersColorScheme::Dark,
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum MediaSessionActionType {
Play,
Pause,
SeekBackward,
SeekForward,
PreviousTrack,
NextTrack,
SkipAd,
Stop,
SeekTo,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum LoadStatus {
Started,
HeadParsed,
Complete,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Notification {
pub title: String,
pub body: String,
pub tag: String,
pub language: String,
pub require_interaction: bool,
pub silent: Option<bool>,
pub icon_url: Option<ServoUrl>,
pub icon_resource: Option<Arc<SharedRasterImage>>,
pub badge_url: Option<ServoUrl>,
pub badge_resource: Option<Arc<SharedRasterImage>>,
pub image_url: Option<ServoUrl>,
pub image_resource: Option<Arc<SharedRasterImage>>,
pub actions: Vec<NotificationAction>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NotificationAction {
pub name: String,
pub title: String,
pub icon_url: Option<ServoUrl>,
pub icon_resource: Option<Arc<SharedRasterImage>>,
}
#[derive(Clone, Copy, Debug, Default)]
pub struct ScreenGeometry {
pub size: DeviceIntSize,
pub available_size: DeviceIntSize,
pub window_rect: DeviceIntRect,
}
impl From<SelectElementOption> for SelectElementOptionOrOptgroup {
fn from(value: SelectElementOption) -> Self {
Self::Option(value)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UntrustedNodeAddress(pub *const c_void);
malloc_size_of_is_0!(UntrustedNodeAddress);
#[expect(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 {
#[inline]
pub fn from_id(id: usize) -> UntrustedNodeAddress {
UntrustedNodeAddress(id as *const c_void)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PaintHitTestResult {
pub pipeline_id: PipelineId,
pub point_in_viewport: Point2D<f32, CSSPixel>,
pub external_scroll_id: ExternalScrollId,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum AnimationState {
AnimationsPresent,
AnimationCallbacksPresent,
NoAnimationsPresent,
NoAnimationCallbacksPresent,
}
#[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)
}
}
#[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 struct JavaScriptErrorInfo {
pub message: String,
pub filename: String,
pub stack: Option<String>,
pub line_number: u64,
pub column: u64,
}
#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
pub enum JavaScriptEvaluationResultSerializationError {
DetachedShadowRoot,
StaleElementReference,
UnknownType,
OtherJavaScriptError,
}
#[derive(Clone, Debug, Deserialize, EnumMessage, PartialEq, Serialize)]
pub enum JavaScriptEvaluationError {
DocumentNotFound,
CompilationFailure,
EvaluationFailure(Option<JavaScriptErrorInfo>),
InternalError,
WebViewNotReady,
SerializationError(JavaScriptEvaluationResultSerializationError),
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub enum ScreenshotCaptureError {
CouldNotReadImage,
WebViewDoesNotExist,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct RgbColor {
pub red: u8,
pub green: u8,
pub blue: u8,
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct ScriptToEmbedderChan(GenericCallback<EmbedderMsg>);
impl ScriptToEmbedderChan {
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)
}
pub fn send(&self, msg: EmbedderMsg) -> SendResult {
self.0.send(msg)
}
}
#[derive(Deserialize, Serialize)]
pub struct NewWebViewDetails {
pub webview_id: WebViewId,
pub viewport_details: ViewportDetails,
pub user_content_manager_id: Option<UserContentManagerId>,
}