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 // the json code is largely unfinished; allow these to silence a bunch of warnings 6 #![allow(unused_variables)] 7 #![allow(dead_code)] 8 9 use app_units::Au; 10 use image::{save_buffer, ColorType}; 11 use premultiply::unpremultiply; 12 use serde_json; 13 use std::collections::HashMap; 14 use std::io::Write; 15 use std::path::{Path, PathBuf}; 16 use std::{fmt, fs}; 17 use super::CURRENT_FRAME_NUMBER; 18 use time; 19 use webrender; 20 use webrender::api::*; 21 use webrender::api::channel::Payload; 22 23 enum CachedFont { 24 Native(NativeFontHandle), 25 Raw(Option<Vec<u8>>, u32, Option<PathBuf>), 26 } 27 28 struct CachedFontInstance { 29 font_key: FontKey, 30 glyph_size: Au, 31 } 32 33 struct CachedImage { 34 width: u32, 35 height: u32, 36 stride: u32, 37 format: ImageFormat, 38 bytes: Option<Vec<u8>>, 39 path: Option<PathBuf>, 40 } 41 42 pub struct JsonFrameWriter { 43 frame_base: PathBuf, 44 rsrc_base: PathBuf, 45 rsrc_prefix: String, 46 next_rsrc_num: u32, 47 images: HashMap<ImageKey, CachedImage>, 48 fonts: HashMap<FontKey, CachedFont>, 49 font_instances: HashMap<FontInstanceKey, CachedFontInstance>, 50 51 last_frame_written: u32, 52 53 dl_descriptor: Option<BuiltDisplayListDescriptor>, 54 } 55 56 impl JsonFrameWriter { new(path: &Path) -> Self57 pub fn new(path: &Path) -> Self { 58 let mut rsrc_base = path.to_owned(); 59 rsrc_base.push("res"); 60 fs::create_dir_all(&rsrc_base).ok(); 61 62 let rsrc_prefix = format!("{}", time::get_time().sec); 63 64 JsonFrameWriter { 65 frame_base: path.to_owned(), 66 rsrc_base, 67 rsrc_prefix, 68 next_rsrc_num: 1, 69 images: HashMap::new(), 70 fonts: HashMap::new(), 71 font_instances: HashMap::new(), 72 73 dl_descriptor: None, 74 75 last_frame_written: u32::max_value(), 76 } 77 } 78 begin_write_display_list( &mut self, _: &Epoch, _: &PipelineId, _: &Option<ColorF>, _: &LayoutSize, display_list: &BuiltDisplayListDescriptor, )79 pub fn begin_write_display_list( 80 &mut self, 81 _: &Epoch, 82 _: &PipelineId, 83 _: &Option<ColorF>, 84 _: &LayoutSize, 85 display_list: &BuiltDisplayListDescriptor, 86 ) { 87 unsafe { 88 if CURRENT_FRAME_NUMBER == self.last_frame_written { 89 return; 90 } 91 self.last_frame_written = CURRENT_FRAME_NUMBER; 92 } 93 94 self.dl_descriptor = Some(display_list.clone()); 95 } 96 finish_write_display_list(&mut self, frame: u32, data: &[u8])97 pub fn finish_write_display_list(&mut self, frame: u32, data: &[u8]) { 98 let payload = Payload::from_data(data); 99 let dl_desc = self.dl_descriptor.take().unwrap(); 100 101 let dl = BuiltDisplayList::from_data(payload.display_list_data, dl_desc); 102 103 let mut frame_file_name = self.frame_base.clone(); 104 let current_shown_frame = unsafe { CURRENT_FRAME_NUMBER }; 105 frame_file_name.push(format!("frame-{}.json", current_shown_frame)); 106 107 let mut file = fs::File::create(&frame_file_name).unwrap(); 108 109 let s = serde_json::to_string_pretty(&dl).unwrap(); 110 file.write_all(&s.into_bytes()).unwrap(); 111 file.write_all(b"\n").unwrap(); 112 } 113 update_resources(&mut self, updates: &ResourceUpdates)114 fn update_resources(&mut self, updates: &ResourceUpdates) { 115 for update in &updates.updates { 116 match *update { 117 ResourceUpdate::AddImage(ref img) => { 118 let stride = img.descriptor.stride.unwrap_or( 119 img.descriptor.width * img.descriptor.format.bytes_per_pixel(), 120 ); 121 let bytes = match img.data { 122 ImageData::Raw(ref v) => (**v).clone(), 123 ImageData::External(_) | ImageData::Blob(_) => { 124 return; 125 } 126 }; 127 self.images.insert( 128 img.key, 129 CachedImage { 130 width: img.descriptor.width, 131 height: img.descriptor.height, 132 stride, 133 format: img.descriptor.format, 134 bytes: Some(bytes), 135 path: None, 136 }, 137 ); 138 } 139 ResourceUpdate::UpdateImage(ref img) => { 140 if let Some(ref mut data) = self.images.get_mut(&img.key) { 141 assert_eq!(data.width, img.descriptor.width); 142 assert_eq!(data.height, img.descriptor.height); 143 assert_eq!(data.format, img.descriptor.format); 144 145 if let ImageData::Raw(ref bytes) = img.data { 146 data.path = None; 147 data.bytes = Some((**bytes).clone()); 148 } else { 149 // Other existing image types only make sense within the gecko integration. 150 println!( 151 "Wrench only supports updating buffer images ({}).", 152 "ignoring update commands" 153 ); 154 } 155 } 156 } 157 ResourceUpdate::DeleteImage(img) => { 158 self.images.remove(&img); 159 } 160 ResourceUpdate::AddFont(ref font) => match font { 161 &AddFont::Raw(key, ref bytes, index) => { 162 self.fonts 163 .insert(key, CachedFont::Raw(Some(bytes.clone()), index, None)); 164 } 165 &AddFont::Native(key, ref handle) => { 166 self.fonts.insert(key, CachedFont::Native(handle.clone())); 167 } 168 }, 169 ResourceUpdate::DeleteFont(_) => {} 170 ResourceUpdate::AddFontInstance(ref instance) => { 171 self.font_instances.insert( 172 instance.key, 173 CachedFontInstance { 174 font_key: instance.font_key, 175 glyph_size: instance.glyph_size, 176 }, 177 ); 178 } 179 ResourceUpdate::DeleteFontInstance(_) => {} 180 } 181 } 182 } 183 next_rsrc_paths( prefix: &str, counter: &mut u32, base_path: &Path, base: &str, ext: &str, ) -> (PathBuf, PathBuf)184 fn next_rsrc_paths( 185 prefix: &str, 186 counter: &mut u32, 187 base_path: &Path, 188 base: &str, 189 ext: &str, 190 ) -> (PathBuf, PathBuf) { 191 let mut path_file = base_path.to_owned(); 192 let mut path = PathBuf::from("res"); 193 194 let fstr = format!("{}-{}-{}.{}", prefix, base, counter, ext); 195 path_file.push(&fstr); 196 path.push(&fstr); 197 198 *counter += 1; 199 200 (path_file, path) 201 } 202 path_for_image(&mut self, key: ImageKey) -> Option<PathBuf>203 fn path_for_image(&mut self, key: ImageKey) -> Option<PathBuf> { 204 if let Some(ref mut data) = self.images.get_mut(&key) { 205 if data.path.is_some() { 206 return data.path.clone(); 207 } 208 } else { 209 return None; 210 }; 211 212 // Remove the data to munge it 213 let mut data = self.images.remove(&key).unwrap(); 214 let mut bytes = data.bytes.take().unwrap(); 215 let (path_file, path) = Self::next_rsrc_paths( 216 &self.rsrc_prefix, 217 &mut self.next_rsrc_num, 218 &self.rsrc_base, 219 "img", 220 "png", 221 ); 222 223 let ok = match data.format { 224 ImageFormat::BGRA8 => if data.stride == data.width * 4 { 225 unpremultiply(bytes.as_mut_slice()); 226 save_buffer( 227 &path_file, 228 &bytes, 229 data.width, 230 data.height, 231 ColorType::RGBA(8), 232 ).unwrap(); 233 true 234 } else { 235 false 236 }, 237 ImageFormat::R8 => if data.stride == data.width { 238 save_buffer( 239 &path_file, 240 &bytes, 241 data.width, 242 data.height, 243 ColorType::Gray(8), 244 ).unwrap(); 245 true 246 } else { 247 false 248 }, 249 _ => false, 250 }; 251 252 if !ok { 253 println!( 254 "Failed to write image with format {:?}, dimensions {}x{}, stride {}", 255 data.format, 256 data.width, 257 data.height, 258 data.stride 259 ); 260 return None; 261 } 262 263 data.path = Some(path.clone()); 264 // put it back 265 self.images.insert(key, data); 266 Some(path) 267 } 268 } 269 270 impl fmt::Debug for JsonFrameWriter { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result271 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 272 write!(f, "JsonFrameWriter") 273 } 274 } 275 276 impl webrender::ApiRecordingReceiver for JsonFrameWriter { write_msg(&mut self, _: u32, msg: &ApiMsg)277 fn write_msg(&mut self, _: u32, msg: &ApiMsg) { 278 match *msg { 279 ApiMsg::UpdateResources(ref updates) => self.update_resources(updates), 280 281 ApiMsg::UpdateDocument(_, ref txn) => { 282 self.update_resources(&txn.resource_updates); 283 for doc_msg in &txn.scene_ops { 284 match *doc_msg { 285 SceneMsg::SetDisplayList { 286 ref epoch, 287 ref pipeline_id, 288 ref background, 289 ref viewport_size, 290 ref list_descriptor, 291 .. 292 } => { 293 self.begin_write_display_list( 294 epoch, 295 pipeline_id, 296 background, 297 viewport_size, 298 list_descriptor, 299 ); 300 } 301 _ => {} 302 } 303 } 304 } 305 ApiMsg::CloneApi(..) => {} 306 _ => {} 307 } 308 } 309 write_payload(&mut self, frame: u32, data: &[u8])310 fn write_payload(&mut self, frame: u32, data: &[u8]) { 311 if self.dl_descriptor.is_some() { 312 self.finish_write_display_list(frame, data); 313 } 314 } 315 } 316