Skip to main content

cranpose_render_pixels/
style.rs

1#[cfg(test)]
2pub(crate) use cranpose_render_common::graph::quad_bounds;
3#[cfg(test)]
4pub(crate) use cranpose_render_common::layer_transform::apply_layer_to_rect;
5#[cfg(test)]
6pub(crate) use cranpose_render_common::layer_transform::{
7    apply_layer_affine_to_rect, apply_layer_to_quad,
8};
9#[cfg(test)]
10pub(crate) use cranpose_render_common::style_shared::{
11    DrawPlacement, compose_color_filters, primitives_for_placement,
12};
13pub(crate) use cranpose_render_common::style_shared::{
14    apply_layer_to_brush, apply_layer_to_color, combine_layers, scale_corner_radii,
15};
16#[cfg(test)]
17use cranpose_ui::DrawCommand;
18#[cfg(test)]
19use cranpose_ui_graphics::{BlendMode, DrawPrimitive, GraphicsLayer, ShadowPrimitive, Size};
20use cranpose_ui_graphics::{CornerRadii, Rect};
21
22#[cfg(test)]
23use crate::scene::RasterScene;
24
25#[cfg(test)]
26pub(crate) fn apply_draw_commands(
27    commands: &[DrawCommand],
28    placement: DrawPlacement,
29    rect: Rect,
30    size: Size,
31    layer: &GraphicsLayer,
32    clip: Option<Rect>,
33    scene: &mut RasterScene,
34) {
35    fn emit_primitive(
36        primitive: DrawPrimitive,
37        layer_bounds: Rect,
38        layer: &GraphicsLayer,
39        clip: Option<Rect>,
40        scene: &mut RasterScene,
41        blend_mode: Option<BlendMode>,
42    ) {
43        match primitive {
44            DrawPrimitive::Content => {}
45            DrawPrimitive::Blend {
46                primitive,
47                blend_mode: nested,
48            } => emit_primitive(
49                *primitive,
50                layer_bounds,
51                layer,
52                clip,
53                scene,
54                blend_mode.or(Some(nested)),
55            ),
56            shape_primitive @ (DrawPrimitive::Rect { .. }
57            | DrawPrimitive::RoundRect { .. }
58            | DrawPrimitive::Arc { .. }
59            | DrawPrimitive::Line { .. }
60            | DrawPrimitive::Text(_)) => {
61                crate::pipeline::push_draw_primitive(
62                    &shape_primitive,
63                    layer_bounds,
64                    layer,
65                    clip,
66                    scene,
67                    blend_mode,
68                    false,
69                );
70            }
71            DrawPrimitive::Image {
72                rect: local_rect,
73                image,
74                alpha,
75                color_filter,
76                sampling,
77                src_rect,
78            } => {
79                let draw_rect = local_rect.translate(layer_bounds.x, layer_bounds.y);
80                let local_rect = apply_layer_affine_to_rect(draw_rect, layer_bounds, layer);
81                let quad = apply_layer_to_quad(draw_rect, layer_bounds, layer);
82                let transformed = quad_bounds(quad);
83                let combined_alpha = (alpha * layer.alpha).clamp(0.0, 1.0);
84                let combined_filter = compose_color_filters(color_filter, layer.color_filter);
85                scene.push_image_with_geometry(
86                    transformed,
87                    local_rect,
88                    quad,
89                    image,
90                    combined_alpha,
91                    combined_filter,
92                    sampling,
93                    clip,
94                    src_rect,
95                    blend_mode.unwrap_or(BlendMode::SrcOver),
96                );
97            }
98            DrawPrimitive::Shadow(shadow_primitive) => match shadow_primitive {
99                ShadowPrimitive::Drop {
100                    shape,
101                    cutout,
102                    blur_radius: _,
103                    blend_mode: shadow_blend_mode,
104                } => {
105                    emit_primitive(
106                        *shape,
107                        layer_bounds,
108                        layer,
109                        clip,
110                        scene,
111                        blend_mode.or(Some(shadow_blend_mode)),
112                    );
113                    if let Some(cutout) = cutout {
114                        emit_primitive(
115                            *cutout,
116                            layer_bounds,
117                            layer,
118                            clip,
119                            scene,
120                            Some(BlendMode::DstOut),
121                        );
122                    }
123                }
124                ShadowPrimitive::Inner {
125                    fill,
126                    cutout,
127                    blur_radius: _,
128                    blend_mode: shadow_blend_mode,
129                    clip_rect,
130                } => {
131                    let abs_clip = Rect {
132                        x: clip_rect.x + layer_bounds.x,
133                        y: clip_rect.y + layer_bounds.y,
134                        width: clip_rect.width,
135                        height: clip_rect.height,
136                    };
137                    let transformed_clip = apply_layer_to_rect(abs_clip, layer_bounds, layer);
138                    let shadow_clip = clip.map_or(Some(transformed_clip), |parent_clip| {
139                        parent_clip.intersect(transformed_clip)
140                    });
141                    emit_primitive(
142                        *fill,
143                        layer_bounds,
144                        layer,
145                        shadow_clip,
146                        scene,
147                        blend_mode.or(Some(shadow_blend_mode)),
148                    );
149                    emit_primitive(
150                        *cutout,
151                        layer_bounds,
152                        layer,
153                        shadow_clip,
154                        scene,
155                        blend_mode.or(Some(BlendMode::DstOut)),
156                    );
157                }
158            },
159        }
160    }
161
162    for command in commands {
163        let primitives = primitives_for_placement(command, placement, size);
164        for primitive in primitives {
165            emit_primitive(primitive, rect, layer, clip, scene, None);
166        }
167    }
168}
169
170pub(crate) fn point_in_resolved_rounded_rect(
171    x: f32,
172    y: f32,
173    rect: Rect,
174    radii: &CornerRadii,
175) -> bool {
176    if !rect.contains(x, y) {
177        return false;
178    }
179    let left = rect.x;
180    let right = rect.x + rect.width;
181    let top = rect.y;
182    let bottom = rect.y + rect.height;
183
184    if radii.top_left > 0.0 && x < left + radii.top_left && y < top + radii.top_left {
185        let cx = left + radii.top_left;
186        let cy = top + radii.top_left;
187        if (x - cx).powi(2) + (y - cy).powi(2) > radii.top_left.powi(2) {
188            return false;
189        }
190    }
191    if radii.top_right > 0.0 && x > right - radii.top_right && y < top + radii.top_right {
192        let cx = right - radii.top_right;
193        let cy = top + radii.top_right;
194        if (x - cx).powi(2) + (y - cy).powi(2) > radii.top_right.powi(2) {
195            return false;
196        }
197    }
198    if radii.bottom_right > 0.0 && x > right - radii.bottom_right && y > bottom - radii.bottom_right
199    {
200        let cx = right - radii.bottom_right;
201        let cy = bottom - radii.bottom_right;
202        if (x - cx).powi(2) + (y - cy).powi(2) > radii.bottom_right.powi(2) {
203            return false;
204        }
205    }
206    if radii.bottom_left > 0.0 && x < left + radii.bottom_left && y > bottom - radii.bottom_left {
207        let cx = left + radii.bottom_left;
208        let cy = bottom - radii.bottom_left;
209        if (x - cx).powi(2) + (y - cy).powi(2) > radii.bottom_left.powi(2) {
210            return false;
211        }
212    }
213    true
214}
215
216#[cfg(test)]
217#[path = "tests/style_tests.rs"]
218mod tests;