#![crate_name = "devtools_traits"]
#![crate_type = "rlib"]
#![deny(unsafe_code)]
use core::fmt;
use std::collections::HashMap;
use std::fmt::Display;
use std::net::TcpStream;
use std::str::FromStr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub use embedder_traits::ConsoleLogLevel;
use embedder_traits::Theme;
use http::{HeaderMap, Method};
use malloc_size_of_derive::MallocSizeOf;
use net_traits::http_status::HttpStatus;
use net_traits::request::Destination;
use net_traits::{DebugVec, TlsSecurityInfo};
use profile_traits::mem::ReportsChan;
use serde::{Deserialize, Serialize};
use servo_base::cross_process_instant::CrossProcessInstant;
use servo_base::generic_channel::GenericSender;
use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
use servo_url::ServoUrl;
use uuid::Uuid;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DevtoolsPageInfo {
pub title: String,
pub url: ServoUrl,
pub is_top_level_global: bool,
pub is_service_worker: bool,
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct CSSError {
pub filename: String,
pub line: u32,
pub column: u32,
pub msg: String,
}
#[derive(Debug)]
pub enum DevtoolsControlMsg {
FromChrome(ChromeToDevtoolsControlMsg),
FromScript(ScriptToDevtoolsControlMsg),
ClientExited,
}
#[expect(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum ChromeToDevtoolsControlMsg {
AddClient(TcpStream),
ServerExitMsg,
NetworkEvent(String, NetworkEvent),
CollectMemoryReport(ReportsChan),
}
#[derive(Debug, Deserialize, Serialize)]
pub enum NavigationState {
Start(ServoUrl),
Stop(PipelineId, DevtoolsPageInfo),
}
#[derive(Debug, Deserialize, Serialize)]
pub enum ScriptToDevtoolsControlMsg {
NewGlobal(
(BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
GenericSender<DevtoolScriptControlMsg>,
DevtoolsPageInfo,
),
Navigate(BrowsingContextId, NavigationState),
ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
ClearConsole(PipelineId, Option<WorkerId>),
FramerateTick(String, f64),
ReportCSSError(PipelineId, CSSError),
ReportPageError(PipelineId, PageError),
TitleChanged(PipelineId, String),
CreateSourceActor(
GenericSender<DevtoolScriptControlMsg>,
PipelineId,
SourceInfo,
),
UpdateSourceContent(PipelineId, String),
DomMutation(PipelineId, DomMutation),
DebuggerPause(PipelineId, FrameOffset, PauseReason),
CreateFrameActor(GenericSender<String>, PipelineId, FrameInfo),
CreateEnvironmentActor(GenericSender<String>, EnvironmentInfo, Option<String>),
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub enum DomMutation {
AttributeModified {
node: String,
attribute_name: String,
new_value: Option<String>,
},
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct ObjectPreview {
pub kind: String,
pub own_properties: Option<Vec<PropertyDescriptor>>,
pub own_properties_length: Option<u32>,
pub function: Option<FunctionPreview>,
pub array_length: Option<u32>,
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct FunctionPreview {
pub name: Option<String>,
pub display_name: Option<String>,
pub parameter_names: Vec<String>,
pub is_async: bool,
pub is_generator: bool,
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub enum DebuggerValue {
VoidValue,
NullValue,
BooleanValue(bool),
NumberValue(f64),
StringValue(String),
ObjectValue {
uuid: String,
class: String,
preview: Option<ObjectPreview>,
},
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct PropertyDescriptor {
pub name: String,
pub value: DebuggerValue,
pub configurable: bool,
pub enumerable: bool,
pub writable: bool,
pub is_accessor: bool,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct EvaluateJSReply {
pub value: DebuggerValue,
pub has_exception: bool,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct AttrInfo {
pub namespace: String,
pub name: String,
pub value: String,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeInfo {
pub unique_id: String,
pub host: Option<String>,
#[serde(rename = "baseURI")]
pub base_uri: String,
pub parent: String,
pub node_type: u16,
pub node_name: String,
pub node_value: Option<String>,
pub num_children: usize,
pub attrs: Vec<AttrInfo>,
pub is_top_level_document: bool,
pub shadow_root_mode: Option<ShadowRootMode>,
pub is_shadow_host: bool,
pub display: Option<String>,
pub is_displayed: bool,
pub doctype_name: Option<String>,
pub doctype_public_identifier: Option<String>,
pub doctype_system_identifier: Option<String>,
pub has_event_listeners: bool,
}
pub struct StartedTimelineMarker {
name: String,
start_time: CrossProcessInstant,
start_stack: Option<Vec<()>>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct TimelineMarker {
pub name: String,
pub start_time: CrossProcessInstant,
pub start_stack: Option<Vec<()>>,
pub end_time: CrossProcessInstant,
pub end_stack: Option<Vec<()>>,
}
#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum TimelineMarkerType {
Reflow,
DOMEvent,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NodeStyle {
pub name: String,
pub value: String,
pub priority: String,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct ComputedNodeLayout {
pub display: String,
pub position: String,
pub z_index: String,
pub box_sizing: String,
pub margin_top: String,
pub margin_right: String,
pub margin_bottom: String,
pub margin_left: String,
pub border_top_width: String,
pub border_right_width: String,
pub border_bottom_width: String,
pub border_left_width: String,
pub padding_top: String,
pub padding_right: String,
pub padding_bottom: String,
pub padding_left: String,
pub width: f32,
pub height: f32,
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct AutoMargins {
pub top: bool,
pub right: bool,
pub bottom: bool,
pub left: bool,
}
#[derive(Debug, Deserialize, Serialize)]
pub enum DevtoolScriptControlMsg {
GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
GetStylesheetStyle(
PipelineId,
String,
String,
usize,
GenericSender<Option<Vec<NodeStyle>>>,
),
GetSelectors(
PipelineId,
String,
GenericSender<Option<Vec<(String, usize)>>>,
),
GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
GetLayout(
PipelineId,
String,
GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
),
GetXPath(PipelineId, String, GenericSender<String>),
ModifyAttribute(PipelineId, String, Vec<AttrModification>),
ModifyRule(PipelineId, String, Vec<RuleModification>),
WantsLiveNotifications(PipelineId, bool),
SetTimelineMarkers(
PipelineId,
Vec<TimelineMarkerType>,
GenericSender<Option<TimelineMarker>>,
),
DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
RequestAnimationFrame(PipelineId, String),
NavigateTo(PipelineId, ServoUrl),
GoBack(PipelineId),
GoForward(PipelineId),
Reload(PipelineId),
GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
SimulateColorScheme(PipelineId, Theme),
HighlightDomNode(PipelineId, Option<String>),
Eval(
String,
PipelineId,
Option<String>,
GenericSender<EvaluateJSReply>,
),
GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
SetBreakpoint(u32, u32, u32),
ClearBreakpoint(u32, u32, u32),
Interrupt,
Resume(Option<String>, Option<String>),
ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
GetEnvironment(String, GenericSender<String>),
}
#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
#[serde(rename_all = "camelCase")]
pub struct AttrModification {
pub attribute_name: String,
pub new_value: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RuleModification {
#[serde(rename = "type")]
pub type_: String,
pub index: u32,
pub name: String,
pub value: String,
pub priority: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
#[serde(rename_all = "camelCase")]
pub struct StackFrame {
pub filename: String,
pub function_name: String,
pub column_number: u32,
pub line_number: u32,
}
pub fn get_time_stamp() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}
#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
#[serde(rename_all = "camelCase")]
pub struct ConsoleMessageFields {
pub level: ConsoleLogLevel,
pub filename: String,
pub line_number: u32,
pub column_number: u32,
pub time_stamp: u64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum ConsoleArgument {
String(String),
Integer(i32),
Number(f64),
Boolean(bool),
Object(ConsoleArgumentObject),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ConsoleArgumentObject {
pub class: String,
pub own_properties: Vec<ConsoleArgumentPropertyValue>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ConsoleArgumentPropertyValue {
pub key: String,
pub configurable: bool,
pub enumerable: bool,
pub writable: bool,
pub value: ConsoleArgument,
}
impl From<String> for ConsoleArgument {
fn from(value: String) -> Self {
Self::String(value)
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ConsoleMessage {
pub fields: ConsoleMessageFields,
pub arguments: Vec<ConsoleArgument>,
pub stacktrace: Option<Vec<StackFrame>>,
}
#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
#[serde(rename_all = "camelCase")]
pub struct PageError {
pub error_message: String,
pub source_name: String,
pub line_number: u32,
pub column_number: u32,
pub time_stamp: u64,
}
#[derive(Debug, PartialEq, MallocSizeOf)]
pub struct HttpRequest {
pub url: ServoUrl,
#[ignore_malloc_size_of = "http type"]
pub method: Method,
#[ignore_malloc_size_of = "http type"]
pub headers: HeaderMap,
pub body: Option<DebugVec>,
pub pipeline_id: PipelineId,
pub started_date_time: SystemTime,
pub time_stamp: i64,
pub connect_time: Duration,
pub send_time: Duration,
pub destination: Destination,
pub is_xhr: bool,
pub browsing_context_id: BrowsingContextId,
}
#[derive(Debug, PartialEq, MallocSizeOf)]
pub struct HttpResponse {
#[ignore_malloc_size_of = "Http type"]
pub headers: Option<HeaderMap>,
pub status: HttpStatus,
pub body: Option<DebugVec>,
pub from_cache: bool,
pub pipeline_id: PipelineId,
pub browsing_context_id: BrowsingContextId,
}
#[derive(Debug, PartialEq)]
pub struct SecurityInfoUpdate {
pub browsing_context_id: BrowsingContextId,
pub security_info: Option<TlsSecurityInfo>,
}
#[derive(Debug)]
pub enum NetworkEvent {
HttpRequest(HttpRequest),
HttpRequestUpdate(HttpRequest),
HttpResponse(HttpResponse),
SecurityInfo(SecurityInfoUpdate),
}
impl NetworkEvent {
pub fn forward_to_devtools(&self) -> bool {
match self {
NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
NetworkEvent::HttpRequestUpdate(_) => true,
NetworkEvent::HttpResponse(_) => true,
NetworkEvent::SecurityInfo(_) => true,
}
}
}
impl TimelineMarker {
pub fn start(name: String) -> StartedTimelineMarker {
StartedTimelineMarker {
name,
start_time: CrossProcessInstant::now(),
start_stack: None,
}
}
}
impl StartedTimelineMarker {
pub fn end(self) -> TimelineMarker {
TimelineMarker {
name: self.name,
start_time: self.start_time,
start_stack: self.start_stack,
end_time: CrossProcessInstant::now(),
end_stack: None,
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub struct WorkerId(pub Uuid);
impl Display for WorkerId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl FromStr for WorkerId {
type Err = uuid::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.parse()?))
}
}
#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
#[serde(rename_all = "camelCase")]
pub struct CssDatabaseProperty {
pub is_inherited: bool,
pub values: Vec<String>,
pub supports: Vec<String>,
pub subproperties: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize)]
pub enum ShadowRootMode {
Open,
Closed,
}
impl fmt::Display for ShadowRootMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Open => write!(f, "open"),
Self::Closed => write!(f, "close"),
}
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct SourceInfo {
pub url: ServoUrl,
pub introduction_type: String,
pub inline: bool,
pub worker_id: Option<WorkerId>,
pub content: Option<String>,
pub content_type: Option<String>,
pub spidermonkey_id: u32,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RecommendedBreakpointLocation {
pub script_id: u32,
pub offset: u32,
pub line_number: u32,
pub column_number: u32,
pub is_step_start: bool,
}
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct FrameInfo {
pub display_name: String,
pub on_stack: bool,
pub oldest: bool,
pub terminated: bool,
pub type_: String,
pub url: String,
}
#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
pub struct EnvironmentInfo {
pub type_: Option<String>,
pub scope_kind: Option<String>,
pub function_display_name: Option<String>,
pub binding_variables: HashMap<String, String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct EventListenerInfo {
pub event_type: String,
pub capturing: bool,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PauseReason {
#[serde(rename = "type")]
pub type_: String,
pub on_next: Option<bool>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct FrameOffset {
pub actor: String,
pub column: u32,
pub line: u32,
}