tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

capture.rs (8789B)


      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 std::fs::File;
      6 use std::path::{Path, PathBuf};
      7 
      8 use api::{ExternalImageData, ImageDescriptor};
      9 #[cfg(feature = "png")]
     10 use api::ImageFormat;
     11 use api::units::TexelRect;
     12 #[cfg(feature = "png")]
     13 use api::units::DeviceIntSize;
     14 #[cfg(feature = "capture")]
     15 use crate::print_tree::{PrintableTree, PrintTree};
     16 use crate::render_api::CaptureBits;
     17 
     18 
     19 #[derive(Clone)]
     20 pub struct CaptureConfig {
     21    pub root: PathBuf,
     22    pub bits: CaptureBits,
     23    /// Scene sequence ID when capturing multiple frames. Zero for a single frame capture.
     24    pub scene_id: u32,
     25    /// Frame sequence ID when capturing multiple frames. Zero for a single frame capture.
     26    pub frame_id: u32,
     27    /// Resource sequence ID when capturing multiple frames. Zero for a single frame capture.
     28    pub resource_id: u32,
     29    #[cfg(feature = "capture")]
     30    pretty: ron::ser::PrettyConfig,
     31 }
     32 
     33 impl CaptureConfig {
     34    #[cfg(any(feature = "capture", feature = "replay"))]
     35    pub fn new(root: PathBuf, bits: CaptureBits) -> Self {
     36        CaptureConfig {
     37            root,
     38            bits,
     39            scene_id: 0,
     40            frame_id: 0,
     41            resource_id: 0,
     42            #[cfg(feature = "capture")]
     43            pretty: ron::ser::PrettyConfig::new()
     44                .enumerate_arrays(true)
     45                .indentor(" ".to_string()),
     46        }
     47    }
     48 
     49    #[cfg(feature = "capture")]
     50    pub fn prepare_scene(&mut self) {
     51        use std::fs::create_dir_all;
     52        self.scene_id += 1;
     53        let _ = create_dir_all(&self.scene_root());
     54    }
     55 
     56    #[cfg(feature = "capture")]
     57    pub fn prepare_frame(&mut self) {
     58        use std::fs::create_dir_all;
     59        self.frame_id += 1;
     60        let _ = create_dir_all(&self.frame_root());
     61    }
     62 
     63    #[cfg(feature = "capture")]
     64    pub fn prepare_resource(&mut self) {
     65        use std::fs::create_dir_all;
     66        self.resource_id += 1;
     67        let _ = create_dir_all(&self.resource_root());
     68    }
     69 
     70    #[cfg(any(feature = "capture", feature = "replay"))]
     71    pub fn scene_root(&self) -> PathBuf {
     72        if self.scene_id > 0 {
     73            let path = format!("scenes/{:05}", self.scene_id);
     74            self.root.join(path)
     75        } else {
     76            self.root.clone()
     77        }
     78    }
     79 
     80    #[cfg(any(feature = "capture", feature = "replay"))]
     81    pub fn frame_root(&self) -> PathBuf {
     82        if self.frame_id > 0 {
     83            let path = format!("frames/{:05}", self.frame_id);
     84            self.scene_root().join(path)
     85        } else {
     86            self.root.clone()
     87        }
     88    }
     89 
     90    #[cfg(any(feature = "capture", feature = "replay"))]
     91    pub fn resource_root(&self) -> PathBuf {
     92        if self.resource_id > 0 {
     93            let path = format!("resources/{:05}", self.resource_id);
     94            self.root.join(path)
     95        } else {
     96            self.root.clone()
     97        }
     98    }
     99 
    100    #[cfg(feature = "capture")]
    101    pub fn serialize_for_scene<T, P>(&self, data: &T, name: P)
    102    where
    103        T: serde::Serialize,
    104        P: AsRef<Path>,
    105    {
    106        self.serialize(data, self.scene_root(), name)
    107    }
    108 
    109    #[cfg(feature = "capture")]
    110    pub fn serialize_for_frame<T, P>(&self, data: &T, name: P)
    111    where
    112        T: serde::Serialize,
    113        P: AsRef<Path>,
    114    {
    115        self.serialize(data, self.frame_root(), name)
    116    }
    117 
    118    #[cfg(feature = "capture")]
    119    pub fn serialize_for_resource<T, P>(&self, data: &T, name: P)
    120    where
    121        T: serde::Serialize,
    122        P: AsRef<Path>,
    123    {
    124        self.serialize(data, self.resource_root(), name)
    125    }
    126 
    127    #[cfg(feature = "capture")]
    128    pub fn file_path_for_frame<P>(&self, name: P, ext: &str) -> PathBuf
    129    where P: AsRef<Path> {
    130        self.frame_root().join(name).with_extension(ext)
    131    }
    132 
    133    #[cfg(feature = "capture")]
    134    fn serialize<T, P>(&self, data: &T, path: PathBuf, name: P)
    135    where
    136        T: serde::Serialize,
    137        P: AsRef<Path>,
    138    {
    139        use std::io::Write;
    140        let ron = ron::ser::to_string_pretty(data, self.pretty.clone())
    141            .unwrap();
    142        let mut file = File::create(path.join(name).with_extension("ron"))
    143            .unwrap();
    144        write!(file, "{}\n", ron)
    145            .unwrap();
    146    }
    147 
    148    #[cfg(feature = "capture")]
    149    fn serialize_tree<T, P>(data: &T, root: PathBuf, name: P)
    150    where
    151        T: PrintableTree,
    152        P: AsRef<Path>
    153    {
    154        let path = root
    155            .join(name)
    156            .with_extension("tree");
    157        let file = File::create(path)
    158            .unwrap();
    159        let mut pt = PrintTree::new_with_sink("", file);
    160        data.print_with(&mut pt);
    161    }
    162 
    163    #[cfg(feature = "capture")]
    164    pub fn serialize_tree_for_frame<T, P>(&self, data: &T, name: P)
    165    where
    166        T: PrintableTree,
    167        P: AsRef<Path>
    168    {
    169        Self::serialize_tree(data, self.frame_root(), name)
    170    }
    171 
    172    #[cfg(feature = "replay")]
    173    fn deserialize<T, P>(root: &PathBuf, name: P) -> Option<T>
    174    where
    175        T: for<'a> serde::Deserialize<'a>,
    176        P: AsRef<Path>,
    177    {
    178        use std::io::Read;
    179 
    180        let mut string = String::new();
    181        let path = root
    182            .join(name.as_ref())
    183            .with_extension("ron");
    184        File::open(path)
    185            .ok()?
    186            .read_to_string(&mut string)
    187            .unwrap();
    188        match ron::de::from_str(&string) {
    189            Ok(out) => Some(out),
    190            Err(e) => panic!("File {:?} deserialization failed: {:?}", name.as_ref(), e),
    191        }
    192    }
    193 
    194    #[cfg(feature = "replay")]
    195    pub fn deserialize_for_scene<T, P>(&self, name: P) -> Option<T>
    196    where
    197        T: for<'a> serde::Deserialize<'a>,
    198        P: AsRef<Path>,
    199    {
    200        Self::deserialize(&self.scene_root(), name)
    201    }
    202 
    203    #[cfg(feature = "replay")]
    204    pub fn deserialize_for_frame<T, P>(&self, name: P) -> Option<T>
    205    where
    206        T: for<'a> serde::Deserialize<'a>,
    207        P: AsRef<Path>,
    208    {
    209        Self::deserialize(&self.frame_root(), name)
    210    }
    211 
    212    #[cfg(feature = "replay")]
    213    pub fn deserialize_for_resource<T, P>(&self, name: P) -> Option<T>
    214    where
    215        T: for<'a> serde::Deserialize<'a>,
    216        P: AsRef<Path>,
    217    {
    218        Self::deserialize(&self.resource_root(), name)
    219    }
    220 
    221    #[cfg(feature = "png")]
    222    pub fn save_png(
    223        path: PathBuf, size: DeviceIntSize, format: ImageFormat, stride: Option<i32>, data: &[u8],
    224    ) {
    225        use png::{BitDepth, ColorType, Encoder};
    226        use std::io::BufWriter;
    227        use std::borrow::Cow;
    228 
    229        // `png` expects
    230        let data = match stride {
    231            Some(stride) if stride != format.bytes_per_pixel() * size.width => {
    232                let mut unstrided = Vec::new();
    233                for y in 0..size.height {
    234                    let start = (y * stride) as usize;
    235                    unstrided.extend_from_slice(&data[start..start+(size.width * format.bytes_per_pixel()) as usize]);
    236                }
    237                Cow::from(unstrided)
    238            }
    239            _ => Cow::from(data),
    240        };
    241 
    242        let color_type = match format {
    243            ImageFormat::RGBA8 => ColorType::RGBA,
    244            ImageFormat::BGRA8 => {
    245                warn!("Unable to swizzle PNG of BGRA8 type");
    246                ColorType::RGBA
    247            },
    248            ImageFormat::R8 => ColorType::Grayscale,
    249            ImageFormat::RG8 => ColorType::GrayscaleAlpha,
    250            _ => {
    251                error!("Unable to save PNG of {:?}", format);
    252                return;
    253            }
    254        };
    255        let w = BufWriter::new(File::create(path).unwrap());
    256        let mut enc = Encoder::new(w, size.width as u32, size.height as u32);
    257        enc.set_color(color_type);
    258        enc.set_depth(BitDepth::Eight);
    259        enc
    260            .write_header()
    261            .unwrap()
    262            .write_image_data(&*data)
    263            .unwrap();
    264    }
    265 }
    266 
    267 /// An image that `ResourceCache` is unable to resolve during a capture.
    268 /// The image has to be transferred to `Renderer` and locked with the
    269 /// external image handler to get the actual contents and serialize them.
    270 #[derive(Deserialize, Serialize)]
    271 pub struct ExternalCaptureImage {
    272    pub short_path: String,
    273    pub descriptor: ImageDescriptor,
    274    pub external: ExternalImageData,
    275 }
    276 
    277 /// A short description of an external image to be saved separately as
    278 /// "externals/XX.ron", redirecting into a specific texture/blob with
    279 /// the corresponding UV rectangle.
    280 #[derive(Deserialize, Serialize)]
    281 pub struct PlainExternalImage {
    282    /// Path to the RON file describing the texel data.
    283    pub data: String,
    284    /// External image data source.
    285    pub external: ExternalImageData,
    286    /// UV sub-rectangle of the image.
    287    pub uv: TexelRect,
    288 }