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(
144 GenericSender<String>,
145 EnvironmentInfo,
146 Option<String>,
147 Option<String>,
148 ),
149}
150
151#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
152pub enum DomMutation {
153 AttributeModified {
154 node: String,
155 attribute_name: String,
156 new_value: Option<String>,
157 },
158}
159
160#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
161pub struct ObjectPreview {
162 pub kind: String,
163 pub own_properties: Option<Vec<PropertyDescriptor>>,
164 pub own_properties_length: Option<u32>,
165 pub function: Option<FunctionPreview>,
166 pub array_length: Option<u32>,
167 pub items: Option<Vec<DebuggerValue>>,
168}
169
170#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
171pub struct FunctionPreview {
172 pub name: Option<String>,
173 pub display_name: Option<String>,
174 pub parameter_names: Vec<String>,
175 pub is_async: Option<bool>,
176 pub is_generator: Option<bool>,
177}
178
179#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
180pub enum DebuggerValue {
181 VoidValue,
182 NullValue,
183 BooleanValue(bool),
184 NumberValue(f64),
185 StringValue(String),
186 ObjectValue {
187 uuid: String,
188 class: String,
189 preview: Option<ObjectPreview>,
190 },
191}
192
193#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
195pub struct PropertyDescriptor {
196 pub name: String,
197 pub value: DebuggerValue,
198 pub configurable: bool,
199 pub enumerable: bool,
200 pub writable: bool,
201 pub is_accessor: bool,
202}
203
204#[derive(Debug, Deserialize, Serialize)]
205pub struct EvaluateJSReply {
206 pub value: DebuggerValue,
207 pub has_exception: bool,
208}
209
210#[derive(Debug, Deserialize, Serialize)]
211pub struct AttrInfo {
212 pub namespace: String,
213 pub name: String,
214 pub value: String,
215}
216
217#[derive(Debug, Deserialize, Serialize)]
218#[serde(rename_all = "camelCase")]
219pub struct NodeInfo {
220 pub unique_id: String,
221 pub host: Option<String>,
222 #[serde(rename = "baseURI")]
223 pub base_uri: String,
224 pub parent: String,
225 pub node_type: u16,
226 pub node_name: String,
227 pub node_value: Option<String>,
228 pub num_children: usize,
229 pub attrs: Vec<AttrInfo>,
230 pub is_top_level_document: bool,
231 pub shadow_root_mode: Option<ShadowRootMode>,
232 pub is_shadow_host: bool,
233 pub display: Option<String>,
234 pub is_displayed: bool,
238
239 pub doctype_name: Option<String>,
241
242 pub doctype_public_identifier: Option<String>,
244
245 pub doctype_system_identifier: Option<String>,
247
248 pub has_event_listeners: bool,
249}
250
251pub struct StartedTimelineMarker {
252 name: String,
253 start_time: CrossProcessInstant,
254 start_stack: Option<Vec<()>>,
255}
256
257#[derive(Debug, Deserialize, Serialize)]
258pub struct TimelineMarker {
259 pub name: String,
260 pub start_time: CrossProcessInstant,
261 pub start_stack: Option<Vec<()>>,
262 pub end_time: CrossProcessInstant,
263 pub end_stack: Option<Vec<()>>,
264}
265
266#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
267pub enum TimelineMarkerType {
268 Reflow,
269 DOMEvent,
270}
271
272#[derive(Debug, Deserialize, Serialize)]
273#[serde(rename_all = "camelCase")]
274pub struct NodeStyle {
275 pub name: String,
276 pub value: String,
277 pub priority: String,
278}
279
280#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
281#[serde(tag = "type", rename_all = "camelCase")]
282pub enum AncestorData {
283 Layer {
284 actor_id: Option<String>,
285 value: Option<String>,
286 },
287}
288
289#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
290#[serde(rename_all = "camelCase")]
291pub struct MatchedRule {
292 pub selector: String,
293 pub stylesheet_index: usize,
294 pub block_id: usize,
295 pub ancestor_data: Vec<AncestorData>,
296}
297
298#[derive(Debug, Deserialize, Serialize)]
300#[serde(rename_all = "kebab-case")]
301pub struct ComputedNodeLayout {
302 pub display: String,
303 pub position: String,
304 pub z_index: String,
305 pub box_sizing: String,
306
307 pub margin_top: String,
308 pub margin_right: String,
309 pub margin_bottom: String,
310 pub margin_left: String,
311
312 pub border_top_width: String,
313 pub border_right_width: String,
314 pub border_bottom_width: String,
315 pub border_left_width: String,
316
317 pub padding_top: String,
318 pub padding_right: String,
319 pub padding_bottom: String,
320 pub padding_left: String,
321
322 pub width: f32,
323 pub height: f32,
324}
325
326#[derive(Debug, Default, Deserialize, Serialize)]
327pub struct AutoMargins {
328 pub top: bool,
329 pub right: bool,
330 pub bottom: bool,
331 pub left: bool,
332}
333
334#[derive(Debug, Deserialize, Serialize)]
337pub enum DevtoolScriptControlMsg {
338 GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
340 GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
342 GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
344 GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
346 GetStylesheetStyle(
348 PipelineId,
349 String,
350 MatchedRule,
351 GenericSender<Option<Vec<NodeStyle>>>,
352 ),
353 GetStyleSheets(PipelineId, GenericSender<Vec<StyleSheetInfo>>),
355 GetStyleSheetText(PipelineId, i32, GenericSender<Option<String>>),
357 GetSelectors(PipelineId, String, GenericSender<Option<Vec<MatchedRule>>>),
360 GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
362 GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
364 GetLayout(
366 PipelineId,
367 String,
368 GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
369 ),
370 GetXPath(PipelineId, String, GenericSender<String>),
372 ModifyAttribute(PipelineId, String, Vec<AttrModification>),
374 ModifyRule(PipelineId, String, Vec<RuleModification>),
376 WantsLiveNotifications(PipelineId, bool),
378 SetTimelineMarkers(
380 PipelineId,
381 Vec<TimelineMarkerType>,
382 GenericSender<Option<TimelineMarker>>,
383 ),
384 DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
386 RequestAnimationFrame(PipelineId, String),
389 NavigateTo(PipelineId, ServoUrl),
392 GoBack(PipelineId),
395 GoForward(PipelineId),
398 Reload(PipelineId),
400 GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
402 SimulateColorScheme(PipelineId, Theme),
404 HighlightDomNode(PipelineId, Option<String>),
406
407 Eval(
408 String,
409 PipelineId,
410 Option<String>,
411 GenericSender<EvaluateJSReply>,
412 ),
413 GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
414 SetBreakpoint(u32, u32, u32),
415 ClearBreakpoint(u32, u32, u32),
416 Interrupt,
417 Resume(Option<String>, Option<String>),
418 ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
419 GetEnvironment(String, GenericSender<String>),
420}
421
422#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
423#[serde(rename_all = "camelCase")]
424pub struct AttrModification {
425 pub attribute_name: String,
426 pub new_value: Option<String>,
427}
428
429#[derive(Clone, Debug, Deserialize, Serialize)]
430#[serde(rename_all = "camelCase")]
431pub struct RuleModification {
432 #[serde(rename = "type")]
433 pub type_: String,
434 pub index: u32,
435 pub name: String,
436 pub value: String,
437 pub priority: String,
438}
439
440#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
441#[serde(rename_all = "camelCase")]
442pub struct StackFrame {
443 pub filename: String,
444 pub function_name: String,
445 pub column_number: u32,
446 pub line_number: u32,
447 }
450
451pub fn get_time_stamp() -> u64 {
452 SystemTime::now()
453 .duration_since(UNIX_EPOCH)
454 .unwrap_or_default()
455 .as_millis() as u64
456}
457
458#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
459#[serde(rename_all = "camelCase")]
460pub struct ConsoleMessageFields {
461 pub level: ConsoleLogLevel,
462 pub filename: String,
463 pub line_number: u32,
464 pub column_number: u32,
465 pub time_stamp: u64,
466}
467
468#[derive(Clone, Debug, Deserialize, Serialize)]
469pub struct ConsoleMessage {
470 pub fields: ConsoleMessageFields,
471 pub arguments: Vec<DebuggerValue>,
472 pub stacktrace: Option<Vec<StackFrame>>,
473}
474
475#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
476#[serde(rename_all = "camelCase")]
477pub struct PageError {
478 pub error_message: String,
479 pub source_name: String,
480 pub line_number: u32,
481 pub column_number: u32,
482 pub time_stamp: u64,
483}
484
485#[derive(Debug, PartialEq, MallocSizeOf)]
486pub struct HttpRequest {
487 pub url: ServoUrl,
488 pub method: Method,
489 pub headers: HeaderMap,
490 pub body: Option<DebugVec>,
491 pub pipeline_id: PipelineId,
492 pub started_date_time: SystemTime,
493 pub time_stamp: i64,
494 pub connect_time: Duration,
495 pub send_time: Duration,
496 pub destination: Destination,
497 pub is_xhr: bool,
498 pub browsing_context_id: BrowsingContextId,
499}
500
501#[derive(Debug, PartialEq, MallocSizeOf)]
502pub struct HttpResponse {
503 #[ignore_malloc_size_of = "Http type"]
504 pub headers: Option<HeaderMap>,
505 pub status: HttpStatus,
506 pub body: Option<DebugVec>,
507 pub from_cache: bool,
508 pub pipeline_id: PipelineId,
509 pub browsing_context_id: BrowsingContextId,
510}
511
512#[derive(Debug, PartialEq)]
513pub struct SecurityInfoUpdate {
514 pub browsing_context_id: BrowsingContextId,
515 pub security_info: Option<TlsSecurityInfo>,
516}
517
518#[derive(Debug)]
519pub enum NetworkEvent {
520 HttpRequest(HttpRequest),
521 HttpRequestUpdate(HttpRequest),
522 HttpResponse(HttpResponse),
523 SecurityInfo(SecurityInfoUpdate),
524}
525
526impl NetworkEvent {
527 pub fn forward_to_devtools(&self) -> bool {
528 match self {
529 NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
530 NetworkEvent::HttpRequestUpdate(_) => true,
531 NetworkEvent::HttpResponse(_) => true,
532 NetworkEvent::SecurityInfo(_) => true,
533 }
534 }
535}
536
537impl TimelineMarker {
538 pub fn start(name: String) -> StartedTimelineMarker {
539 StartedTimelineMarker {
540 name,
541 start_time: CrossProcessInstant::now(),
542 start_stack: None,
543 }
544 }
545}
546
547impl StartedTimelineMarker {
548 pub fn end(self) -> TimelineMarker {
549 TimelineMarker {
550 name: self.name,
551 start_time: self.start_time,
552 start_stack: self.start_stack,
553 end_time: CrossProcessInstant::now(),
554 end_stack: None,
555 }
556 }
557}
558#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
559pub struct WorkerId(pub Uuid);
560impl Display for WorkerId {
561 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
562 write!(f, "{}", self.0)
563 }
564}
565impl FromStr for WorkerId {
566 type Err = uuid::Error;
567
568 fn from_str(s: &str) -> Result<Self, Self::Err> {
569 Ok(Self(s.parse()?))
570 }
571}
572
573#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
574#[serde(rename_all = "camelCase")]
575pub struct CssDatabaseProperty {
576 pub is_inherited: bool,
577 pub values: Vec<String>,
578 pub supports: Vec<String>,
579 pub subproperties: Vec<String>,
580}
581
582#[derive(Debug, Deserialize, Serialize)]
583pub enum ShadowRootMode {
584 Open,
585 Closed,
586}
587
588impl fmt::Display for ShadowRootMode {
589 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
590 match self {
591 Self::Open => write!(f, "open"),
592 Self::Closed => write!(f, "close"),
593 }
594 }
595}
596
597#[derive(Debug, Deserialize, Serialize)]
598pub struct SourceInfo {
599 pub url: ServoUrl,
600 pub introduction_type: String,
601 pub inline: bool,
602 pub worker_id: Option<WorkerId>,
603 pub content: Option<String>,
604 pub content_type: Option<String>,
605 pub spidermonkey_id: u32,
606}
607
608#[derive(Clone, Debug, Deserialize, Serialize)]
609#[serde(rename_all = "camelCase")]
610pub struct RecommendedBreakpointLocation {
611 pub script_id: u32,
612 pub offset: u32,
613 pub line_number: u32,
614 pub column_number: u32,
615 pub is_step_start: bool,
616}
617
618#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
619pub struct FrameInfo {
620 pub display_name: String,
621 pub on_stack: bool,
622 pub oldest: bool,
623 pub terminated: bool,
624 pub type_: String,
625 pub url: String,
626}
627
628#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
629pub struct EnvironmentInfo {
630 pub type_: Option<String>,
631 pub scope_kind: Option<String>,
632 pub function_display_name: Option<String>,
633 pub binding_variables: Vec<PropertyDescriptor>,
634}
635
636#[derive(Clone, Debug, Deserialize, Serialize)]
637pub struct StyleSheetInfo {
638 pub href: Option<String>,
639 pub disabled: bool,
640 pub title: String,
641 pub style_sheet_index: i32,
642 pub system: bool,
643 pub rule_count: u32,
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}