1#![crate_name = "devtools_traits"]
16#![crate_type = "rlib"]
17#![deny(unsafe_code)]
18
19use core::fmt;
20use std::collections::HashMap;
21use std::fmt::Display;
22use std::net::TcpStream;
23use std::str::FromStr;
24use std::time::{Duration, SystemTime, UNIX_EPOCH};
25
26pub use embedder_traits::ConsoleLogLevel;
27use embedder_traits::Theme;
28use http::{HeaderMap, Method};
29use malloc_size_of_derive::MallocSizeOf;
30use net_traits::http_status::HttpStatus;
31use net_traits::request::Destination;
32use net_traits::{DebugVec, TlsSecurityInfo};
33use profile_traits::mem::ReportsChan;
34use serde::{Deserialize, Serialize};
35use servo_base::cross_process_instant::CrossProcessInstant;
36use servo_base::generic_channel::GenericSender;
37use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
38use servo_url::ServoUrl;
39use uuid::Uuid;
40
41#[derive(Clone, Debug, Deserialize, Serialize)]
44pub struct DevtoolsPageInfo {
45 pub title: String,
46 pub url: ServoUrl,
47 pub is_top_level_global: bool,
48 pub is_service_worker: bool,
49}
50
51#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
52pub struct CSSError {
53 pub filename: String,
54 pub line: u32,
55 pub column: u32,
56 pub msg: String,
57}
58
59#[derive(Debug)]
62pub enum DevtoolsControlMsg {
63 FromChrome(ChromeToDevtoolsControlMsg),
65 FromScript(ScriptToDevtoolsControlMsg),
67 ClientExited,
69}
70
71#[expect(clippy::large_enum_variant)]
74#[derive(Debug)]
75pub enum ChromeToDevtoolsControlMsg {
76 AddClient(TcpStream),
78 ServerExitMsg,
80 NetworkEvent(String, NetworkEvent),
83 CollectMemoryReport(ReportsChan),
85}
86
87#[derive(Debug, Deserialize, Serialize)]
89pub enum NavigationState {
90 Start(ServoUrl),
92 Stop(PipelineId, DevtoolsPageInfo),
94}
95
96#[derive(Debug, Deserialize, Serialize)]
97pub enum ScriptToDevtoolsControlMsg {
99 NewGlobal(
102 (BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
103 GenericSender<DevtoolScriptControlMsg>,
104 DevtoolsPageInfo,
105 ),
106 Navigate(BrowsingContextId, NavigationState),
108 ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
110 ClearConsole(PipelineId, Option<WorkerId>),
112 FramerateTick(String, f64),
115
116 ReportCSSError(PipelineId, CSSError),
118
119 ReportPageError(PipelineId, PageError),
121
122 TitleChanged(PipelineId, String),
124
125 CreateSourceActor(
127 GenericSender<DevtoolScriptControlMsg>,
128 PipelineId,
129 SourceInfo,
130 ),
131
132 UpdateSourceContent(PipelineId, String),
133
134 DomMutation(PipelineId, DomMutation),
135
136 DebuggerPause(PipelineId, FrameOffset, PauseReason),
138
139 CreateFrameActor(GenericSender<String>, PipelineId, FrameInfo),
141
142 CreateEnvironmentActor(GenericSender<String>, EnvironmentInfo, Option<String>),
144}
145
146#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
147pub enum DomMutation {
148 AttributeModified {
149 node: String,
150 attribute_name: String,
151 new_value: Option<String>,
152 },
153}
154
155#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
156pub struct ObjectPreview {
157 pub kind: String,
158 pub own_properties: Option<Vec<PropertyDescriptor>>,
159 pub own_properties_length: Option<u32>,
160 pub function: Option<FunctionPreview>,
161 pub array_length: Option<u32>,
162}
163
164#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
165pub struct FunctionPreview {
166 pub name: Option<String>,
167 pub display_name: Option<String>,
168 pub parameter_names: Vec<String>,
169 pub is_async: bool,
170 pub is_generator: bool,
171}
172
173#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
174pub enum DebuggerValue {
175 VoidValue,
176 NullValue,
177 BooleanValue(bool),
178 NumberValue(f64),
179 StringValue(String),
180 ObjectValue {
181 uuid: String,
182 class: String,
183 preview: Option<ObjectPreview>,
184 },
185}
186
187#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
189pub struct PropertyDescriptor {
190 pub name: String,
191 pub value: DebuggerValue,
192 pub configurable: bool,
193 pub enumerable: bool,
194 pub writable: bool,
195 pub is_accessor: bool,
196}
197
198#[derive(Debug, Deserialize, Serialize)]
199pub struct EvaluateJSReply {
200 pub value: DebuggerValue,
201 pub has_exception: bool,
202}
203
204#[derive(Debug, Deserialize, Serialize)]
205pub struct AttrInfo {
206 pub namespace: String,
207 pub name: String,
208 pub value: String,
209}
210
211#[derive(Debug, Deserialize, Serialize)]
212#[serde(rename_all = "camelCase")]
213pub struct NodeInfo {
214 pub unique_id: String,
215 pub host: Option<String>,
216 #[serde(rename = "baseURI")]
217 pub base_uri: String,
218 pub parent: String,
219 pub node_type: u16,
220 pub node_name: String,
221 pub node_value: Option<String>,
222 pub num_children: usize,
223 pub attrs: Vec<AttrInfo>,
224 pub is_top_level_document: bool,
225 pub shadow_root_mode: Option<ShadowRootMode>,
226 pub is_shadow_host: bool,
227 pub display: Option<String>,
228 pub is_displayed: bool,
232
233 pub doctype_name: Option<String>,
235
236 pub doctype_public_identifier: Option<String>,
238
239 pub doctype_system_identifier: Option<String>,
241
242 pub has_event_listeners: bool,
243}
244
245pub struct StartedTimelineMarker {
246 name: String,
247 start_time: CrossProcessInstant,
248 start_stack: Option<Vec<()>>,
249}
250
251#[derive(Debug, Deserialize, Serialize)]
252pub struct TimelineMarker {
253 pub name: String,
254 pub start_time: CrossProcessInstant,
255 pub start_stack: Option<Vec<()>>,
256 pub end_time: CrossProcessInstant,
257 pub end_stack: Option<Vec<()>>,
258}
259
260#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
261pub enum TimelineMarkerType {
262 Reflow,
263 DOMEvent,
264}
265
266#[derive(Debug, Deserialize, Serialize)]
267#[serde(rename_all = "camelCase")]
268pub struct NodeStyle {
269 pub name: String,
270 pub value: String,
271 pub priority: String,
272}
273
274#[derive(Debug, Deserialize, Serialize)]
276#[serde(rename_all = "kebab-case")]
277pub struct ComputedNodeLayout {
278 pub display: String,
279 pub position: String,
280 pub z_index: String,
281 pub box_sizing: String,
282
283 pub margin_top: String,
284 pub margin_right: String,
285 pub margin_bottom: String,
286 pub margin_left: String,
287
288 pub border_top_width: String,
289 pub border_right_width: String,
290 pub border_bottom_width: String,
291 pub border_left_width: String,
292
293 pub padding_top: String,
294 pub padding_right: String,
295 pub padding_bottom: String,
296 pub padding_left: String,
297
298 pub width: f32,
299 pub height: f32,
300}
301
302#[derive(Debug, Default, Deserialize, Serialize)]
303pub struct AutoMargins {
304 pub top: bool,
305 pub right: bool,
306 pub bottom: bool,
307 pub left: bool,
308}
309
310#[derive(Debug, Deserialize, Serialize)]
313pub enum DevtoolScriptControlMsg {
314 GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
316 GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
318 GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
320 GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
322 GetStylesheetStyle(
324 PipelineId,
325 String,
326 String,
327 usize,
328 GenericSender<Option<Vec<NodeStyle>>>,
329 ),
330 GetSelectors(
333 PipelineId,
334 String,
335 GenericSender<Option<Vec<(String, usize)>>>,
336 ),
337 GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
339 GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
341 GetLayout(
343 PipelineId,
344 String,
345 GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
346 ),
347 GetXPath(PipelineId, String, GenericSender<String>),
349 ModifyAttribute(PipelineId, String, Vec<AttrModification>),
351 ModifyRule(PipelineId, String, Vec<RuleModification>),
353 WantsLiveNotifications(PipelineId, bool),
355 SetTimelineMarkers(
357 PipelineId,
358 Vec<TimelineMarkerType>,
359 GenericSender<Option<TimelineMarker>>,
360 ),
361 DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
363 RequestAnimationFrame(PipelineId, String),
366 NavigateTo(PipelineId, ServoUrl),
369 GoBack(PipelineId),
372 GoForward(PipelineId),
375 Reload(PipelineId),
377 GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
379 SimulateColorScheme(PipelineId, Theme),
381 HighlightDomNode(PipelineId, Option<String>),
383
384 Eval(
385 String,
386 PipelineId,
387 Option<String>,
388 GenericSender<EvaluateJSReply>,
389 ),
390 GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
391 SetBreakpoint(u32, u32, u32),
392 ClearBreakpoint(u32, u32, u32),
393 Interrupt,
394 Resume(Option<String>, Option<String>),
395 ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
396 GetEnvironment(String, GenericSender<String>),
397}
398
399#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
400#[serde(rename_all = "camelCase")]
401pub struct AttrModification {
402 pub attribute_name: String,
403 pub new_value: Option<String>,
404}
405
406#[derive(Clone, Debug, Deserialize, Serialize)]
407#[serde(rename_all = "camelCase")]
408pub struct RuleModification {
409 #[serde(rename = "type")]
410 pub type_: String,
411 pub index: u32,
412 pub name: String,
413 pub value: String,
414 pub priority: String,
415}
416
417#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
418#[serde(rename_all = "camelCase")]
419pub struct StackFrame {
420 pub filename: String,
421 pub function_name: String,
422 pub column_number: u32,
423 pub line_number: u32,
424 }
427
428pub fn get_time_stamp() -> u64 {
429 SystemTime::now()
430 .duration_since(UNIX_EPOCH)
431 .unwrap_or_default()
432 .as_millis() as u64
433}
434
435#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
436#[serde(rename_all = "camelCase")]
437pub struct ConsoleMessageFields {
438 pub level: ConsoleLogLevel,
439 pub filename: String,
440 pub line_number: u32,
441 pub column_number: u32,
442 pub time_stamp: u64,
443}
444
445#[derive(Clone, Debug, Deserialize, Serialize)]
446pub enum ConsoleArgument {
447 String(String),
448 Integer(i32),
449 Number(f64),
450 Boolean(bool),
451 Object(ConsoleArgumentObject),
452}
453
454#[derive(Clone, Debug, Deserialize, Serialize)]
455pub struct ConsoleArgumentObject {
456 pub class: String,
457 pub own_properties: Vec<ConsoleArgumentPropertyValue>,
458}
459
460#[derive(Clone, Debug, Deserialize, Serialize)]
462pub struct ConsoleArgumentPropertyValue {
463 pub key: String,
464 pub configurable: bool,
465 pub enumerable: bool,
466 pub writable: bool,
467 pub value: ConsoleArgument,
468}
469
470impl From<String> for ConsoleArgument {
471 fn from(value: String) -> Self {
472 Self::String(value)
473 }
474}
475
476#[derive(Clone, Debug, Deserialize, Serialize)]
477pub struct ConsoleMessage {
478 pub fields: ConsoleMessageFields,
479 pub arguments: Vec<ConsoleArgument>,
480 pub stacktrace: Option<Vec<StackFrame>>,
481}
482
483#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
484#[serde(rename_all = "camelCase")]
485pub struct PageError {
486 pub error_message: String,
487 pub source_name: String,
488 pub line_number: u32,
489 pub column_number: u32,
490 pub time_stamp: u64,
491}
492
493#[derive(Debug, PartialEq, MallocSizeOf)]
494pub struct HttpRequest {
495 pub url: ServoUrl,
496 pub method: Method,
497 pub headers: HeaderMap,
498 pub body: Option<DebugVec>,
499 pub pipeline_id: PipelineId,
500 pub started_date_time: SystemTime,
501 pub time_stamp: i64,
502 pub connect_time: Duration,
503 pub send_time: Duration,
504 pub destination: Destination,
505 pub is_xhr: bool,
506 pub browsing_context_id: BrowsingContextId,
507}
508
509#[derive(Debug, PartialEq, MallocSizeOf)]
510pub struct HttpResponse {
511 #[ignore_malloc_size_of = "Http type"]
512 pub headers: Option<HeaderMap>,
513 pub status: HttpStatus,
514 pub body: Option<DebugVec>,
515 pub from_cache: bool,
516 pub pipeline_id: PipelineId,
517 pub browsing_context_id: BrowsingContextId,
518}
519
520#[derive(Debug, PartialEq)]
521pub struct SecurityInfoUpdate {
522 pub browsing_context_id: BrowsingContextId,
523 pub security_info: Option<TlsSecurityInfo>,
524}
525
526#[derive(Debug)]
527pub enum NetworkEvent {
528 HttpRequest(HttpRequest),
529 HttpRequestUpdate(HttpRequest),
530 HttpResponse(HttpResponse),
531 SecurityInfo(SecurityInfoUpdate),
532}
533
534impl NetworkEvent {
535 pub fn forward_to_devtools(&self) -> bool {
536 match self {
537 NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
538 NetworkEvent::HttpRequestUpdate(_) => true,
539 NetworkEvent::HttpResponse(_) => true,
540 NetworkEvent::SecurityInfo(_) => true,
541 }
542 }
543}
544
545impl TimelineMarker {
546 pub fn start(name: String) -> StartedTimelineMarker {
547 StartedTimelineMarker {
548 name,
549 start_time: CrossProcessInstant::now(),
550 start_stack: None,
551 }
552 }
553}
554
555impl StartedTimelineMarker {
556 pub fn end(self) -> TimelineMarker {
557 TimelineMarker {
558 name: self.name,
559 start_time: self.start_time,
560 start_stack: self.start_stack,
561 end_time: CrossProcessInstant::now(),
562 end_stack: None,
563 }
564 }
565}
566#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
567pub struct WorkerId(pub Uuid);
568impl Display for WorkerId {
569 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
570 write!(f, "{}", self.0)
571 }
572}
573impl FromStr for WorkerId {
574 type Err = uuid::Error;
575
576 fn from_str(s: &str) -> Result<Self, Self::Err> {
577 Ok(Self(s.parse()?))
578 }
579}
580
581#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
582#[serde(rename_all = "camelCase")]
583pub struct CssDatabaseProperty {
584 pub is_inherited: bool,
585 pub values: Vec<String>,
586 pub supports: Vec<String>,
587 pub subproperties: Vec<String>,
588}
589
590#[derive(Debug, Deserialize, Serialize)]
591pub enum ShadowRootMode {
592 Open,
593 Closed,
594}
595
596impl fmt::Display for ShadowRootMode {
597 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598 match self {
599 Self::Open => write!(f, "open"),
600 Self::Closed => write!(f, "close"),
601 }
602 }
603}
604
605#[derive(Debug, Deserialize, Serialize)]
606pub struct SourceInfo {
607 pub url: ServoUrl,
608 pub introduction_type: String,
609 pub inline: bool,
610 pub worker_id: Option<WorkerId>,
611 pub content: Option<String>,
612 pub content_type: Option<String>,
613 pub spidermonkey_id: u32,
614}
615
616#[derive(Clone, Debug, Deserialize, Serialize)]
617#[serde(rename_all = "camelCase")]
618pub struct RecommendedBreakpointLocation {
619 pub script_id: u32,
620 pub offset: u32,
621 pub line_number: u32,
622 pub column_number: u32,
623 pub is_step_start: bool,
624}
625
626#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
627pub struct FrameInfo {
628 pub display_name: String,
629 pub on_stack: bool,
630 pub oldest: bool,
631 pub terminated: bool,
632 pub type_: String,
633 pub url: String,
634}
635
636#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
637pub struct EnvironmentInfo {
638 pub type_: Option<String>,
639 pub scope_kind: Option<String>,
640 pub function_display_name: Option<String>,
641 pub binding_variables: Vec<PropertyDescriptor>,
642}
643
644#[derive(Clone, Debug, Deserialize, Serialize)]
645pub struct EventListenerInfo {
646 pub event_type: String,
647 pub capturing: bool,
648}
649
650#[derive(Debug, Deserialize, Serialize)]
651#[serde(rename_all = "camelCase")]
652pub struct PauseReason {
653 #[serde(rename = "type")]
654 pub type_: String,
655 pub on_next: Option<bool>,
656}
657
658#[derive(Debug, Deserialize, Serialize)]
659pub struct FrameOffset {
660 pub actor: String,
661 pub column: u32,
662 pub line: u32,
663}