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 #[ignore_malloc_size_of = "http type"]
497 pub method: Method,
498 #[ignore_malloc_size_of = "http type"]
499 pub headers: HeaderMap,
500 pub body: Option<DebugVec>,
501 pub pipeline_id: PipelineId,
502 pub started_date_time: SystemTime,
503 pub time_stamp: i64,
504 pub connect_time: Duration,
505 pub send_time: Duration,
506 pub destination: Destination,
507 pub is_xhr: bool,
508 pub browsing_context_id: BrowsingContextId,
509}
510
511#[derive(Debug, PartialEq, MallocSizeOf)]
512pub struct HttpResponse {
513 #[ignore_malloc_size_of = "Http type"]
514 pub headers: Option<HeaderMap>,
515 pub status: HttpStatus,
516 pub body: Option<DebugVec>,
517 pub from_cache: bool,
518 pub pipeline_id: PipelineId,
519 pub browsing_context_id: BrowsingContextId,
520}
521
522#[derive(Debug, PartialEq)]
523pub struct SecurityInfoUpdate {
524 pub browsing_context_id: BrowsingContextId,
525 pub security_info: Option<TlsSecurityInfo>,
526}
527
528#[derive(Debug)]
529pub enum NetworkEvent {
530 HttpRequest(HttpRequest),
531 HttpRequestUpdate(HttpRequest),
532 HttpResponse(HttpResponse),
533 SecurityInfo(SecurityInfoUpdate),
534}
535
536impl NetworkEvent {
537 pub fn forward_to_devtools(&self) -> bool {
538 match self {
539 NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
540 NetworkEvent::HttpRequestUpdate(_) => true,
541 NetworkEvent::HttpResponse(_) => true,
542 NetworkEvent::SecurityInfo(_) => true,
543 }
544 }
545}
546
547impl TimelineMarker {
548 pub fn start(name: String) -> StartedTimelineMarker {
549 StartedTimelineMarker {
550 name,
551 start_time: CrossProcessInstant::now(),
552 start_stack: None,
553 }
554 }
555}
556
557impl StartedTimelineMarker {
558 pub fn end(self) -> TimelineMarker {
559 TimelineMarker {
560 name: self.name,
561 start_time: self.start_time,
562 start_stack: self.start_stack,
563 end_time: CrossProcessInstant::now(),
564 end_stack: None,
565 }
566 }
567}
568#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
569pub struct WorkerId(pub Uuid);
570impl Display for WorkerId {
571 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572 write!(f, "{}", self.0)
573 }
574}
575impl FromStr for WorkerId {
576 type Err = uuid::Error;
577
578 fn from_str(s: &str) -> Result<Self, Self::Err> {
579 Ok(Self(s.parse()?))
580 }
581}
582
583#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
584#[serde(rename_all = "camelCase")]
585pub struct CssDatabaseProperty {
586 pub is_inherited: bool,
587 pub values: Vec<String>,
588 pub supports: Vec<String>,
589 pub subproperties: Vec<String>,
590}
591
592#[derive(Debug, Deserialize, Serialize)]
593pub enum ShadowRootMode {
594 Open,
595 Closed,
596}
597
598impl fmt::Display for ShadowRootMode {
599 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600 match self {
601 Self::Open => write!(f, "open"),
602 Self::Closed => write!(f, "close"),
603 }
604 }
605}
606
607#[derive(Debug, Deserialize, Serialize)]
608pub struct SourceInfo {
609 pub url: ServoUrl,
610 pub introduction_type: String,
611 pub inline: bool,
612 pub worker_id: Option<WorkerId>,
613 pub content: Option<String>,
614 pub content_type: Option<String>,
615 pub spidermonkey_id: u32,
616}
617
618#[derive(Clone, Debug, Deserialize, Serialize)]
619#[serde(rename_all = "camelCase")]
620pub struct RecommendedBreakpointLocation {
621 pub script_id: u32,
622 pub offset: u32,
623 pub line_number: u32,
624 pub column_number: u32,
625 pub is_step_start: bool,
626}
627
628#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
629pub struct FrameInfo {
630 pub display_name: String,
631 pub on_stack: bool,
632 pub oldest: bool,
633 pub terminated: bool,
634 pub type_: String,
635 pub url: String,
636}
637
638#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
639pub struct EnvironmentInfo {
640 pub type_: Option<String>,
641 pub scope_kind: Option<String>,
642 pub function_display_name: Option<String>,
643 pub binding_variables: HashMap<String, String>,
644}
645
646#[derive(Clone, Debug, Deserialize, Serialize)]
647pub struct EventListenerInfo {
648 pub event_type: String,
649 pub capturing: bool,
650}
651
652#[derive(Debug, Deserialize, Serialize)]
653#[serde(rename_all = "camelCase")]
654pub struct PauseReason {
655 #[serde(rename = "type")]
656 pub type_: String,
657 pub on_next: Option<bool>,
658}
659
660#[derive(Debug, Deserialize, Serialize)]
661pub struct FrameOffset {
662 pub actor: String,
663 pub column: u32,
664 pub line: u32,
665}