skia_safe/core/
picture_recorder.rs

1use crate::{prelude::*, BBHFactory, Canvas, Drawable, Picture, Rect};
2use skia_bindings::{self as sb, SkPictureRecorder, SkRect};
3use std::{fmt, ptr};
4
5pub type PictureRecorder = Handle<SkPictureRecorder>;
6
7impl NativeDrop for SkPictureRecorder {
8    fn drop(&mut self) {
9        unsafe {
10            sb::C_SkPictureRecorder_destruct(self);
11        }
12    }
13}
14
15impl fmt::Debug for PictureRecorder {
16    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17        f.debug_struct("PictureRecorder").finish()
18    }
19}
20
21impl PictureRecorder {
22    pub fn new() -> Self {
23        Self::construct(|pr| unsafe { sb::C_SkPictureRecorder_Construct(pr) })
24    }
25
26    // TODO: beginRecording with BBoxHierarchy
27
28    pub fn begin_recording(
29        &mut self,
30        bounds: impl AsRef<Rect>,
31        mut bbh_factory: Option<&mut BBHFactory>,
32    ) -> &Canvas {
33        let canvas_ref = unsafe {
34            &*self.native_mut().beginRecording1(
35                bounds.as_ref().native(),
36                bbh_factory.native_ptr_or_null_mut(),
37            )
38        };
39
40        Canvas::borrow_from_native(canvas_ref)
41    }
42
43    pub fn recording_canvas(&mut self) -> Option<&Canvas> {
44        let canvas = unsafe { self.native_mut().getRecordingCanvas() };
45        if canvas.is_null() {
46            return None;
47        }
48        Some(Canvas::borrow_from_native(unsafe { &*canvas }))
49    }
50
51    pub fn finish_recording_as_picture(&mut self, cull_rect: Option<&Rect>) -> Option<Picture> {
52        self.recording_canvas()?;
53        let cull_rect_ptr: *const SkRect =
54            cull_rect.map(|r| r.native() as _).unwrap_or(ptr::null());
55
56        let picture_ptr = unsafe {
57            sb::C_SkPictureRecorder_finishRecordingAsPicture(self.native_mut(), cull_rect_ptr)
58        };
59
60        Picture::from_ptr(picture_ptr)
61    }
62
63    pub fn finish_recording_as_drawable(&mut self) -> Option<Drawable> {
64        self.recording_canvas()?;
65        Drawable::from_ptr(unsafe {
66            sb::C_SkPictureRecorder_finishRecordingAsDrawable(self.native_mut())
67        })
68    }
69}
70
71#[test]
72fn good_case() {
73    let mut recorder = PictureRecorder::new();
74    let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), None);
75    canvas.clear(crate::Color::WHITE);
76    let _picture = recorder.finish_recording_as_picture(None).unwrap();
77}
78
79#[test]
80fn begin_recording_two_times() {
81    let mut recorder = PictureRecorder::new();
82    let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), None);
83    canvas.clear(crate::Color::WHITE);
84    assert!(recorder.recording_canvas().is_some());
85    let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), None);
86    canvas.clear(crate::Color::WHITE);
87    assert!(recorder.recording_canvas().is_some());
88}
89
90#[test]
91fn finishing_recording_two_times() {
92    let mut recorder = PictureRecorder::new();
93    let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), None);
94    canvas.clear(crate::Color::WHITE);
95    assert!(recorder.finish_recording_as_picture(None).is_some());
96    assert!(recorder.recording_canvas().is_none());
97    assert!(recorder.finish_recording_as_picture(None).is_none());
98}
99
100#[test]
101fn not_recording_no_canvas() {
102    let mut recorder = PictureRecorder::new();
103    assert!(recorder.recording_canvas().is_none());
104}