Source code

Revision control

Other Tools

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
use api::{ApiMsg, FrameMsg, SceneMsg, TransactionMsg};
6
use bincode::serialize;
7
use byteorder::{LittleEndian, WriteBytesExt};
8
use std::any::TypeId;
9
use std::fmt::Debug;
10
use std::fs::File;
11
use std::io::Write;
12
use std::mem;
13
use std::path::PathBuf;
14
15
pub static WEBRENDER_RECORDING_HEADER: u64 = 0xbeefbeefbeefbe01u64;
16
17
pub trait ApiRecordingReceiver: Send + Debug {
18
fn write_msg(&mut self, frame: u32, msg: &ApiMsg);
19
fn write_payload(&mut self, frame: u32, data: &[u8]);
20
}
21
22
#[derive(Debug)]
23
pub struct BinaryRecorder {
24
file: File,
25
}
26
27
impl BinaryRecorder {
28
pub fn new(dest: &PathBuf) -> BinaryRecorder {
29
let mut file = File::create(dest).unwrap();
30
31
// write the header
32
let apimsg_type_id = unsafe {
33
assert!(mem::size_of::<TypeId>() == mem::size_of::<u64>());
34
mem::transmute::<TypeId, u64>(TypeId::of::<ApiMsg>())
35
};
36
file.write_u64::<LittleEndian>(WEBRENDER_RECORDING_HEADER)
37
.ok();
38
file.write_u64::<LittleEndian>(apimsg_type_id).ok();
39
40
BinaryRecorder { file }
41
}
42
43
fn write_length_and_data(&mut self, data: &[u8]) {
44
self.file.write_u32::<LittleEndian>(data.len() as u32).ok();
45
self.file.write(data).ok();
46
}
47
}
48
49
impl ApiRecordingReceiver for BinaryRecorder {
50
fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
51
if should_record_msg(msg) {
52
let buf = serialize(msg).unwrap();
53
self.write_length_and_data(&buf);
54
}
55
}
56
57
fn write_payload(&mut self, _: u32, data: &[u8]) {
58
// signal payload with a 0 length
59
self.file.write_u32::<LittleEndian>(0).ok();
60
self.write_length_and_data(data);
61
}
62
}
63
64
#[derive(Debug)]
65
pub struct LogRecorder {
66
file: File,
67
}
68
69
impl LogRecorder {
70
pub fn new(dest: &PathBuf) -> Option<Box<LogRecorder>> {
71
Some(Box::new(LogRecorder { file: File::create(dest).ok()? }))
72
}
73
}
74
75
impl ApiRecordingReceiver for LogRecorder {
76
fn write_msg(&mut self, _: u32, msg: &ApiMsg) {
77
let current_time = time::now_utc();
78
writeln!(self.file, "{}:{}ms - {:?}", current_time.rfc3339(), current_time.tm_nsec / 1000000, msg).unwrap();
79
match *msg {
80
ApiMsg::UpdateDocuments(_, ref msgs) => {
81
for msg in msgs {
82
writeln!(self.file, "\tTransaction: {:?}", msg).unwrap();
83
}
84
}
85
_ => {},
86
}
87
}
88
89
fn write_payload(&mut self, _: u32, _data: &[u8]) {
90
}
91
}
92
93
fn should_record_transaction_msg(msgs: &TransactionMsg) -> bool {
94
if msgs.generate_frame {
95
return true;
96
}
97
98
for msg in &msgs.scene_ops {
99
match *msg {
100
SceneMsg::SetDisplayList { .. } |
101
SceneMsg::SetRootPipeline { .. } => return true,
102
_ => {}
103
}
104
}
105
106
for msg in &msgs.frame_ops {
107
match *msg {
108
FrameMsg::GetScrollNodeState(..) |
109
FrameMsg::HitTest(..) => {}
110
_ => return true,
111
}
112
}
113
114
false
115
}
116
117
pub fn should_record_msg(msg: &ApiMsg) -> bool {
118
match *msg {
119
ApiMsg::UpdateResources(..) |
120
ApiMsg::AddDocument { .. } |
121
ApiMsg::DeleteDocument(..) => true,
122
ApiMsg::UpdateDocuments(_, ref msgs) => {
123
for msg in msgs {
124
if should_record_transaction_msg(msg) {
125
return true;
126
}
127
}
128
false
129
}
130
_ => false,
131
}
132
}