Skip to main content

cranpose_render_pixels/
scene.rs

1use std::rc::Rc;
2
3pub use cranpose_render_common::graph_scene::{HitRegion, Scene};
4use cranpose_render_common::{layer_shadow::ShadowRRect, primitive_emit::ShapeDrawParams};
5use cranpose_ui::TextStyle;
6use cranpose_ui_graphics::{
7    ArcGeometry, BlendMode, Brush, Color, ColorFilter, ImageBitmap, ImageSampling, LineGeometry,
8    Point, Rect, RoundedCornerShape, Stroke, Trapezoid,
9};
10
11#[derive(Clone)]
12pub(crate) struct DrawShape {
13    pub rect: Rect,
14    pub snap_anchor: Option<Point>,
15    pub snap_to_pixel_grid: bool,
16    pub brush: Brush,
17    pub shape: Option<RoundedCornerShape>,
18    pub stroke: Option<Stroke>,
19    pub arc: Option<ArcGeometry>,
20    pub line: Option<LineGeometry>,
21    pub trapezoid: Option<Trapezoid>,
22    pub z_index: usize,
23    pub clip: Option<Rect>,
24    pub blend_mode: BlendMode,
25}
26
27impl DrawShape {
28    /// The shape `params` resolved, drawn `z_index`-th.
29    pub(crate) fn of_params(params: ShapeDrawParams, z_index: usize) -> Self {
30        Self {
31            rect: params.rect,
32            snap_anchor: None,
33            snap_to_pixel_grid: false,
34            brush: params.brush.into_brush(),
35            shape: params.shape,
36            stroke: params.stroke,
37            arc: params.arc,
38            line: params.line,
39            trapezoid: params.trapezoid,
40            z_index,
41            clip: params.clip,
42            blend_mode: params.blend_mode,
43        }
44    }
45}
46
47#[derive(Clone)]
48pub(crate) struct TextDraw {
49    pub rect: Rect,
50    pub snap_anchor: Option<Point>,
51    pub text: Rc<cranpose_ui::text::AnnotatedString>,
52    pub color: Color,
53    pub text_style: TextStyle,
54    pub font_size: f32,
55    pub scale: f32,
56    pub z_index: usize,
57    pub clip: Option<Rect>,
58}
59
60#[derive(Clone)]
61pub(crate) struct ImageDraw {
62    pub rect: Rect,
63    pub snap_anchor: Option<Point>,
64    pub image: ImageBitmap,
65    pub alpha: f32,
66    pub color_filter: Option<ColorFilter>,
67    pub sampling: ImageSampling,
68    pub z_index: usize,
69    pub clip: Option<Rect>,
70    pub blend_mode: BlendMode,
71    pub src_rect: Option<Rect>,
72}
73
74/// One pass of a layer's elevation shadow: Skia's round rect shadow in
75/// device pixels, its color and the clip it is cut to.
76#[derive(Clone, Copy)]
77pub(crate) struct ShadowDraw {
78    pub shadow: ShadowRRect,
79    pub snap_anchor: Option<Point>,
80    pub color: Color,
81    pub z_index: usize,
82    pub clip: Option<Rect>,
83}
84
85pub(crate) struct RasterScene {
86    pub shapes: Vec<DrawShape>,
87    pub images: Vec<ImageDraw>,
88    pub texts: Vec<TextDraw>,
89    pub shadows: Vec<ShadowDraw>,
90    pub next_z: usize,
91}
92
93impl RasterScene {
94    pub fn new() -> Self {
95        Self {
96            shapes: Vec::new(),
97            images: Vec::new(),
98            texts: Vec::new(),
99            shadows: Vec::new(),
100            next_z: 0,
101        }
102    }
103
104    pub fn push_shape(
105        &mut self,
106        rect: Rect,
107        brush: Brush,
108        shape: Option<RoundedCornerShape>,
109        clip: Option<Rect>,
110        blend_mode: BlendMode,
111    ) {
112        let z_index = self.next_z;
113        self.next_z += 1;
114        self.shapes.push(DrawShape {
115            rect,
116            snap_anchor: None,
117            snap_to_pixel_grid: false,
118            brush,
119            shape,
120            stroke: None,
121            arc: None,
122            line: None,
123            trapezoid: None,
124            z_index,
125            clip,
126            blend_mode,
127        });
128    }
129
130    pub fn push_shadow(&mut self, shadow: ShadowRRect, color: Color, clip: Option<Rect>) {
131        let z_index = self.next_z;
132        self.next_z += 1;
133        self.shadows.push(ShadowDraw {
134            shadow,
135            snap_anchor: None,
136            color,
137            z_index,
138            clip,
139        });
140    }
141
142    pub fn push_pixel_snapped_shape(
143        &mut self,
144        rect: Rect,
145        brush: Brush,
146        shape: Option<RoundedCornerShape>,
147        clip: Option<Rect>,
148        blend_mode: BlendMode,
149    ) {
150        let z_index = self.next_z;
151        self.next_z += 1;
152        self.shapes.push(DrawShape {
153            rect,
154            snap_anchor: None,
155            snap_to_pixel_grid: true,
156            brush,
157            shape,
158            stroke: None,
159            arc: None,
160            line: None,
161            trapezoid: None,
162            z_index,
163            clip,
164            blend_mode,
165        });
166    }
167
168    /// Queues a shape an emitted primitive resolved: a rect, rounded rect,
169    /// stroke, arc band, line segment or slice of a path fill.
170    pub fn push_shape_params(&mut self, params: ShapeDrawParams) {
171        let z_index = self.next_z;
172        self.next_z += 1;
173        self.shapes.push(DrawShape::of_params(params, z_index));
174    }
175
176    #[expect(clippy::too_many_arguments)]
177    pub fn push_image_with_geometry(
178        &mut self,
179        rect: Rect,
180        _local_rect: Rect,
181        _quad: [[f32; 2]; 4],
182        image: ImageBitmap,
183        alpha: f32,
184        color_filter: Option<ColorFilter>,
185        sampling: ImageSampling,
186        clip: Option<Rect>,
187        src_rect: Option<Rect>,
188        blend_mode: BlendMode,
189    ) {
190        let z_index = self.next_z;
191        self.next_z += 1;
192        self.images.push(ImageDraw {
193            rect,
194            snap_anchor: None,
195            image,
196            alpha: alpha.clamp(0.0, 1.0),
197            color_filter,
198            sampling,
199            z_index,
200            clip,
201            blend_mode,
202            src_rect,
203        });
204    }
205
206    #[expect(clippy::too_many_arguments)]
207    pub fn push_text(
208        &mut self,
209        rect: Rect,
210        text: Rc<cranpose_ui::text::AnnotatedString>,
211        color: Color,
212        text_style: TextStyle,
213        font_size: f32,
214        scale: f32,
215        clip: Option<Rect>,
216    ) {
217        let z_index = self.next_z;
218        self.next_z += 1;
219        self.texts.push(TextDraw {
220            rect,
221            snap_anchor: None,
222            text,
223            color,
224            text_style,
225            font_size,
226            scale,
227            z_index,
228            clip,
229        });
230    }
231}
232
233impl Default for RasterScene {
234    fn default() -> Self {
235        Self::new()
236    }
237}