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;