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