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
26use base::cross_process_instant::CrossProcessInstant;
27use base::generic_channel::GenericSender;
28use base::id::{BrowsingContextId, PipelineId, WebViewId};
29pub use embedder_traits::ConsoleLogLevel;
30use embedder_traits::Theme;
31use http::{HeaderMap, Method};
32use malloc_size_of_derive::MallocSizeOf;
33use net_traits::http_status::HttpStatus;
34use net_traits::request::Destination;
35use net_traits::{DebugVec, TlsSecurityInfo};
36use profile_traits::mem::ReportsChan;
37use serde::{Deserialize, Serialize};
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}
49
50#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
51pub struct CSSError {
52 pub filename: String,
53 pub line: u32,
54 pub column: u32,
55 pub msg: String,
56}
57
58#[derive(Debug)]
61pub enum DevtoolsControlMsg {
62 FromChrome(ChromeToDevtoolsControlMsg),
64 FromScript(ScriptToDevtoolsControlMsg),
66 ClientExited,
68}
69
70#[expect(clippy::large_enum_variant)]
73#[derive(Debug)]
74pub enum ChromeToDevtoolsControlMsg {
75 AddClient(TcpStream),
77 ServerExitMsg,
79 NetworkEvent(String, NetworkEvent),
82 CollectMemoryReport(ReportsChan),
84}
85
86#[derive(Debug, Deserialize, Serialize)]
88pub enum NavigationState {
89 Start(ServoUrl),
91 Stop(PipelineId, DevtoolsPageInfo),
93}
94
95#[derive(Debug, Deserialize, Serialize)]
96pub enum ScriptToDevtoolsControlMsg {
98 NewGlobal(
101 (BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
102 GenericSender<DevtoolScriptControlMsg>,
103 DevtoolsPageInfo,
104 ),
105 Navigate(BrowsingContextId, NavigationState),
107 ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
109 ClearConsole(PipelineId, Option<WorkerId>),
111 FramerateTick(String, f64),
114
115 ReportCSSError(PipelineId, CSSError),
117
118 ReportPageError(PipelineId, PageError),
120
121 TitleChanged(PipelineId, String),
123
124 CreateSourceActor(
126 GenericSender<DevtoolScriptControlMsg>,
127 PipelineId,
128 SourceInfo,
129 ),
130
131 UpdateSourceContent(PipelineId, String),
132
133 DomMutation(PipelineId, DomMutation),
134
135 DebuggerPause(PipelineId, FrameOffset, PauseReason),
137
138 CreateFrameActor(GenericSender<String>, PipelineId, FrameInfo),
140
141 CreateEnvironmentActor(GenericSender<String>, EnvironmentInfo, Option<String>),
143}
144
145#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
146pub enum DomMutation {
147 AttributeModified {
148 node: String,
149 attribute_name: String,
150 new_value: Option<String>,
151 },
152}
153
154#[derive(Debug, Deserialize, Serialize)]
156pub enum EvaluateJSReplyValue {
157 VoidValue,
158 NullValue,
159 BooleanValue(bool),
160 NumberValue(f64),
161 StringValue(String),
162 ActorValue {
163 class: String,
164 uuid: String,
165 name: Option<String>,
166 },
167}
168
169#[derive(Debug, Deserialize, Serialize)]
170pub struct EvaluateJSReply {
171 pub value: EvaluateJSReplyValue,
172 pub has_exception: bool,
173}
174
175#[derive(Debug, Deserialize, Serialize)]
176pub struct AttrInfo {
177 pub namespace: String,
178 pub name: String,
179 pub value: String,
180}
181
182#[derive(Debug, Deserialize, Serialize)]
183#[serde(rename_all = "camelCase")]
184pub struct NodeInfo {
185 pub unique_id: String,
186 pub host: Option<String>,
187 #[serde(rename = "baseURI")]
188 pub base_uri: String,
189 pub parent: String,
190 pub node_type: u16,
191 pub node_name: String,
192 pub node_value: Option<String>,
193 pub num_children: usize,
194 pub attrs: Vec<AttrInfo>,
195 pub is_top_level_document: bool,
196 pub shadow_root_mode: Option<ShadowRootMode>,
197 pub is_shadow_host: bool,
198 pub display: Option<String>,
199 pub is_displayed: bool,
203
204 pub doctype_name: Option<String>,
206
207 pub doctype_public_identifier: Option<String>,
209
210 pub doctype_system_identifier: Option<String>,
212
213 pub has_event_listeners: bool,
214}
215
216pub struct StartedTimelineMarker {
217 name: String,
218 start_time: CrossProcessInstant,
219 start_stack: Option<Vec<()>>,
220}
221
222#[derive(Debug, Deserialize, Serialize)]
223pub struct TimelineMarker {
224 pub name: String,
225 pub start_time: CrossProcessInstant,
226 pub start_stack: Option<Vec<()>>,
227 pub end_time: CrossProcessInstant,
228 pub end_stack: Option<Vec<()>>,
229}
230
231#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
232pub enum TimelineMarkerType {
233 Reflow,
234 DOMEvent,
235}
236
237#[derive(Debug, Deserialize, Serialize)]
238#[serde(rename_all = "camelCase")]
239pub struct NodeStyle {
240 pub name: String,
241 pub value: String,
242 pub priority: String,
243}
244
245#[derive(Debug, Deserialize, Serialize)]
247#[serde(rename_all = "kebab-case")]
248pub struct ComputedNodeLayout {
249 pub display: String,
250 pub position: String,
251 pub z_index: String,
252 pub box_sizing: String,
253
254 pub margin_top: String,
255 pub margin_right: String,
256 pub margin_bottom: String,
257 pub margin_left: String,
258
259 pub border_top_width: String,
260 pub border_right_width: String,
261 pub border_bottom_width: String,
262 pub border_left_width: String,
263
264 pub padding_top: String,
265 pub padding_right: String,
266 pub padding_bottom: String,
267 pub padding_left: String,
268
269 pub width: f32,
270 pub height: f32,
271}
272
273#[derive(Debug, Default, Deserialize, Serialize)]
274pub struct AutoMargins {
275 pub top: bool,
276 pub right: bool,
277 pub bottom: bool,
278 pub left: bool,
279}
280
281#[derive(Debug, Deserialize, Serialize)]
284pub enum DevtoolScriptControlMsg {
285 EvaluateJS(PipelineId, String, GenericSender<EvaluateJSReply>),
287 GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
289 GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
291 GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
293 GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
295 GetStylesheetStyle(
297 PipelineId,
298 String,
299 String,
300 usize,
301 GenericSender<Option<Vec<NodeStyle>>>,
302 ),
303 GetSelectors(
306 PipelineId,
307 String,
308 GenericSender<Option<Vec<(String, usize)>>>,
309 ),
310 GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
312 GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
314 GetLayout(
316 PipelineId,
317 String,
318 GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
319 ),
320 GetXPath(PipelineId, String, GenericSender<String>),
322 ModifyAttribute(PipelineId, String, Vec<AttrModification>),
324 ModifyRule(PipelineId, String, Vec<RuleModification>),
326 WantsLiveNotifications(PipelineId, bool),
328 SetTimelineMarkers(
330 PipelineId,
331 Vec<TimelineMarkerType>,
332 GenericSender<Option<TimelineMarker>>,
333 ),
334 DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
336 RequestAnimationFrame(PipelineId, String),
339 NavigateTo(PipelineId, ServoUrl),
342 GoBack(PipelineId),
345 GoForward(PipelineId),
348 Reload(PipelineId),
350 GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
352 SimulateColorScheme(PipelineId, Theme),
354 HighlightDomNode(PipelineId, Option<String>),
356
357 Eval(
358 String,
359 PipelineId,
360 Option<String>,
361 GenericSender<EvaluateJSReply>,
362 ),
363 GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
364 SetBreakpoint(u32, u32, u32),
365 ClearBreakpoint(u32, u32, u32),
366 Interrupt,
367 Resume(Option<String>, Option<String>),
368 ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
369 GetEnvironment(String, GenericSender<String>),
370}
371
372#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
373#[serde(rename_all = "camelCase")]
374pub struct AttrModification {
375 pub attribute_name: String,
376 pub new_value: Option<String>,
377}
378
379#[derive(Clone, Debug, Deserialize, Serialize)]
380#[serde(rename_all = "camelCase")]
381pub struct RuleModification {
382 #[serde(rename = "type")]
383 pub type_: String,
384 pub index: u32,
385 pub name: String,
386 pub value: String,
387 pub priority: String,
388}
389
390#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
391#[serde(rename_all = "camelCase")]
392pub struct StackFrame {
393 pub filename: String,
394 pub function_name: String,
395 pub column_number: u32,
396 pub line_number: u32,
397 }
400
401pub fn get_time_stamp() -> u64 {
402 SystemTime::now()
403 .duration_since(UNIX_EPOCH)
404 .unwrap_or_default()
405 .as_millis() as u64
406}
407
408#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
409#[serde(rename_all = "camelCase")]
410pub struct ConsoleMessageFields {
411 pub level: ConsoleLogLevel,
412 pub filename: String,
413 pub line_number: u32,
414 pub column_number: u32,
415 pub time_stamp: u64,
416}
417
418#[derive(Clone, Debug, Deserialize, Serialize)]
419pub enum ConsoleArgument {
420 String(String),
421 Integer(i32),
422 Number(f64),
423 Boolean(bool),
424 Object(ConsoleArgumentObject),
425}
426
427#[derive(Clone, Debug, Deserialize, Serialize)]
428pub struct ConsoleArgumentObject {
429 pub class: String,
430 pub own_properties: Vec<ConsoleArgumentPropertyValue>,
431}
432
433#[derive(Clone, Debug, Deserialize, Serialize)]
435pub struct ConsoleArgumentPropertyValue {
436 pub key: String,
437 pub configurable: bool,
438 pub enumerable: bool,
439 pub writable: bool,
440 pub value: ConsoleArgument,
441}
442
443impl From<String> for ConsoleArgument {
444 fn from(value: String) -> Self {
445 Self::String(value)
446 }
447}
448
449#[derive(Clone, Debug, Deserialize, Serialize)]
450pub struct ConsoleMessage {
451 pub fields: ConsoleMessageFields,
452 pub arguments: Vec<ConsoleArgument>,
453 pub stacktrace: Option<Vec<StackFrame>>,
454}
455
456#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
457#[serde(rename_all = "camelCase")]
458pub struct PageError {
459 pub error_message: String,
460 pub source_name: String,
461 pub line_number: u32,
462 pub column_number: u32,
463 pub time_stamp: u64,
464}
465
466#[derive(Debug, PartialEq, MallocSizeOf)]
467pub struct HttpRequest {
468 pub url: ServoUrl,
469 #[ignore_malloc_size_of = "http type"]
470 pub method: Method,
471 #[ignore_malloc_size_of = "http type"]
472 pub headers: HeaderMap,
473 pub body: Option<DebugVec>,
474 pub pipeline_id: PipelineId,
475 pub started_date_time: SystemTime,
476 pub time_stamp: i64,
477 pub connect_time: Duration,
478 pub send_time: Duration,
479 pub destination: Destination,
480 pub is_xhr: bool,
481 pub browsing_context_id: BrowsingContextId,
482}
483
484#[derive(Debug, PartialEq, MallocSizeOf)]
485pub struct HttpResponse {
486 #[ignore_malloc_size_of = "Http type"]
487 pub headers: Option<HeaderMap>,
488 pub status: HttpStatus,
489 pub body: Option<DebugVec>,
490 pub from_cache: bool,
491 pub pipeline_id: PipelineId,
492 pub browsing_context_id: BrowsingContextId,
493}
494
495#[derive(Debug, PartialEq)]
496pub struct SecurityInfoUpdate {
497 pub browsing_context_id: BrowsingContextId,
498 pub security_info: Option<TlsSecurityInfo>,
499}
500
501#[derive(Debug)]
502pub enum NetworkEvent {
503 HttpRequest(HttpRequest),
504 HttpRequestUpdate(HttpRequest),
505 HttpResponse(HttpResponse),
506 SecurityInfo(SecurityInfoUpdate),
507}
508
509impl NetworkEvent {
510 pub fn forward_to_devtools(&self) -> bool {
511 match self {
512 NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
513 NetworkEvent::HttpRequestUpdate(_) => true,
514 NetworkEvent::HttpResponse(_) => true,
515 NetworkEvent::SecurityInfo(_) => true,
516 }
517 }
518}
519
520impl TimelineMarker {
521 pub fn start(name: String) -> StartedTimelineMarker {
522 StartedTimelineMarker {
523 name,
524 start_time: CrossProcessInstant::now(),
525 start_stack: None,
526 }
527 }
528}
529
530impl StartedTimelineMarker {
531 pub fn end(self) -> TimelineMarker {
532 TimelineMarker {
533 name: self.name,
534 start_time: self.start_time,
535 start_stack: self.start_stack,
536 end_time: CrossProcessInstant::now(),
537 end_stack: None,
538 }
539 }
540}
541#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
542pub struct WorkerId(pub Uuid);
543impl Display for WorkerId {
544 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
545 write!(f, "{}", self.0)
546 }
547}
548impl FromStr for WorkerId {
549 type Err = uuid::Error;
550
551 fn from_str(s: &str) -> Result<Self, Self::Err> {
552 Ok(Self(s.parse()?))
553 }
554}
555
556#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
557#[serde(rename_all = "camelCase")]
558pub struct CssDatabaseProperty {
559 pub is_inherited: bool,
560 pub values: Vec<String>,
561 pub supports: Vec<String>,
562 pub subproperties: Vec<String>,
563}
564
565#[derive(Debug, Deserialize, Serialize)]
566pub enum ShadowRootMode {
567 Open,
568 Closed,
569}
570
571impl fmt::Display for ShadowRootMode {
572 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
573 match self {
574 Self::Open => write!(f, "open"),
575 Self::Closed => write!(f, "close"),
576 }
577 }
578}
579
580#[derive(Debug, Deserialize, Serialize)]
581pub struct SourceInfo {
582 pub url: ServoUrl,
583 pub introduction_type: String,
584 pub inline: bool,
585 pub worker_id: Option<WorkerId>,
586 pub content: Option<String>,
587 pub content_type: Option<String>,
588 pub spidermonkey_id: u32,
589}
590
591#[derive(Clone, Debug, Deserialize, Serialize)]
592#[serde(rename_all = "camelCase")]
593pub struct RecommendedBreakpointLocation {
594 pub script_id: u32,
595 pub offset: u32,
596 pub line_number: u32,
597 pub column_number: u32,
598 pub is_step_start: bool,
599}
600
601#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
602pub struct FrameInfo {
603 pub display_name: String,
604 pub on_stack: bool,
605 pub oldest: bool,
606 pub terminated: bool,
607 pub type_: String,
608 pub url: String,
609}
610
611#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
612pub struct EnvironmentInfo {
613 pub type_: Option<String>,
614 pub scope_kind: Option<String>,
615 pub function_display_name: Option<String>,
616}
617
618#[derive(Clone, Debug, Deserialize, Serialize)]
619pub struct EventListenerInfo {
620 pub event_type: String,
621 pub capturing: bool,
622}
623
624#[derive(Debug, Deserialize, Serialize)]
625#[serde(rename_all = "camelCase")]
626pub struct PauseReason {
627 #[serde(rename = "type")]
628 pub type_: String,
629 pub on_next: Option<bool>,
630}
631
632#[derive(Debug, Deserialize, Serialize)]
633pub struct FrameOffset {
634 pub actor: String,
635 pub column: u32,
636 pub line: u32,
637}