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::Trapezoid { .. }
61            | DrawPrimitive::Text(_)) => {
62                crate::pipeline::push_draw_primitive(
63                    &shape_primitive,
64                    layer_bounds,
65                    layer,
66                    clip,
67                    scene,
68                    blend_mode,
69                    false,
70                );
71            }
72            DrawPrimitive::Image {
73                rect: local_rect,
74                image,
75                alpha,
76                color_filter,
77                sampling,
78                src_rect,
79            } => {
80                let draw_rect = local_rect.translate(layer_bounds.x, layer_bounds.y);
81                let local_rect = apply_layer_affine_to_rect(draw_rect, layer_bounds, layer);
82                let quad = apply_layer_to_quad(draw_rect, layer_bounds, layer);
83                let transformed = quad_bounds(quad);
84                let combined_alpha = (alpha * layer.alpha).clamp(0.0, 1.0);
85                let combined_filter = compose_color_filters(color_filter, layer.color_filter);
86                scene.push_image_with_geometry(
87                    transformed,
88                    local_rect,
89                    quad,
90                    image,
91                    combined_alpha,
92                    combined_filter,
93                    sampling,
94                    clip,
95                    src_rect,
96                    blend_mode.unwrap_or(BlendMode::SrcOver),
97                );
98            }
99            DrawPrimitive::Shadow(shadow_primitive) => match shadow_primitive {
100                ShadowPrimitive::Drop {
101                    shape,
102                    cutout,
103                    blur_radius: _,
104                    blend_mode: shadow_blend_mode,
105                } => {
106                    emit_primitive(
107                        *shape,
108                        layer_bounds,
109                        layer,
110                        clip,
111                        scene,
112                        blend_mode.or(Some(shadow_blend_mode)),
113                    );
114                    if let Some(cutout) = cutout {
115                        emit_primitive(
116                            *cutout,
117                            layer_bounds,
118                            layer,
119                            clip,
120                            scene,
121                            Some(BlendMode::DstOut),
122                        );
123                    }
124                }
125                ShadowPrimitive::Inner {
126                    fill,
127                    cutout,
128                    blur_radius: _,
129                    blend_mode: shadow_blend_mode,
130                    clip_rect,
131                } => {
132                    let abs_clip = Rect {
133                        x: clip_rect.x + layer_bounds.x,
134                        y: clip_rect.y + layer_bounds.y,
135                        width: clip_rect.width,
136                        height: clip_rect.height,
137                    };
138                    let transformed_clip = apply_layer_to_rect(abs_clip, layer_bounds, layer);
139                    let shadow_clip = clip.map_or(Some(transformed_clip), |parent_clip| {
140                        parent_clip.intersect(transformed_clip)
141                    });
142                    emit_primitive(
143                        *fill,
144                        layer_bounds,
145                        layer,
146                        shadow_clip,
147                        scene,
148                        blend_mode.or(Some(shadow_blend_mode)),
149                    );
150                    emit_primitive(
151                        *cutout,
152                        layer_bounds,
153                        layer,
154                        shadow_clip,
155                        scene,
156                        blend_mode.or(Some(BlendMode::DstOut)),
157                    );
158                }
159            },
160        }
161    }
162
163    for command in commands {
164        let primitives = primitives_for_placement(command, placement, size);
165        for primitive in primitives {
166            emit_primitive(primitive, rect, layer, clip, scene, None);
167        }
168    }
169}
170
171pub(crate) fn point_in_resolved_rounded_rect(
172    x: f32,
173    y: f32,
174    rect: Rect,
175    radii: &CornerRadii,
176) -> bool {
177    if !rect.contains(x, y) {
178        return false;
179    }
180    let left = rect.x;
181    let right = rect.x + rect.width;
182    let top = rect.y;
183    let bottom = rect.y + rect.height;
184
185    if radii.top_left > 0.0 && x < left + radii.top_left && y < top + radii.top_left {
186        let cx = left + radii.top_left;
187        let cy = top + radii.top_left;
188        if (x - cx).powi(2) + (y - cy).powi(2) > radii.top_left.powi(2) {
189            return false;
190        }
191    }
192    if radii.top_right > 0.0 && x > right - radii.top_right && y < top + radii.top_right {
193        let cx = right - radii.top_right;
194        let cy = top + radii.top_right;
195        if (x - cx).powi(2) + (y - cy).powi(2) > radii.top_right.powi(2) {
196            return false;
197        }
198    }
199    if radii.bottom_right > 0.0 && x > right - radii.bottom_right && y > bottom - radii.bottom_right
200    {
201        let cx = right - radii.bottom_right;
202        let cy = bottom - radii.bottom_right;
203        if (x - cx).powi(2) + (y - cy).powi(2) > radii.bottom_right.powi(2) {
204            return false;
205        }
206    }
207    if radii.bottom_left > 0.0 && x < left + radii.bottom_left && y > bottom - radii.bottom_left {
208        let cx = left + radii.bottom_left;
209        let cy = bottom - radii.bottom_left;
210        if (x - cx).powi(2) + (y - cy).powi(2) > radii.bottom_left.powi(2) {
211            return false;
212        }
213    }
214    true
215}
216
217#[cfg(test)]
218#[path = "tests/style_tests.rs"]
219mod tests;