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 http://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 #![crate_name = "devtools_traits"]
10 #![crate_type = "rlib"]
11 
12 #![allow(non_snake_case)]
13 #![deny(unsafe_code)]
14 
15 #[macro_use]
16 extern crate bitflags;
17 extern crate hyper;
18 extern crate ipc_channel;
19 extern crate malloc_size_of;
20 #[macro_use] extern crate malloc_size_of_derive;
21 extern crate msg;
22 #[macro_use] extern crate serde;
23 extern crate servo_url;
24 extern crate time;
25 
26 use hyper::header::Headers;
27 use hyper::method::Method;
28 use ipc_channel::ipc::IpcSender;
29 use msg::constellation_msg::PipelineId;
30 use servo_url::ServoUrl;
31 use std::net::TcpStream;
32 use time::Duration;
33 use time::Tm;
34 
35 // Information would be attached to NewGlobal to be received and show in devtools.
36 // Extend these fields if we need more information.
37 #[derive(Debug, Deserialize, Serialize)]
38 pub struct DevtoolsPageInfo {
39     pub title: String,
40     pub url: ServoUrl,
41 }
42 
43 #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
44 pub struct CSSError {
45     pub filename: String,
46     pub line: u32,
47     pub column: u32,
48     pub msg: String
49 }
50 
51 /// Messages to instruct the devtools server to update its known actors/state
52 /// according to changes in the browser.
53 #[derive(Debug)]
54 pub enum DevtoolsControlMsg {
55     /// Messages from threads in the chrome process (resource/constellation/devtools)
56     FromChrome(ChromeToDevtoolsControlMsg),
57     /// Messages from script threads
58     FromScript(ScriptToDevtoolsControlMsg),
59 }
60 
61 /// Events that the devtools server must act upon.
62 #[derive(Debug)]
63 pub enum ChromeToDevtoolsControlMsg {
64     /// A new client has connected to the server.
65     AddClient(TcpStream),
66     /// The browser is shutting down.
67     ServerExitMsg,
68     /// A network event occurred (request, reply, etc.). The actor with the
69     /// provided name should be notified.
70     NetworkEvent(String, NetworkEvent),
71 }
72 
73 #[derive(Debug, Deserialize, Serialize)]
74 /// Events that the devtools server must act upon.
75 pub enum ScriptToDevtoolsControlMsg {
76     /// A new global object was created, associated with a particular pipeline.
77     /// The means of communicating directly with it are provided.
78     NewGlobal((PipelineId, Option<WorkerId>),
79               IpcSender<DevtoolScriptControlMsg>,
80               DevtoolsPageInfo),
81     /// A particular page has invoked the console API.
82     ConsoleAPI(PipelineId, ConsoleMessage, Option<WorkerId>),
83     /// An animation frame with the given timestamp was processed in a script thread.
84     /// The actor with the provided name should be notified.
85     FramerateTick(String, f64),
86 
87     /// Report a CSS parse error for the given pipeline
88     ReportCSSError(PipelineId, CSSError),
89 }
90 
91 /// Serialized JS return values
92 /// TODO: generalize this beyond the EvaluateJS message?
93 #[derive(Debug, Deserialize, Serialize)]
94 pub enum EvaluateJSReply {
95     VoidValue,
96     NullValue,
97     BooleanValue(bool),
98     NumberValue(f64),
99     StringValue(String),
100     ActorValue { class: String, uuid: String },
101 }
102 
103 #[derive(Debug, Deserialize, Serialize)]
104 pub struct AttrInfo {
105     pub namespace: String,
106     pub name: String,
107     pub value: String,
108 }
109 
110 #[derive(Debug, Deserialize, Serialize)]
111 pub struct NodeInfo {
112     pub uniqueId: String,
113     pub baseURI: String,
114     pub parent: String,
115     pub nodeType: u16,
116     pub namespaceURI: String,
117     pub nodeName: String,
118     pub numChildren: usize,
119 
120     pub name: String,
121     pub publicId: String,
122     pub systemId: String,
123 
124     pub attrs: Vec<AttrInfo>,
125 
126     pub isDocumentElement: bool,
127 
128     pub shortValue: String,
129     pub incompleteValue: bool,
130 }
131 
132 pub struct StartedTimelineMarker {
133     name: String,
134     start_time: PreciseTime,
135     start_stack: Option<Vec<()>>,
136 }
137 
138 #[derive(Debug, Deserialize, Serialize)]
139 pub struct TimelineMarker {
140     pub name: String,
141     pub start_time: PreciseTime,
142     pub start_stack: Option<Vec<()>>,
143     pub end_time: PreciseTime,
144     pub end_stack: Option<Vec<()>>,
145 }
146 
147 #[derive(Clone, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
148 pub enum TimelineMarkerType {
149     Reflow,
150     DOMEvent,
151 }
152 
153 /// The properties of a DOM node as computed by layout.
154 #[derive(Debug, Deserialize, Serialize)]
155 pub struct ComputedNodeLayout {
156     pub display: String,
157     pub position: String,
158     pub zIndex: String,
159     pub boxSizing: String,
160 
161     pub autoMargins: AutoMargins,
162     pub marginTop: String,
163     pub marginRight: String,
164     pub marginBottom: String,
165     pub marginLeft: String,
166 
167     pub borderTopWidth: String,
168     pub borderRightWidth: String,
169     pub borderBottomWidth: String,
170     pub borderLeftWidth: String,
171 
172     pub paddingTop: String,
173     pub paddingRight: String,
174     pub paddingBottom: String,
175     pub paddingLeft: String,
176 
177     pub width: f32,
178     pub height: f32,
179 }
180 
181 #[derive(Debug, Deserialize, Serialize)]
182 pub struct AutoMargins {
183     pub top: bool,
184     pub right: bool,
185     pub bottom: bool,
186     pub left: bool,
187 }
188 
189 /// Messages to process in a particular script thread, as instructed by a devtools client.
190 /// TODO: better error handling, e.g. if pipeline id lookup fails?
191 #[derive(Debug, Deserialize, Serialize)]
192 pub enum DevtoolScriptControlMsg {
193     /// Evaluate a JS snippet in the context of the global for the given pipeline.
194     EvaluateJS(PipelineId, String, IpcSender<EvaluateJSReply>),
195     /// Retrieve the details of the root node (ie. the document) for the given pipeline.
196     GetRootNode(PipelineId, IpcSender<Option<NodeInfo>>),
197     /// Retrieve the details of the document element for the given pipeline.
198     GetDocumentElement(PipelineId, IpcSender<Option<NodeInfo>>),
199     /// Retrieve the details of the child nodes of the given node in the given pipeline.
200     GetChildren(PipelineId, String, IpcSender<Option<Vec<NodeInfo>>>),
201     /// Retrieve the computed layout properties of the given node in the given pipeline.
202     GetLayout(PipelineId, String, IpcSender<Option<ComputedNodeLayout>>),
203     /// Retrieve all stored console messages for the given pipeline.
204     GetCachedMessages(PipelineId, CachedConsoleMessageTypes, IpcSender<Vec<CachedConsoleMessage>>),
205     /// Update a given node's attributes with a list of modifications.
206     ModifyAttribute(PipelineId, String, Vec<Modification>),
207     /// Request live console messages for a given pipeline (true if desired, false otherwise).
208     WantsLiveNotifications(PipelineId, bool),
209     /// Request live notifications for a given set of timeline events for a given pipeline.
210     SetTimelineMarkers(PipelineId, Vec<TimelineMarkerType>, IpcSender<Option<TimelineMarker>>),
211     /// Withdraw request for live timeline notifications for a given pipeline.
212     DropTimelineMarkers(PipelineId, Vec<TimelineMarkerType>),
213     /// Request a callback directed at the given actor name from the next animation frame
214     /// executed in the given pipeline.
215     RequestAnimationFrame(PipelineId, String),
216     /// Direct the given pipeline to reload the current page.
217     Reload(PipelineId),
218 }
219 
220 #[derive(Debug, Deserialize, Serialize)]
221 pub struct Modification {
222     pub attributeName: String,
223     pub newValue: Option<String>,
224 }
225 
226 #[derive(Clone, Debug, Deserialize, Serialize)]
227 pub enum LogLevel {
228     Log,
229     Debug,
230     Info,
231     Warn,
232     Error,
233 }
234 
235 #[derive(Clone, Debug, Deserialize, Serialize)]
236 pub struct ConsoleMessage {
237     pub message: String,
238     pub logLevel: LogLevel,
239     pub filename: String,
240     pub lineNumber: usize,
241     pub columnNumber: usize,
242 }
243 
244 bitflags! {
245     #[derive(Deserialize, Serialize)]
246     pub struct CachedConsoleMessageTypes: u8 {
247         const PAGE_ERROR  = 1 << 0;
248         const CONSOLE_API = 1 << 1;
249     }
250 }
251 
252 #[derive(Debug, Deserialize, Serialize)]
253 pub struct PageError {
254     #[serde(rename = "_type")]
255     pub type_: String,
256     pub errorMessage: String,
257     pub sourceName: String,
258     pub lineText: String,
259     pub lineNumber: u32,
260     pub columnNumber: u32,
261     pub category: String,
262     pub timeStamp: u64,
263     pub error: bool,
264     pub warning: bool,
265     pub exception: bool,
266     pub strict: bool,
267     pub private: bool,
268 }
269 
270 #[derive(Debug, Deserialize, Serialize)]
271 pub struct ConsoleAPI {
272     #[serde(rename = "_type")]
273     pub type_: String,
274     pub level: String,
275     pub filename: String,
276     pub lineNumber: u32,
277     pub functionName: String,
278     pub timeStamp: u64,
279     pub private: bool,
280     pub arguments: Vec<String>,
281 }
282 
283 #[derive(Debug, Deserialize, Serialize)]
284 pub enum CachedConsoleMessage {
285     PageError(PageError),
286     ConsoleAPI(ConsoleAPI),
287 }
288 
289 #[derive(Debug, PartialEq)]
290 pub struct HttpRequest {
291     pub url: ServoUrl,
292     pub method: Method,
293     pub headers: Headers,
294     pub body: Option<Vec<u8>>,
295     pub pipeline_id: PipelineId,
296     pub startedDateTime: Tm,
297     pub timeStamp: i64,
298     pub connect_time: u64,
299     pub send_time: u64,
300     pub is_xhr: bool,
301 }
302 
303 #[derive(Debug, PartialEq)]
304 pub struct HttpResponse {
305     pub headers: Option<Headers>,
306     pub status: Option<(u16, Vec<u8>)>,
307     pub body: Option<Vec<u8>>,
308     pub pipeline_id: PipelineId,
309 }
310 
311 #[derive(Debug)]
312 pub enum NetworkEvent {
313     HttpRequest(HttpRequest),
314     HttpResponse(HttpResponse),
315 }
316 
317 impl TimelineMarker {
start(name: String) -> StartedTimelineMarker318     pub fn start(name: String) -> StartedTimelineMarker {
319         StartedTimelineMarker {
320             name: name,
321             start_time: PreciseTime::now(),
322             start_stack: None,
323         }
324     }
325 }
326 
327 impl StartedTimelineMarker {
end(self) -> TimelineMarker328     pub fn end(self) -> TimelineMarker {
329         TimelineMarker {
330             name: self.name,
331             start_time: self.start_time,
332             start_stack: self.start_stack,
333             end_time: PreciseTime::now(),
334             end_stack: None,
335         }
336     }
337 }
338 
339 /// A replacement for `time::PreciseTime` that isn't opaque, so we can serialize it.
340 ///
341 /// The reason why this doesn't go upstream is that `time` is slated to be part of Rust's standard
342 /// library, which definitely can't have any dependencies on `serde`. But `serde` can't implement
343 /// `Deserialize` and `Serialize` itself, because `time::PreciseTime` is opaque! A Catch-22. So I'm
344 /// duplicating the definition here.
345 #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
346 pub struct PreciseTime(u64);
347 
348 impl PreciseTime {
now() -> PreciseTime349     pub fn now() -> PreciseTime {
350         PreciseTime(time::precise_time_ns())
351     }
352 
to(&self, later: PreciseTime) -> Duration353     pub fn to(&self, later: PreciseTime) -> Duration {
354         Duration::nanoseconds((later.0 - self.0) as i64)
355     }
356 }
357 
358 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
359 pub struct WorkerId(pub u32);
360