skia_safe/core/
picture_recorder.rs1use crate::{prelude::*, 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 pub fn begin_recording(&mut self, bounds: impl AsRef<Rect>, use_bbh: bool) -> &Canvas {
27 let canvas_ref = unsafe {
28 &*sb::C_SkPictureRecorder_beginRecording(
29 self.native_mut(),
30 bounds.as_ref().native(),
31 use_bbh,
32 )
33 };
34
35 Canvas::borrow_from_native(canvas_ref)
36 }
37
38 pub fn recording_canvas(&mut self) -> Option<&Canvas> {
39 let canvas = unsafe { self.native_mut().getRecordingCanvas() };
40 if canvas.is_null() {
41 return None;
42 }
43 Some(Canvas::borrow_from_native(unsafe { &*canvas }))
44 }
45
46 pub fn finish_recording_as_picture(&mut self, cull_rect: Option<&Rect>) -> Option<Picture> {
47 self.recording_canvas()?;
48 let cull_rect_ptr: *const SkRect =
49 cull_rect.map(|r| r.native() as _).unwrap_or(ptr::null());
50
51 let picture_ptr = unsafe {
52 sb::C_SkPictureRecorder_finishRecordingAsPicture(self.native_mut(), cull_rect_ptr)
53 };
54
55 Picture::from_ptr(picture_ptr)
56 }
57
58 pub fn finish_recording_as_drawable(&mut self) -> Option<Drawable> {
59 self.recording_canvas()?;
60 Drawable::from_ptr(unsafe {
61 sb::C_SkPictureRecorder_finishRecordingAsDrawable(self.native_mut())
62 })
63 }
64}
65
66#[test]
67fn good_case() {
68 let mut recorder = PictureRecorder::new();
69 let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), false);
70 canvas.clear(crate::Color::WHITE);
71 let _picture = recorder.finish_recording_as_picture(None).unwrap();
72}
73
74#[test]
75fn begin_recording_two_times() {
76 let mut recorder = PictureRecorder::new();
77 let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), false);
78 canvas.clear(crate::Color::WHITE);
79 assert!(recorder.recording_canvas().is_some());
80 let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), false);
81 canvas.clear(crate::Color::WHITE);
82 assert!(recorder.recording_canvas().is_some());
83}
84
85#[test]
86fn finishing_recording_two_times() {
87 let mut recorder = PictureRecorder::new();
88 let canvas = recorder.begin_recording(Rect::new(0.0, 0.0, 100.0, 100.0), false);
89 canvas.clear(crate::Color::WHITE);
90 assert!(recorder.finish_recording_as_picture(None).is_some());
91 assert!(recorder.recording_canvas().is_none());
92 assert!(recorder.finish_recording_as_picture(None).is_none());
93}
94
95#[test]
96fn not_recording_no_canvas() {
97 let mut recorder = PictureRecorder::new();
98 assert!(recorder.recording_canvas().is_none());
99}
100
101#[test]
102fn record_with_bbox_hierarchy() {
103 let mut paint = crate::Paint::new(crate::Color4f::new(0.0, 0.0, 0.0, 1.0), None);
104 paint.set_style(crate::PaintStyle::Fill);
105
106 let frame_rect = Rect::new(0.0, 0.0, 100.0, 100.0);
107 let crop_rect = Rect::new(50.0, 50.0, 100.0, 100.0);
108 let drawn_rect = Rect::new(70.0, 70.0, 80.0, 80.0);
109
110 let mut src_rec = PictureRecorder::new();
112 src_rec
113 .begin_recording(frame_rect, false)
114 .draw_rect(drawn_rect, &paint);
115 let picture = src_rec.finish_recording_as_picture(None).unwrap();
116 assert!(picture.cull_rect() == frame_rect);
117
118 let mut no_bbh = PictureRecorder::new();
119 no_bbh
120 .begin_recording(crop_rect, false)
121 .draw_picture(&picture, None, None);
122 let no_bbh_pict = no_bbh.finish_recording_as_picture(None).unwrap();
123 assert!(no_bbh_pict.cull_rect() == crop_rect);
124
125 let mut with_bbh = PictureRecorder::new();
127 with_bbh
128 .begin_recording(frame_rect, true)
129 .draw_picture(&picture, None, None);
130 let bbh_pict = with_bbh.finish_recording_as_picture(None).unwrap();
131 assert!(bbh_pict.cull_rect() == drawn_rect);
132}