Skip to main content

devtools_traits/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! This module contains shared types and messages for use by devtools/script.
6//! The traits are here instead of in script so that the devtools crate can be
7//! modified independently of the rest of Servo.
8//!
9//! Since these types can be sent through the IPC channel and use non
10//! self-describing serializers, the `flatten`, `skip*`, `tag` and `untagged`
11//! serde annotations are not supported. Types like `serde_json::Value` aren't
12//! supported either. For JSON serialization it is preferred to use a wrapper
13//! struct in the devtools crate instead.
14
15#![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::de::{Error, Visitor};
35use serde::{Deserialize, Serialize};
36use servo_base::cross_process_instant::CrossProcessInstant;
37use servo_base::generic_channel::GenericSender;
38use servo_base::id::{BrowsingContextId, PipelineId, WebViewId};
39use servo_url::ServoUrl;
40use uuid::Uuid;
41
42// Information would be attached to NewGlobal to be received and show in devtools.
43// Extend these fields if we need more information.
44#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
45pub struct DevtoolsPageInfo {
46    pub title: String,
47    pub url: ServoUrl,
48    pub is_top_level_global: bool,
49    pub is_service_worker: bool,
50}
51
52#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
53pub struct CSSError {
54    pub filename: String,
55    pub line: u32,
56    pub column: u32,
57    pub msg: String,
58}
59
60/// Messages to instruct the devtools server to update its known actors/state
61/// according to changes in the browser.
62#[derive(Debug)]
63pub enum DevtoolsControlMsg {
64    /// Messages from threads in the chrome process (resource/constellation/devtools)
65    FromChrome(ChromeToDevtoolsControlMsg),
66    /// Messages from script threads
67    FromScript(ScriptToDevtoolsControlMsg),
68    /// Sent when a devtools client thread terminates.
69    ClientExited,
70}
71
72/// Events that the devtools server must act upon.
73// FIXME: https://github.com/servo/servo/issues/34591
74#[expect(clippy::large_enum_variant)]
75#[derive(Debug)]
76pub enum ChromeToDevtoolsControlMsg {
77    /// A new client has connected to the server.
78    AddClient(TcpStream),
79    /// The browser is shutting down.
80    ServerExitMsg,
81    /// A network event occurred (request, reply, etc.). The actor with the
82    /// provided name should be notified.
83    NetworkEvent(String, NetworkEvent),
84    /// Perform a memory report.
85    CollectMemoryReport(ReportsChan),
86}
87
88/// The state of a page navigation.
89#[derive(Debug, Deserialize, Serialize)]
90pub enum NavigationState {
91    /// A browsing context is about to navigate to a given URL.
92    Start(ServoUrl),
93    /// A browsing context has completed navigating to the provided pipeline.
94    Stop(PipelineId, DevtoolsPageInfo),
95}
96
97#[derive(Debug, Deserialize, Serialize)]
98/// Events that the devtools server must act upon.
99pub enum ScriptToDevtoolsControlMsg {
100    /// A new global object was created, associated with a particular pipeline.
101    /// The means of communicating directly with it are provided.
102    NewGlobal(
103        (BrowsingContextId, PipelineId, Option<WorkerId>, WebViewId),
104        GenericSender<DevtoolScriptControlMsg>,
105        DevtoolsPageInfo,
106    ),
107    /// The given browsing context is performing a navigation.
108    Navigate(BrowsingContextId, NavigationState),
109    /// A particular page has invoked the console API.
110    ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
111    /// Request to clear the console for a given pipeline.
112    ClearConsole(PipelineId, Option<WorkerId>),
113    /// An animation frame with the given timestamp was processed in a script thread.
114    /// The actor with the provided name should be notified.
115    FramerateTick(String, f64),
116
117    /// Report a CSS parse error for the given pipeline
118    ReportCSSError(PipelineId, CSSError),
119
120    /// Report a page error for the given pipeline
121    ReportPageError(PipelineId, PageError),
122
123    /// Report a page title change
124    TitleChanged(PipelineId, String),
125
126    /// Get source information from script
127    CreateSourceActor(
128        GenericSender<DevtoolScriptControlMsg>,
129        PipelineId,
130        SourceInfo,
131    ),
132
133    UpdateSourceContent(PipelineId, String),
134
135    DomMutation(PipelineId, DomMutation),
136
137    /// The debugger is paused, sending frame information.
138    DebuggerPause(PipelineId, FrameOffset, PauseReason),
139
140    /// Get frame information from script
141    CreateFrameActor(GenericSender<String>, PipelineId, FrameInfo),
142
143    /// Get object information from script
144    CreateObjectActor(GenericSender<String>, DebuggerValue),
145
146    /// Get environment information from script
147    CreateEnvironmentActor(
148        GenericSender<String>,
149        EnvironmentInfo,
150        Option<String>,
151        Option<String>,
152    ),
153}
154
155#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
156pub enum DomMutation {
157    AttributeModified {
158        node: String,
159        attribute_name: String,
160        new_value: Option<String>,
161    },
162}
163
164#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
165#[serde(rename_all = "camelCase")]
166pub struct ObjectPreview {
167    pub kind: String,
168    pub size: Option<u32>,
169    pub entries: Option<Vec<(DebuggerValue, DebuggerValue)>>,
170    pub own_properties: Option<Vec<PropertyDescriptor>>,
171    pub own_properties_length: Option<u32>,
172    pub function: Option<FunctionPreview>,
173    pub array_length: Option<u32>,
174    pub items: Option<Vec<DebuggerValue>>,
175}
176
177#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
178#[serde(rename_all = "camelCase")]
179pub struct FunctionPreview {
180    pub name: Option<String>,
181    pub display_name: Option<String>,
182    pub parameter_names: Vec<String>,
183    pub is_async: Option<bool>,
184    pub is_generator: Option<bool>,
185}
186
187struct DebuggerNumberVisitor;
188
189impl Visitor<'_> for DebuggerNumberVisitor {
190    type Value = f64;
191
192    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
193        formatter.write_str("a debugger value number")
194    }
195
196    fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E> {
197        Ok(value)
198    }
199
200    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> {
201        Ok(value as f64)
202    }
203
204    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> {
205        Ok(value as f64)
206    }
207
208    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
209    where
210        E: Error,
211    {
212        value.parse().map_err(E::custom)
213    }
214}
215
216fn deserialize_debugger_number<'de, D>(deserializer: D) -> Result<f64, D::Error>
217where
218    D: serde::Deserializer<'de>,
219{
220    // `DebuggerValue` is also sent over Servo IPC, not only through debugger.js.
221    if !deserializer.is_human_readable() {
222        return f64::deserialize(deserializer);
223    }
224
225    deserializer.deserialize_any(DebuggerNumberVisitor)
226}
227
228#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
229#[serde(rename_all_fields = "camelCase")]
230pub enum DebuggerValue {
231    VoidValue,
232    NullValue(bool),
233    BooleanValue(bool),
234    NumberValue(#[serde(deserialize_with = "deserialize_debugger_number")] f64),
235    StringValue(String),
236    ObjectValue {
237        actor: Option<String>,
238        class: String,
239        own_property_length: Option<u32>,
240        preview: Option<Box<ObjectPreview>>,
241    },
242}
243
244/// <https://searchfox.org/mozilla-central/source/devtools/server/actors/object/property-iterator.js#51>
245#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
246#[serde(rename_all = "camelCase")]
247pub struct PropertyDescriptor {
248    pub name: String,
249    pub value: DebuggerValue,
250    pub configurable: bool,
251    pub enumerable: bool,
252    pub writable: bool,
253    pub is_accessor: bool,
254}
255
256#[derive(Debug, Deserialize, Serialize)]
257#[serde(rename_all = "camelCase")]
258pub struct EvaluateJSReply {
259    pub value: DebuggerValue,
260    pub exception_message: Option<String>,
261    pub has_exception: bool,
262}
263
264#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
265pub struct AttrInfo {
266    pub namespace: String,
267    pub name: String,
268    pub value: String,
269}
270
271#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
272#[serde(rename_all = "camelCase")]
273pub struct NodeInfo {
274    pub unique_id: String,
275    pub host: Option<String>,
276    #[serde(rename = "baseURI")]
277    pub base_uri: String,
278    pub parent: String,
279    pub node_type: u16,
280    pub node_name: String,
281    pub node_value: Option<String>,
282    pub num_children: usize,
283    pub attrs: Vec<AttrInfo>,
284    pub is_top_level_document: bool,
285    pub shadow_root_mode: Option<ShadowRootMode>,
286    pub is_shadow_host: bool,
287    pub display: Option<String>,
288    /// Whether this node is currently displayed.
289    ///
290    /// For example, the node might have `display: none`.
291    pub is_displayed: bool,
292
293    /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise
294    pub doctype_name: Option<String>,
295
296    /// The `DOCTYPE` public identifier if this is a `DocumentType` node , `None` otherwise
297    pub doctype_public_identifier: Option<String>,
298
299    /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise
300    pub doctype_system_identifier: Option<String>,
301
302    pub has_event_listeners: bool,
303}
304
305pub struct StartedTimelineMarker {
306    name: String,
307    start_time: CrossProcessInstant,
308    start_stack: Option<Vec<()>>,
309}
310
311#[derive(Debug, Deserialize, Serialize)]
312pub struct TimelineMarker {
313    pub name: String,
314    pub start_time: CrossProcessInstant,
315    pub start_stack: Option<Vec<()>>,
316    pub end_time: CrossProcessInstant,
317    pub end_stack: Option<Vec<()>>,
318}
319
320#[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
321pub enum TimelineMarkerType {
322    Reflow,
323    DOMEvent,
324}
325
326#[derive(Debug, Deserialize, Serialize)]
327#[serde(rename_all = "camelCase")]
328pub struct NodeStyle {
329    pub name: String,
330    pub value: String,
331    pub priority: String,
332}
333
334#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
335#[serde(tag = "type", rename_all = "camelCase")]
336pub enum AncestorData {
337    Layer {
338        actor_id: Option<String>,
339        value: Option<String>,
340    },
341}
342
343#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf, PartialEq, Eq, Hash)]
344#[serde(rename_all = "camelCase")]
345pub struct MatchedRule {
346    pub selector: String,
347    pub stylesheet_index: usize,
348    pub block_id: usize,
349    pub ancestor_data: Vec<AncestorData>,
350}
351
352/// The properties of a DOM node as computed by layout.
353#[derive(Debug, Deserialize, Serialize)]
354#[serde(rename_all = "kebab-case")]
355pub struct ComputedNodeLayout {
356    pub display: String,
357    pub position: String,
358    pub z_index: String,
359    pub box_sizing: String,
360
361    pub margin_top: String,
362    pub margin_right: String,
363    pub margin_bottom: String,
364    pub margin_left: String,
365
366    pub border_top_width: String,
367    pub border_right_width: String,
368    pub border_bottom_width: String,
369    pub border_left_width: String,
370
371    pub padding_top: String,
372    pub padding_right: String,
373    pub padding_bottom: String,
374    pub padding_left: String,
375
376    pub width: f32,
377    pub height: f32,
378}
379
380#[derive(Debug, Default, Deserialize, Serialize)]
381pub struct AutoMargins {
382    pub top: bool,
383    pub right: bool,
384    pub bottom: bool,
385    pub left: bool,
386}
387
388#[derive(Debug, Deserialize, Serialize)]
389pub enum GetHTMLType {
390    OuterHTML,
391    InnerHTML,
392}
393
394/// Messages to process in a particular script thread, as instructed by a devtools client.
395/// TODO: better error handling, e.g. if pipeline id lookup fails?
396#[derive(Debug, Deserialize, Serialize)]
397pub enum DevtoolScriptControlMsg {
398    /// Retrieve the details of the root node (ie. the document) for the given pipeline.
399    GetRootNode(PipelineId, GenericSender<Option<NodeInfo>>),
400    /// Retrieve the details of the document element for the given pipeline.
401    GetDocumentElement(PipelineId, GenericSender<Option<NodeInfo>>),
402    /// Retrieve the details of the child nodes of the given node in the given pipeline.
403    GetChildren(PipelineId, String, GenericSender<Option<Vec<NodeInfo>>>),
404    /// Retrieve the CSS style properties defined in the attribute tag for the given node.
405    GetAttributeStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
406    /// Retrieve the CSS style properties defined in an stylesheet for the given selector.
407    GetStylesheetStyle(
408        PipelineId,
409        String,
410        MatchedRule,
411        GenericSender<Option<Vec<NodeStyle>>>,
412    ),
413    /// Retrieve the list of stylesheets for the given pipeline and node.
414    GetStyleSheets(PipelineId, GenericSender<Vec<StyleSheetInfo>>),
415    /// Retrieve the actual CSS text for the stylesheet with the given node ID and index.
416    GetStyleSheetText(PipelineId, i32, GenericSender<Option<String>>),
417    /// Retrieves the CSS selectors for the given node. A selector is comprised of the text
418    /// of the selector and the id of the stylesheet that contains it.
419    GetSelectors(PipelineId, String, GenericSender<Option<Vec<MatchedRule>>>),
420    /// Retrieve the computed CSS style properties for the given node.
421    GetComputedStyle(PipelineId, String, GenericSender<Option<Vec<NodeStyle>>>),
422    /// Get information about event listeners on a node.
423    GetEventListenerInfo(PipelineId, String, GenericSender<Vec<EventListenerInfo>>),
424    /// Retrieve the computed layout properties of the given node in the given pipeline.
425    GetLayout(
426        PipelineId,
427        String,
428        GenericSender<Option<(ComputedNodeLayout, AutoMargins)>>,
429    ),
430    /// Get a unique XPath selector for the node.
431    GetXPath(PipelineId, String, GenericSender<String>),
432    /// Get inner/outer HTML on a node.
433    GetInnerOrOuterHTML(
434        PipelineId,
435        String,
436        GenericSender<Option<String>>,
437        GetHTMLType,
438    ),
439    /// Update a given node's attributes with a list of modifications.
440    ModifyAttribute(PipelineId, String, Vec<AttrModification>),
441    /// Update a given node's style rules with a list of modifications.
442    ModifyRule(PipelineId, String, Vec<RuleModification>),
443    /// Request live console messages for a given pipeline (true if desired, false otherwise).
444    WantsLiveNotifications(PipelineId, bool),
445    /// Request live notifications for a given set of timeline events for a given pipeline.
446    SetTimelineMarkers(
447        PipelineId,
448        Vec<TimelineMarkerType>,
449        GenericSender<Option<TimelineMarker>>,
450    ),
451    /// Withdraw request for live timeline notifications for a given pipeline.
452    DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
453    /// Request a callback directed at the given actor name from the next animation frame
454    /// executed in the given pipeline.
455    RequestAnimationFrame(PipelineId, String),
456    /// Direct the WebView containing the given pipeline to load a new URL,
457    /// as if it was typed by the user.
458    NavigateTo(PipelineId, ServoUrl),
459    /// Direct the WebView containing the given pipeline to traverse history backward
460    /// up to one step.
461    GoBack(PipelineId),
462    /// Direct the WebView containing the given pipeline to traverse history forward
463    /// up to one step.
464    GoForward(PipelineId),
465    /// Direct the given pipeline to reload the current page.
466    Reload(PipelineId),
467    /// Gets the list of all allowed CSS rules and possible values.
468    GetCssDatabase(GenericSender<HashMap<String, CssDatabaseProperty>>),
469    /// Simulates a light or dark color scheme for the given pipeline
470    SimulateColorScheme(PipelineId, Theme),
471    /// Highlight the given DOM node
472    HighlightDomNode(PipelineId, Option<String>),
473
474    Eval(
475        String,
476        PipelineId,
477        Option<String>,
478        GenericSender<EvaluateJSReply>,
479    ),
480    GetPossibleBreakpoints(u32, GenericSender<Vec<RecommendedBreakpointLocation>>),
481    SetBreakpoint(u32, u32, u32),
482    ClearBreakpoint(u32, u32, u32),
483    Interrupt,
484    Resume(Option<String>, Option<String>),
485    ListFrames(PipelineId, u32, u32, GenericSender<Vec<String>>),
486    GetEnvironment(GetEnvironmentRequest, GenericSender<String>),
487    Blackbox(u32, BlackboxCoverage),
488    Unblackbox(u32, BlackboxCoverage),
489}
490
491#[derive(Debug, Deserialize, Serialize)]
492pub enum GetEnvironmentRequest {
493    Global(PipelineId),
494    Frame(String),
495}
496
497#[derive(Debug, Deserialize, Serialize)]
498pub enum BlackboxCoverage {
499    Full,
500    Partial((u32, u32), (u32, u32)),
501}
502
503#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
504#[serde(rename_all = "camelCase")]
505pub struct AttrModification {
506    pub attribute_name: String,
507    pub new_value: Option<String>,
508}
509
510#[derive(Clone, Debug, Deserialize, Serialize)]
511#[serde(rename_all = "camelCase")]
512pub struct RuleModification {
513    #[serde(rename = "type")]
514    pub type_: String,
515    pub index: u32,
516    pub name: String,
517    pub value: String,
518    pub priority: String,
519}
520
521#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
522#[serde(rename_all = "camelCase")]
523pub struct StackFrame {
524    pub filename: String,
525    pub function_name: String,
526    pub column_number: u32,
527    pub line_number: u32,
528    // Not implemented in Servo
529    // source_id
530}
531
532pub fn get_time_stamp() -> u64 {
533    SystemTime::now()
534        .duration_since(UNIX_EPOCH)
535        .unwrap_or_default()
536        .as_millis() as u64
537}
538
539#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
540#[serde(rename_all = "camelCase")]
541pub struct ConsoleMessageFields {
542    pub level: ConsoleLogLevel,
543    pub filename: String,
544    pub line_number: u32,
545    pub column_number: u32,
546    pub time_stamp: u64,
547}
548
549#[derive(Clone, Debug, Deserialize, Serialize)]
550pub struct ConsoleMessage {
551    pub fields: ConsoleMessageFields,
552    pub arguments: Vec<DebuggerValue>,
553    pub stacktrace: Option<Vec<StackFrame>>,
554}
555
556#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
557#[serde(rename_all = "camelCase")]
558pub struct PageError {
559    pub error_message: String,
560    pub source_name: String,
561    pub line_number: u32,
562    pub column_number: u32,
563    pub time_stamp: u64,
564}
565
566#[derive(Debug, PartialEq, MallocSizeOf)]
567pub struct HttpRequest {
568    pub url: ServoUrl,
569    pub method: Method,
570    pub headers: HeaderMap,
571    pub body: Option<DebugVec>,
572    pub pipeline_id: PipelineId,
573    pub started_date_time: SystemTime,
574    pub time_stamp: i64,
575    pub connect_time: Duration,
576    pub send_time: Duration,
577    pub destination: Destination,
578    pub is_xhr: bool,
579    pub browsing_context_id: BrowsingContextId,
580}
581
582#[derive(Debug, PartialEq, MallocSizeOf)]
583pub struct HttpResponse {
584    #[ignore_malloc_size_of = "Http type"]
585    pub headers: Option<HeaderMap>,
586    pub status: HttpStatus,
587    pub body: Option<DebugVec>,
588    pub from_cache: bool,
589    pub pipeline_id: PipelineId,
590    pub browsing_context_id: BrowsingContextId,
591}
592
593#[derive(Debug, PartialEq)]
594pub struct SecurityInfoUpdate {
595    pub browsing_context_id: BrowsingContextId,
596    pub security_info: Option<TlsSecurityInfo>,
597}
598
599#[derive(Debug)]
600pub enum NetworkEvent {
601    HttpRequest(HttpRequest),
602    HttpRequestUpdate(HttpRequest),
603    HttpResponse(HttpResponse),
604    SecurityInfo(SecurityInfoUpdate),
605}
606
607impl NetworkEvent {
608    pub fn forward_to_devtools(&self) -> bool {
609        match self {
610            NetworkEvent::HttpRequest(http_request) => http_request.url.scheme() != "data",
611            NetworkEvent::HttpRequestUpdate(_) => true,
612            NetworkEvent::HttpResponse(_) => true,
613            NetworkEvent::SecurityInfo(_) => true,
614        }
615    }
616}
617
618impl TimelineMarker {
619    pub fn start(name: String) -> StartedTimelineMarker {
620        StartedTimelineMarker {
621            name,
622            start_time: CrossProcessInstant::now(),
623            start_stack: None,
624        }
625    }
626}
627
628impl StartedTimelineMarker {
629    pub fn end(self) -> TimelineMarker {
630        TimelineMarker {
631            name: self.name,
632            start_time: self.start_time,
633            start_stack: self.start_stack,
634            end_time: CrossProcessInstant::now(),
635            end_stack: None,
636        }
637    }
638}
639#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
640pub struct WorkerId(pub Uuid);
641impl Display for WorkerId {
642    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
643        write!(f, "{}", self.0)
644    }
645}
646impl FromStr for WorkerId {
647    type Err = uuid::Error;
648
649    fn from_str(s: &str) -> Result<Self, Self::Err> {
650        Ok(Self(s.parse()?))
651    }
652}
653
654#[derive(Debug, Deserialize, Serialize, MallocSizeOf)]
655#[serde(rename_all = "camelCase")]
656pub struct CssDatabaseProperty {
657    pub is_inherited: bool,
658    pub values: Vec<String>,
659    pub supports: Vec<String>,
660    pub subproperties: Vec<String>,
661}
662
663#[derive(Debug, Deserialize, MallocSizeOf, Serialize)]
664pub enum ShadowRootMode {
665    Open,
666    Closed,
667}
668
669impl fmt::Display for ShadowRootMode {
670    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
671        match self {
672            Self::Open => write!(f, "open"),
673            Self::Closed => write!(f, "close"),
674        }
675    }
676}
677
678#[derive(Debug, Deserialize, Serialize)]
679pub struct SourceInfo {
680    pub url: ServoUrl,
681    pub introduction_type: String,
682    pub inline: bool,
683    pub worker_id: Option<WorkerId>,
684    pub content: Option<String>,
685    pub content_type: Option<String>,
686    pub spidermonkey_id: u32,
687}
688
689#[derive(Clone, Debug, Deserialize, Serialize)]
690#[serde(rename_all = "camelCase")]
691pub struct RecommendedBreakpointLocation {
692    pub script_id: u32,
693    pub offset: u32,
694    pub line_number: u32,
695    pub column_number: u32,
696    pub is_step_start: bool,
697}
698
699#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
700pub struct FrameInfo {
701    pub display_name: Option<String>,
702    pub on_stack: bool,
703    pub oldest: bool,
704    pub this_value: DebuggerValue,
705    pub terminated: bool,
706    pub type_: String,
707    pub url: String,
708}
709
710#[derive(Clone, Debug, Default, Deserialize, MallocSizeOf, Serialize)]
711pub struct EnvironmentInfo {
712    pub type_: Option<String>,
713    pub scope_kind: Option<String>,
714    pub function_display_name: Option<String>,
715    pub object: Option<DebuggerValue>,
716    pub binding_variables: Vec<PropertyDescriptor>,
717}
718
719#[derive(Clone, Debug, Deserialize, Serialize)]
720pub struct StyleSheetInfo {
721    pub href: Option<String>,
722    pub disabled: bool,
723    pub title: String,
724    pub style_sheet_index: i32,
725    pub system: bool,
726    pub rule_count: u32,
727}
728
729#[derive(Clone, Debug, Deserialize, Serialize)]
730pub struct EventListenerInfo {
731    pub event_type: String,
732    pub capturing: bool,
733}
734
735#[derive(Debug, Deserialize, Serialize)]
736#[serde(rename_all = "camelCase")]
737pub struct PauseReason {
738    #[serde(rename = "type")]
739    pub type_: String,
740    pub on_next: Option<bool>,
741}
742
743#[derive(Debug, Deserialize, Serialize)]
744pub struct FrameOffset {
745    pub actor: String,
746    pub column: u32,
747    pub line: u32,
748}