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 BreakpointHit(PipelineId, PauseFrameResult),
137}
138
139#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
140pub enum DomMutation {
141 AttributeModified {
142 node: String,
143 attribute_name: String,
144 new_value: Option<String>,
145 },
146}
147
148#[derive(Debug, Deserialize, Serialize)]
151pub enum EvaluateJSReply {
152 VoidValue,
153 NullValue,
154 BooleanValue(bool),
155 NumberValue(f64),
156 StringValue(String),
157 ActorValue { class: String, uuid: String },
158}
159
160#[derive(Debug, Deserialize, Serialize)]
161pub struct AttrInfo {
162 pub namespace: String,
163 pub name: String,
164 pub value: String,
165}
166
167#[derive(Debug, Deserialize, Serialize)]
168#[serde(rename_all = "camelCase")]
169pub struct NodeInfo {
170 pub unique_id: String,
171 pub host: Option<String>,
172 #[serde(rename = "baseURI")]
173 pub base_uri: String,
174 pub parent: String,
175 pub node_type: u16,
176 pub node_name: String,
177 pub node_value: Option<String>,
178 pub num_children: usize,
179 pub attrs: Vec<AttrInfo>,
180 pub is_top_level_document: bool,
181 pub shadow_root_mode: Option<ShadowRootMode>,
182 pub is_shadow_host: bool,
183 pub display: Option<String>,
184 pub is_displayed: bool,
188
189 pub doctype_name: Option<String>,
191
192 pub doctype_public_identifier: Option<String>,
194
195 pub doctype_system_identifier: Option<String>,
197
198 pub has_event_listeners: bool,
199}
200
201pub struct StartedTimelineMarker {
202 name: String,
203 start_time: CrossProcessInstant,
204 start_stack: Option<Vec<()>>,
205}
206
207#[derive(Debug, Deserialize, Serialize)]
208pub struct TimelineMarker {
209 pub name: String,
210 pub start_time: CrossProcessInstant,
211 pub start_stack: Option<Vec<()>>,
212 pub end_time: CrossProcessInstant,
213 pub end_stack: Option<Vec<()>>,
214}
215
216#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
217pub enum TimelineMarkerType {
218 Reflow,
219 DOMEvent,
220}
221
222#[derive(Debug, Deserialize, Serialize)]
223#[serde(rename_all = "camelCase")]
224pub struct NodeStyle {
225 pub name: String,
226 pub value: String,
227 pub priority: String,
228}
229
230#[derive(Debug, Deserialize, Serialize)]
232#[serde(rename_all = "kebab-case")]
233pub struct ComputedNodeLayout {
234 pub display: String,
235 pub position: String,
236 pub z_index: String,
237 pub box_sizing: String,
238
239 pub margin_top: String,
240 pub margin_right: String,
241 pub margin_bottom: String,
242 pub margin_left: String,
243
244 pub border_top_width: String,
245 pub border_right_width: String,
246 pub border_bottom_width: String,
247 pub border_left_width: String,
248
249 pub padding_top: String,
250 pub padding_right: String,
251 pub padding_bottom: String,
252 pub padding_left: String,
253
254 pub width: f32,
255 pub height: f32,
256}
257
258#[derive(Debug, Default, Deserialize, Serialize)]
259pub struct AutoMargins {
260 pub top: bool,
261 pub right: bool,
262 pub bottom: bool,
263 pub left: bool,
264}
265
266#[derive(Debug, Deserialize, Serialize)]
269pub enum DevtoolScriptControlMsg {
270 EvaluateJS(PipelineId, String, GenericSender<EvaluateJSReply>),
272 GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
274 GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
276 GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
278 GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
280 GetStylesheetStyle(
282 PipelineId,
283 String,
284 String,
285 usize,
286 GenericSender<Option<Vec<NodeStyle>>>,
287 ),
288 GetSelectors(
291 PipelineId,
292 String,
293 GenericSender<Option<Vec<(String, usize)>>>,
294 ),
295 GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
297 GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
299 GetLayout(
301 PipelineId,
302 String,
303 GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
304 ),
305 GetXPath(PipelineId, String, GenericSender<String>),
307 ModifyAttribute(PipelineId, String, Vec<AttrModification>),
309 ModifyRule(PipelineId, String, Vec<RuleModification>),
311 WantsLiveNotifications(PipelineId, bool),
313 SetTimelineMarkers(
315 PipelineId,
316 Vec<TimelineMarkerType>,
317 GenericSender<Option<TimelineMarker>>,
318 ),
319 DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
321 RequestAnimationFrame(PipelineId, String),
324 Reload(PipelineId),
326 GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
328 SimulateColorScheme(PipelineId, Theme),
330 HighlightDomNode(PipelineId, Option<String>),
332
333 Eval(String, PipelineId, GenericSender<EvaluateJSReply>),
334 GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
335 SetBreakpoint(u32, u32, u32),
336 ClearBreakpoint(u32, u32, u32),
337 Pause(GenericSender<PauseFrameResult>),
338 Resume,
339}
340
341#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
342#[serde(rename_all = "camelCase")]
343pub struct AttrModification {
344 pub attribute_name: String,
345 pub new_value: Option<String>,
346}
347
348#[derive(Clone, Debug, Deserialize, Serialize)]
349#[serde(rename_all = "camelCase")]
350pub struct RuleModification {
351 #[serde(rename = "type")]
352 pub type_: String,
353 pub index: u32,
354 pub name: String,
355 pub value: String,
356 pub priority: String,
357}
358
359#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
360#[serde(rename_all = "camelCase")]
361pub struct StackFrame {
362 pub filename: String,
363 pub function_name: String,
364 pub column_number: u32,
365 pub line_number: u32,
366 }
369
370pub fn get_time_stamp() -> u64 {
371 SystemTime::now()
372 .duration_since(UNIX_EPOCH)
373 .unwrap_or_default()
374 .as_millis() as u64
375}
376
377#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
378#[serde(rename_all = "camelCase")]
379pub struct ConsoleMessageFields {
380 pub level: ConsoleLogLevel,
381 pub filename: String,
382 pub line_number: u32,
383 pub column_number: u32,
384 pub time_stamp: u64,
385}
386
387#[derive(Clone, Debug, Deserialize, Serialize)]
388pub enum ConsoleArgument {
389 String(String),
390 Integer(i32),
391 Number(f64),
392 Boolean(bool),
393 Object(ConsoleArgumentObject),
394}
395
396#[derive(Clone, Debug, Deserialize, Serialize)]
397pub struct ConsoleArgumentObject {
398 pub class: String,
399 pub own_properties: Vec<ConsoleArgumentPropertyValue>,
400}
401
402#[derive(Clone, Debug, Deserialize, Serialize)]
404pub struct ConsoleArgumentPropertyValue {
405 pub key: String,
406 pub configurable: bool,
407 pub enumerable: bool,
408 pub writable: bool,
409 pub value: ConsoleArgument,
410}
411
412impl From<String> for ConsoleArgument {
413 fn from(value: String) -> Self {
414 Self::String(value)
415 }
416}
417
418#[derive(Clone, Debug, Deserialize, Serialize)]
419pub struct ConsoleMessage {
420 pub fields: ConsoleMessageFields,
421 pub arguments: Vec<ConsoleArgument>,
422 pub stacktrace: Option<Vec<StackFrame>>,
423}
424
425#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
426#[serde(rename_all = "camelCase")]
427pub struct PageError {
428 pub error_message: String,
429 pub source_name: String,
430 pub line_number: u32,
431 pub column_number: u32,
432 pub time_stamp: u64,
433}
434
435#[derive(Debug, PartialEq, MallocSizeOf)]
436pub struct HttpRequest {
437 pub url: ServoUrl,
438 #[ignore_malloc_size_of = "http type"]
439 pub method: Method,
440 #[ignore_malloc_size_of = "http type"]
441 pub headers: HeaderMap,
442 pub body: Option<DebugVec>,
443 pub pipeline_id: PipelineId,
444 pub started_date_time: SystemTime,
445 pub time_stamp: i64,
446 pub connect_time: Duration,
447 pub send_time: Duration,
448 pub destination: Destination,
449 pub is_xhr: bool,
450 pub browsing_context_id: BrowsingContextId,
451}
452
453#[derive(Debug, PartialEq, MallocSizeOf)]
454pub struct HttpResponse {
455 #[ignore_malloc_size_of = "Http type"]
456 pub headers: Option<HeaderMap>,
457 pub status: HttpStatus,
458 pub body: Option<DebugVec>,
459 pub from_cache: bool,
460 pub pipeline_id: PipelineId,
461 pub browsing_context_id: BrowsingContextId,
462}
463
464#[derive(Debug, PartialEq)]
465pub struct SecurityInfoUpdate {
466 pub browsing_context_id: BrowsingContextId,
467 pub security_info: Option<TlsSecurityInfo>,
468}
469
470#[derive(Debug)]
471pub enum NetworkEvent {
472 HttpRequest(HttpRequest),
473 HttpRequestUpdate(HttpRequest),
474 HttpResponse(HttpResponse),
475 SecurityInfo(SecurityInfoUpdate),
476}
477
478impl NetworkEvent {
479 pub fn forward_to_devtools(&self) -> bool {
480 match self {
481 NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
482 NetworkEvent::HttpRequestUpdate(_) => true,
483 NetworkEvent::HttpResponse(_) => true,
484 NetworkEvent::SecurityInfo(_) => true,
485 }
486 }
487}
488
489impl TimelineMarker {
490 pub fn start(name: String) -> StartedTimelineMarker {
491 StartedTimelineMarker {
492 name,
493 start_time: CrossProcessInstant::now(),
494 start_stack: None,
495 }
496 }
497}
498
499impl StartedTimelineMarker {
500 pub fn end(self) -> TimelineMarker {
501 TimelineMarker {
502 name: self.name,
503 start_time: self.start_time,
504 start_stack: self.start_stack,
505 end_time: CrossProcessInstant::now(),
506 end_stack: None,
507 }
508 }
509}
510#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
511pub struct WorkerId(pub Uuid);
512impl Display for WorkerId {
513 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
514 write!(f, "{}", self.0)
515 }
516}
517impl FromStr for WorkerId {
518 type Err = uuid::Error;
519
520 fn from_str(s: &str) -> Result<Self, Self::Err> {
521 Ok(Self(s.parse()?))
522 }
523}
524
525#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
526#[serde(rename_all = "camelCase")]
527pub struct CssDatabaseProperty {
528 pub is_inherited: bool,
529 pub values: Vec<String>,
530 pub supports: Vec<String>,
531 pub subproperties: Vec<String>,
532}
533
534#[derive(Debug, Deserialize, Serialize)]
535pub enum ShadowRootMode {
536 Open,
537 Closed,
538}
539
540impl fmt::Display for ShadowRootMode {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 match self {
543 Self::Open => write!(f, "open"),
544 Self::Closed => write!(f, "close"),
545 }
546 }
547}
548
549#[derive(Debug, Deserialize, Serialize)]
550pub struct SourceInfo {
551 pub url: ServoUrl,
552 pub introduction_type: String,
553 pub inline: bool,
554 pub worker_id: Option<WorkerId>,
555 pub content: Option<String>,
556 pub content_type: Option<String>,
557 pub spidermonkey_id: u32,
558}
559
560#[derive(Clone, Debug, Deserialize, Serialize)]
561#[serde(rename_all = "camelCase")]
562pub struct RecommendedBreakpointLocation {
563 pub script_id: u32,
564 pub offset: u32,
565 pub line_number: u32,
566 pub column_number: u32,
567 pub is_step_start: bool,
568}
569
570#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
571#[serde(rename_all = "camelCase")]
572pub struct PauseFrameResult {
573 pub column: u32,
574 pub display_name: String,
575 pub line: u32,
576 pub on_stack: bool,
577 pub oldest: bool,
578 pub terminated: bool,
579 #[serde(rename = "type")]
580 pub type_: String,
581 pub url: String,
582}
583
584#[derive(Clone, Debug, Deserialize, Serialize)]
585pub struct EventListenerInfo {
586 pub event_type: String,
587 pub capturing: bool,
588}