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 GetSelectors(PipelineId, String, GenericSender<Option<Vec<MatchedRule>>>),
351 GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
353 GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
355 GetLayout(
357 PipelineId,
358 String,
359 GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
360 ),
361 GetXPath(PipelineId, String, GenericSender<String>),
363 ModifyAttribute(PipelineId, String, Vec<AttrModification>),
365 ModifyRule(PipelineId, String, Vec<RuleModification>),
367 WantsLiveNotifications(PipelineId, bool),
369 SetTimelineMarkers(
371 PipelineId,
372 Vec<TimelineMarkerType>,
373 GenericSender<Option<TimelineMarker>>,
374 ),
375 DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
377 RequestAnimationFrame(PipelineId, String),
380 NavigateTo(PipelineId, ServoUrl),
383 GoBack(PipelineId),
386 GoForward(PipelineId),
389 Reload(PipelineId),
391 GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
393 SimulateColorScheme(PipelineId, Theme),
395 HighlightDomNode(PipelineId, Option<String>),
397
398 Eval(
399 String,
400 PipelineId,
401 Option<String>,
402 GenericSender<EvaluateJSReply>,
403 ),
404 GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
405 SetBreakpoint(u32, u32, u32),
406 ClearBreakpoint(u32, u32, u32),
407 Interrupt,
408 Resume(Option<String>, Option<String>),
409 ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
410 GetEnvironment(String, GenericSender<String>),
411}
412
413#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
414#[serde(rename_all = "camelCase")]
415pub struct AttrModification {
416 pub attribute_name: String,
417 pub new_value: Option<String>,
418}
419
420#[derive(Clone, Debug, Deserialize, Serialize)]
421#[serde(rename_all = "camelCase")]
422pub struct RuleModification {
423 #[serde(rename = "type")]
424 pub type_: String,
425 pub index: u32,
426 pub name: String,
427 pub value: String,
428 pub priority: String,
429}
430
431#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
432#[serde(rename_all = "camelCase")]
433pub struct StackFrame {
434 pub filename: String,
435 pub function_name: String,
436 pub column_number: u32,
437 pub line_number: u32,
438 }
441
442pub fn get_time_stamp() -> u64 {
443 SystemTime::now()
444 .duration_since(UNIX_EPOCH)
445 .unwrap_or_default()
446 .as_millis() as u64
447}
448
449#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
450#[serde(rename_all = "camelCase")]
451pub struct ConsoleMessageFields {
452 pub level: ConsoleLogLevel,
453 pub filename: String,
454 pub line_number: u32,
455 pub column_number: u32,
456 pub time_stamp: u64,
457}
458
459#[derive(Clone, Debug, Deserialize, Serialize)]
460pub struct ConsoleMessage {
461 pub fields: ConsoleMessageFields,
462 pub arguments: Vec<DebuggerValue>,
463 pub stacktrace: Option<Vec<StackFrame>>,
464}
465
466#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
467#[serde(rename_all = "camelCase")]
468pub struct PageError {
469 pub error_message: String,
470 pub source_name: String,
471 pub line_number: u32,
472 pub column_number: u32,
473 pub time_stamp: u64,
474}
475
476#[derive(Debug, PartialEq, MallocSizeOf)]
477pub struct HttpRequest {
478 pub url: ServoUrl,
479 pub method: Method,
480 pub headers: HeaderMap,
481 pub body: Option<DebugVec>,
482 pub pipeline_id: PipelineId,
483 pub started_date_time: SystemTime,
484 pub time_stamp: i64,
485 pub connect_time: Duration,
486 pub send_time: Duration,
487 pub destination: Destination,
488 pub is_xhr: bool,
489 pub browsing_context_id: BrowsingContextId,
490}
491
492#[derive(Debug, PartialEq, MallocSizeOf)]
493pub struct HttpResponse {
494 #[ignore_malloc_size_of = "Http type"]
495 pub headers: Option<HeaderMap>,
496 pub status: HttpStatus,
497 pub body: Option<DebugVec>,
498 pub from_cache: bool,
499 pub pipeline_id: PipelineId,
500 pub browsing_context_id: BrowsingContextId,
501}
502
503#[derive(Debug, PartialEq)]
504pub struct SecurityInfoUpdate {
505 pub browsing_context_id: BrowsingContextId,
506 pub security_info: Option<TlsSecurityInfo>,
507}
508
509#[derive(Debug)]
510pub enum NetworkEvent {
511 HttpRequest(HttpRequest),
512 HttpRequestUpdate(HttpRequest),
513 HttpResponse(HttpResponse),
514 SecurityInfo(SecurityInfoUpdate),
515}
516
517impl NetworkEvent {
518 pub fn forward_to_devtools(&self) -> bool {
519 match self {
520 NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
521 NetworkEvent::HttpRequestUpdate(_) => true,
522 NetworkEvent::HttpResponse(_) => true,
523 NetworkEvent::SecurityInfo(_) => true,
524 }
525 }
526}
527
528impl TimelineMarker {
529 pub fn start(name: String) -> StartedTimelineMarker {
530 StartedTimelineMarker {
531 name,
532 start_time: CrossProcessInstant::now(),
533 start_stack: None,
534 }
535 }
536}
537
538impl StartedTimelineMarker {
539 pub fn end(self) -> TimelineMarker {
540 TimelineMarker {
541 name: self.name,
542 start_time: self.start_time,
543 start_stack: self.start_stack,
544 end_time: CrossProcessInstant::now(),
545 end_stack: None,
546 }
547 }
548}
549#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
550pub struct WorkerId(pub Uuid);
551impl Display for WorkerId {
552 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
553 write!(f, "{}", self.0)
554 }
555}
556impl FromStr for WorkerId {
557 type Err = uuid::Error;
558
559 fn from_str(s: &str) -> Result<Self, Self::Err> {
560 Ok(Self(s.parse()?))
561 }
562}
563
564#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
565#[serde(rename_all = "camelCase")]
566pub struct CssDatabaseProperty {
567 pub is_inherited: bool,
568 pub values: Vec<String>,
569 pub supports: Vec<String>,
570 pub subproperties: Vec<String>,
571}
572
573#[derive(Debug, Deserialize, Serialize)]
574pub enum ShadowRootMode {
575 Open,
576 Closed,
577}
578
579impl fmt::Display for ShadowRootMode {
580 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
581 match self {
582 Self::Open => write!(f, "open"),
583 Self::Closed => write!(f, "close"),
584 }
585 }
586}
587
588#[derive(Debug, Deserialize, Serialize)]
589pub struct SourceInfo {
590 pub url: ServoUrl,
591 pub introduction_type: String,
592 pub inline: bool,
593 pub worker_id: Option<WorkerId>,
594 pub content: Option<String>,
595 pub content_type: Option<String>,
596 pub spidermonkey_id: u32,
597}
598
599#[derive(Clone, Debug, Deserialize, Serialize)]
600#[serde(rename_all = "camelCase")]
601pub struct RecommendedBreakpointLocation {
602 pub script_id: u32,
603 pub offset: u32,
604 pub line_number: u32,
605 pub column_number: u32,
606 pub is_step_start: bool,
607}
608
609#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
610pub struct FrameInfo {
611 pub display_name: String,
612 pub on_stack: bool,
613 pub oldest: bool,
614 pub terminated: bool,
615 pub type_: String,
616 pub url: String,
617}
618
619#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
620pub struct EnvironmentInfo {
621 pub type_: Option<String>,
622 pub scope_kind: Option<String>,
623 pub function_display_name: Option<String>,
624 pub binding_variables: Vec<PropertyDescriptor>,
625}
626
627#[derive(Clone, Debug, Deserialize, Serialize)]
628pub struct EventListenerInfo {
629 pub event_type: String,
630 pub capturing: bool,
631}
632
633#[derive(Debug, Deserialize, Serialize)]
634#[serde(rename_all = "camelCase")]
635pub struct PauseReason {
636 #[serde(rename = "type")]
637 pub type_: String,
638 pub on_next: Option<bool>,
639}
640
641#[derive(Debug, Deserialize, Serialize)]
642pub struct FrameOffset {
643 pub actor: String,
644 pub column: u32,
645 pub line: u32,
646}