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 serde::{Deserialize, Serialize};
37use servo_url::ServoUrl;
38use uuid::Uuid;
39
40#[derive(Clone, Debug, Deserialize, Serialize)]
43pub struct DevtoolsPageInfo {
44 pub title: String,
45 pub url: ServoUrl,
46 pub is_top_level_global: bool,
47}
48
49#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
50pub struct CSSError {
51 pub filename: String,
52 pub line: u32,
53 pub column: u32,
54 pub msg: String,
55}
56
57#[derive(Debug)]
60pub enum DevtoolsControlMsg {
61 FromChrome(ChromeToDevtoolsControlMsg),
63 FromScript(ScriptToDevtoolsControlMsg),
65}
66
67#[expect(clippy::large_enum_variant)]
70#[derive(Debug)]
71pub enum ChromeToDevtoolsControlMsg {
72 AddClient(TcpStream),
74 ServerExitMsg,
76 NetworkEvent(String, NetworkEvent),
79}
80
81#[derive(Debug, Deserialize, Serialize)]
83pub enum NavigationState {
84 Start(ServoUrl),
86 Stop(PipelineId, DevtoolsPageInfo),
88}
89
90#[derive(Debug, Deserialize, Serialize)]
91pub enum ScriptToDevtoolsControlMsg {
93 NewGlobal(
96 (BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
97 GenericSender<DevtoolScriptControlMsg>,
98 DevtoolsPageInfo,
99 ),
100 Navigate(BrowsingContextId, NavigationState),
102 ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
104 ClearConsole(PipelineId, Option<WorkerId>),
106 FramerateTick(String, f64),
109
110 ReportCSSError(PipelineId, CSSError),
112
113 ReportPageError(PipelineId, PageError),
115
116 TitleChanged(PipelineId, String),
118
119 CreateSourceActor(
121 GenericSender<DevtoolScriptControlMsg>,
122 PipelineId,
123 SourceInfo,
124 ),
125
126 UpdateSourceContent(PipelineId, String),
127}
128
129#[derive(Debug, Deserialize, Serialize)]
132pub enum EvaluateJSReply {
133 VoidValue,
134 NullValue,
135 BooleanValue(bool),
136 NumberValue(f64),
137 StringValue(String),
138 ActorValue { class: String, uuid: String },
139}
140
141#[derive(Debug, Deserialize, Serialize)]
142pub struct AttrInfo {
143 pub namespace: String,
144 pub name: String,
145 pub value: String,
146}
147
148#[derive(Debug, Deserialize, Serialize)]
149#[serde(rename_all = "camelCase")]
150pub struct NodeInfo {
151 pub unique_id: String,
152 pub host: Option<String>,
153 #[serde(rename = "baseURI")]
154 pub base_uri: String,
155 pub parent: String,
156 pub node_type: u16,
157 pub node_name: String,
158 pub node_value: Option<String>,
159 pub num_children: usize,
160 pub attrs: Vec<AttrInfo>,
161 pub is_top_level_document: bool,
162 pub shadow_root_mode: Option<ShadowRootMode>,
163 pub is_shadow_host: bool,
164 pub display: Option<String>,
165 pub is_displayed: bool,
169
170 pub doctype_name: Option<String>,
172
173 pub doctype_public_identifier: Option<String>,
175
176 pub doctype_system_identifier: Option<String>,
178}
179
180pub struct StartedTimelineMarker {
181 name: String,
182 start_time: CrossProcessInstant,
183 start_stack: Option<Vec<()>>,
184}
185
186#[derive(Debug, Deserialize, Serialize)]
187pub struct TimelineMarker {
188 pub name: String,
189 pub start_time: CrossProcessInstant,
190 pub start_stack: Option<Vec<()>>,
191 pub end_time: CrossProcessInstant,
192 pub end_stack: Option<Vec<()>>,
193}
194
195#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
196pub enum TimelineMarkerType {
197 Reflow,
198 DOMEvent,
199}
200
201#[derive(Debug, Deserialize, Serialize)]
202#[serde(rename_all = "camelCase")]
203pub struct NodeStyle {
204 pub name: String,
205 pub value: String,
206 pub priority: String,
207}
208
209#[derive(Debug, Deserialize, Serialize)]
211#[serde(rename_all = "kebab-case")]
212pub struct ComputedNodeLayout {
213 pub display: String,
214 pub position: String,
215 pub z_index: String,
216 pub box_sizing: String,
217
218 pub margin_top: String,
219 pub margin_right: String,
220 pub margin_bottom: String,
221 pub margin_left: String,
222
223 pub border_top_width: String,
224 pub border_right_width: String,
225 pub border_bottom_width: String,
226 pub border_left_width: String,
227
228 pub padding_top: String,
229 pub padding_right: String,
230 pub padding_bottom: String,
231 pub padding_left: String,
232
233 pub width: f32,
234 pub height: f32,
235}
236
237#[derive(Debug, Default, Deserialize, Serialize)]
238pub struct AutoMargins {
239 pub top: bool,
240 pub right: bool,
241 pub bottom: bool,
242 pub left: bool,
243}
244
245#[derive(Debug, Deserialize, Serialize)]
248pub enum DevtoolScriptControlMsg {
249 EvaluateJS(PipelineId, String, GenericSender<EvaluateJSReply>),
251 GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
253 GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
255 GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
257 GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
259 GetStylesheetStyle(
261 PipelineId,
262 String,
263 String,
264 usize,
265 GenericSender<Option<Vec<NodeStyle>>>,
266 ),
267 GetSelectors(
270 PipelineId,
271 String,
272 GenericSender<Option<Vec<(String, usize)>>>,
273 ),
274 GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
276 GetLayout(
278 PipelineId,
279 String,
280 GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
281 ),
282 GetXPath(PipelineId, String, GenericSender<String>),
284 ModifyAttribute(PipelineId, String, Vec<AttrModification>),
286 ModifyRule(PipelineId, String, Vec<RuleModification>),
288 WantsLiveNotifications(PipelineId, bool),
290 SetTimelineMarkers(
292 PipelineId,
293 Vec<TimelineMarkerType>,
294 GenericSender<Option<TimelineMarker>>,
295 ),
296 DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
298 RequestAnimationFrame(PipelineId, String),
301 Reload(PipelineId),
303 GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
305 SimulateColorScheme(PipelineId, Theme),
307 HighlightDomNode(PipelineId, Option<String>),
309
310 GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
311 SetBreakpoint(u32, u32, u32),
312 ClearBreakpoint(u32, u32, u32),
313 Pause(GenericSender<PauseFrameResult>),
314}
315
316#[derive(Clone, Debug, Deserialize, Serialize)]
317#[serde(rename_all = "camelCase")]
318pub struct AttrModification {
319 pub attribute_name: String,
320 pub new_value: Option<String>,
321}
322
323#[derive(Clone, Debug, Deserialize, Serialize)]
324#[serde(rename_all = "camelCase")]
325pub struct RuleModification {
326 #[serde(rename = "type")]
327 pub type_: String,
328 pub index: u32,
329 pub name: String,
330 pub value: String,
331 pub priority: String,
332}
333
334#[derive(Clone, Debug, Deserialize, Serialize)]
335#[serde(rename_all = "camelCase")]
336pub struct StackFrame {
337 pub filename: String,
338 pub function_name: String,
339 pub column_number: u32,
340 pub line_number: u32,
341 }
344
345pub fn get_time_stamp() -> u64 {
346 SystemTime::now()
347 .duration_since(UNIX_EPOCH)
348 .unwrap_or_default()
349 .as_millis() as u64
350}
351
352#[derive(Clone, Debug, Deserialize, Serialize)]
353#[serde(rename_all = "camelCase")]
354pub struct ConsoleMessageFields {
355 pub level: ConsoleLogLevel,
356 pub filename: String,
357 pub line_number: u32,
358 pub column_number: u32,
359 pub time_stamp: u64,
360}
361
362#[derive(Clone, Debug, Deserialize, Serialize)]
363pub enum ConsoleArgument {
364 String(String),
365 Integer(i32),
366 Number(f64),
367}
368
369impl From<String> for ConsoleArgument {
370 fn from(value: String) -> Self {
371 Self::String(value)
372 }
373}
374
375#[derive(Clone, Debug, Deserialize, Serialize)]
376pub struct ConsoleMessage {
377 pub fields: ConsoleMessageFields,
378 pub arguments: Vec<ConsoleArgument>,
379 pub stacktrace: Option<Vec<StackFrame>>,
380}
381
382#[derive(Clone, Debug, Deserialize, Serialize)]
383#[serde(rename_all = "camelCase")]
384pub struct PageError {
385 pub error_message: String,
386 pub source_name: String,
387 pub line_number: u32,
388 pub column_number: u32,
389 pub time_stamp: u64,
390}
391
392#[derive(Debug, PartialEq)]
393pub struct HttpRequest {
394 pub url: ServoUrl,
395 pub method: Method,
396 pub headers: HeaderMap,
397 pub body: Option<DebugVec>,
398 pub pipeline_id: PipelineId,
399 pub started_date_time: SystemTime,
400 pub time_stamp: i64,
401 pub connect_time: Duration,
402 pub send_time: Duration,
403 pub destination: Destination,
404 pub is_xhr: bool,
405 pub browsing_context_id: BrowsingContextId,
406}
407
408#[derive(Debug, PartialEq)]
409pub struct HttpResponse {
410 pub headers: Option<HeaderMap>,
411 pub status: HttpStatus,
412 pub body: Option<DebugVec>,
413 pub from_cache: bool,
414 pub pipeline_id: PipelineId,
415 pub browsing_context_id: BrowsingContextId,
416}
417
418#[derive(Debug, PartialEq)]
419pub struct SecurityInfoUpdate {
420 pub browsing_context_id: BrowsingContextId,
421 pub security_info: Option<TlsSecurityInfo>,
422}
423
424#[derive(Debug)]
425pub enum NetworkEvent {
426 HttpRequest(HttpRequest),
427 HttpRequestUpdate(HttpRequest),
428 HttpResponse(HttpResponse),
429 SecurityInfo(SecurityInfoUpdate),
430}
431
432impl NetworkEvent {
433 pub fn forward_to_devtools(&self) -> bool {
434 match self {
435 NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
436 NetworkEvent::HttpRequestUpdate(_) => true,
437 NetworkEvent::HttpResponse(_) => true,
438 NetworkEvent::SecurityInfo(_) => true,
439 }
440 }
441}
442
443impl TimelineMarker {
444 pub fn start(name: String) -> StartedTimelineMarker {
445 StartedTimelineMarker {
446 name,
447 start_time: CrossProcessInstant::now(),
448 start_stack: None,
449 }
450 }
451}
452
453impl StartedTimelineMarker {
454 pub fn end(self) -> TimelineMarker {
455 TimelineMarker {
456 name: self.name,
457 start_time: self.start_time,
458 start_stack: self.start_stack,
459 end_time: CrossProcessInstant::now(),
460 end_stack: None,
461 }
462 }
463}
464#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
465pub struct WorkerId(pub Uuid);
466impl Display for WorkerId {
467 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468 write!(f, "{}", self.0)
469 }
470}
471impl FromStr for WorkerId {
472 type Err = uuid::Error;
473
474 fn from_str(s: &str) -> Result<Self, Self::Err> {
475 Ok(Self(s.parse()?))
476 }
477}
478
479#[derive(Debug, Deserialize, Serialize)]
480#[serde(rename_all = "camelCase")]
481pub struct CssDatabaseProperty {
482 pub is_inherited: bool,
483 pub values: Vec<String>,
484 pub supports: Vec<String>,
485 pub subproperties: Vec<String>,
486}
487
488#[derive(Debug, Deserialize, Serialize)]
489pub enum ShadowRootMode {
490 Open,
491 Closed,
492}
493
494impl fmt::Display for ShadowRootMode {
495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
496 match self {
497 Self::Open => write!(f, "open"),
498 Self::Closed => write!(f, "close"),
499 }
500 }
501}
502
503#[derive(Debug, Deserialize, Serialize)]
504pub struct SourceInfo {
505 pub url: ServoUrl,
506 pub introduction_type: String,
507 pub inline: bool,
508 pub worker_id: Option<WorkerId>,
509 pub content: Option<String>,
510 pub content_type: Option<String>,
511 pub spidermonkey_id: u32,
512}
513
514#[derive(Clone, Debug, Deserialize, Serialize)]
515#[serde(rename_all = "camelCase")]
516pub struct RecommendedBreakpointLocation {
517 pub script_id: u32,
518 pub offset: u32,
519 pub line_number: u32,
520 pub column_number: u32,
521 pub is_step_start: bool,
522}
523
524#[derive(Clone, Debug, Deserialize, Serialize)]
525#[serde(rename_all = "camelCase")]
526pub struct PauseFrameResult {
527 pub column: u32,
528 pub display_name: String,
529 pub line: u32,
530 pub on_stack: bool,
531 pub oldest: bool,
532 pub terminated: bool,
533 #[serde(rename = "type")]
534 pub type_: String,
535 pub url: String,
536}