1use super::{signature::command_signature_part, *};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4pub enum RenderPhase {
5 Background,
6 Content,
7 Overlay,
8 Popup,
9}
10
11#[derive(Clone, Debug, PartialEq)]
12pub enum ScenePrimitive {
13 Rect {
14 id: UiId,
15 rect: UiRect,
16 style: VisualStyle,
17 phase: RenderPhase,
18 },
19 Ellipse {
20 id: UiId,
21 rect: UiRect,
22 style: VisualStyle,
23 phase: RenderPhase,
24 },
25 Text {
26 id: UiId,
27 rect: UiRect,
28 text: Cow<'static, str>,
29 style: TextStyle,
30 phase: RenderPhase,
31 },
32 Custom {
33 id: UiId,
34 rect: UiRect,
35 key: &'static str,
36 style: Option<CustomPaintStyle>,
39 phase: RenderPhase,
40 },
41 Line {
42 id: UiId,
43 start: super::Point,
44 end: super::Point,
45 stroke: super::Stroke,
46 phase: RenderPhase,
47 },
48 Path {
49 id: UiId,
50 rect: UiRect,
51 path: UiPath,
52 style: PathStyle,
53 phase: RenderPhase,
54 },
55 Image {
56 id: UiId,
57 rect: UiRect,
58 source: UiImageSource,
59 request: ImageRequest,
60 fit: ImageFit,
61 phase: RenderPhase,
62 },
63 Icon {
64 id: UiId,
65 rect: UiRect,
66 key: &'static str,
67 style: super::IconStyle,
68 phase: RenderPhase,
69 },
70 Glow {
71 id: UiId,
72 rect: UiRect,
73 color: super::Color,
74 alpha: u8,
75 phase: RenderPhase,
76 },
77 BackdropBlur {
78 id: UiId,
79 rect: UiRect,
80 style: BackdropBlurStyle,
81 phase: RenderPhase,
82 },
83 BackdropBlurPath {
84 id: UiId,
85 rect: UiRect,
86 path: UiPath,
87 style: BackdropBlurStyle,
88 phase: RenderPhase,
89 },
90 Overlay {
91 id: UiId,
92 rect: UiRect,
93 style: OverlayStyle,
94 phase: RenderPhase,
95 },
96 CompositingLayer {
97 id: UiId,
98 rect: UiRect,
99 spec: CompositingLayerSpec,
100 commands: Vec<ScenePrimitive>,
102 content_signature: u64,
103 phase: RenderPhase,
104 },
105 StaticLayer {
106 id: UiId,
107 rect: UiRect,
108 spec: StaticLayerSpec,
109 commands: Vec<ScenePrimitive>,
110 child_signature: u64,
111 phase: RenderPhase,
112 },
113 ScrollRaster {
114 id: UiId,
115 viewport: UiRect,
116 spec: ScrollRasterSpec,
117 commands: Vec<ScenePrimitive>,
118 child_signature: u64,
119 phase: RenderPhase,
120 },
121 Clip {
122 id: UiId,
123 rect: UiRect,
124 commands: Vec<ScenePrimitive>,
125 child_signature: u64,
126 phase: RenderPhase,
127 },
128 ClipPath {
129 id: UiId,
130 rect: UiRect,
131 path: UiPath,
132 commands: Vec<ScenePrimitive>,
133 child_signature: u64,
134 phase: RenderPhase,
135 },
136}
137
138#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
139pub enum ScenePrimitiveKind {
140 Rect,
141 Ellipse,
142 Text,
143 Custom,
144 Line,
145 Path,
146 Image,
147 Icon,
148 Glow,
149 BackdropBlur,
150 BackdropBlurPath,
151 Overlay,
152 CompositingLayer,
153 StaticLayer,
154 ScrollRaster,
155 Clip,
156 ClipPath,
157}
158
159impl ScenePrimitiveKind {
160 pub const ALL: [Self; 17] = [
161 Self::Rect,
162 Self::Ellipse,
163 Self::Text,
164 Self::Custom,
165 Self::Line,
166 Self::Path,
167 Self::Image,
168 Self::Icon,
169 Self::Glow,
170 Self::BackdropBlur,
171 Self::BackdropBlurPath,
172 Self::Overlay,
173 Self::CompositingLayer,
174 Self::StaticLayer,
175 Self::ScrollRaster,
176 Self::Clip,
177 Self::ClipPath,
178 ];
179
180 pub const fn as_str(self) -> &'static str {
181 match self {
182 Self::Rect => "Rect",
183 Self::Ellipse => "Ellipse",
184 Self::Text => "Text",
185 Self::Custom => "Custom",
186 Self::Line => "Line",
187 Self::Path => "Path",
188 Self::Image => "Image",
189 Self::Icon => "Icon",
190 Self::Glow => "Glow",
191 Self::BackdropBlur => "BackdropBlur",
192 Self::BackdropBlurPath => "BackdropBlurPath",
193 Self::Overlay => "Overlay",
194 Self::CompositingLayer => "CompositingLayer",
195 Self::StaticLayer => "StaticLayer",
196 Self::ScrollRaster => "ScrollRaster",
197 Self::Clip => "Clip",
198 Self::ClipPath => "ClipPath",
199 }
200 }
201}
202
203#[derive(Clone, Debug, PartialEq)]
204pub struct ScrollRasterSpec {
205 pub cache_epoch: u64,
206 pub content_height: f32,
207 pub scroll_y: f32,
208 pub tile_height_px: f32,
209 pub memory_budget_bytes: usize,
210 pub background_fill: Option<Color>,
211 pub visible_tiles: Vec<usize>,
212 pub prefetch_tiles: Vec<usize>,
213 pub max_prefetch_tiles_per_frame: usize,
214 pub max_prefetch_ms_per_frame: u32,
215}
216
217impl Eq for ScrollRasterSpec {}
218
219impl Hash for ScrollRasterSpec {
220 fn hash<H: Hasher>(&self, state: &mut H) {
221 self.cache_epoch.hash(state);
222 normalized_f32_bits(self.content_height).hash(state);
223 normalized_f32_bits(self.scroll_y).hash(state);
224 normalized_f32_bits(self.tile_height_px).hash(state);
225 self.memory_budget_bytes.hash(state);
226 self.background_fill.hash(state);
227 self.visible_tiles.hash(state);
228 self.prefetch_tiles.hash(state);
229 self.max_prefetch_tiles_per_frame.hash(state);
230 self.max_prefetch_ms_per_frame.hash(state);
231 }
232}
233
234impl ScenePrimitive {
235 pub(crate) fn contains_shadow(&self) -> bool {
236 match self {
237 Self::CompositingLayer { spec, commands, .. } => {
238 spec.shadow.is_some() || commands.iter().any(Self::contains_shadow)
239 }
240 Self::StaticLayer { commands, .. }
241 | Self::ScrollRaster { commands, .. }
242 | Self::Clip { commands, .. }
243 | Self::ClipPath { commands, .. } => commands.iter().any(Self::contains_shadow),
244 _ => false,
245 }
246 }
247
248 pub const fn kind(&self) -> ScenePrimitiveKind {
249 match self {
250 Self::Rect { .. } => ScenePrimitiveKind::Rect,
251 Self::Ellipse { .. } => ScenePrimitiveKind::Ellipse,
252 Self::Text { .. } => ScenePrimitiveKind::Text,
253 Self::Custom { .. } => ScenePrimitiveKind::Custom,
254 Self::Line { .. } => ScenePrimitiveKind::Line,
255 Self::Path { .. } => ScenePrimitiveKind::Path,
256 Self::Image { .. } => ScenePrimitiveKind::Image,
257 Self::Icon { .. } => ScenePrimitiveKind::Icon,
258 Self::Glow { .. } => ScenePrimitiveKind::Glow,
259 Self::BackdropBlur { .. } => ScenePrimitiveKind::BackdropBlur,
260 Self::BackdropBlurPath { .. } => ScenePrimitiveKind::BackdropBlurPath,
261 Self::Overlay { .. } => ScenePrimitiveKind::Overlay,
262 Self::CompositingLayer { .. } => ScenePrimitiveKind::CompositingLayer,
263 Self::StaticLayer { .. } => ScenePrimitiveKind::StaticLayer,
264 Self::ScrollRaster { .. } => ScenePrimitiveKind::ScrollRaster,
265 Self::Clip { .. } => ScenePrimitiveKind::Clip,
266 Self::ClipPath { .. } => ScenePrimitiveKind::ClipPath,
267 }
268 }
269
270 pub fn id(&self) -> &UiId {
271 match self {
272 ScenePrimitive::Rect { id, .. }
273 | ScenePrimitive::Ellipse { id, .. }
274 | ScenePrimitive::Text { id, .. }
275 | ScenePrimitive::Custom { id, .. }
276 | ScenePrimitive::Line { id, .. }
277 | ScenePrimitive::Path { id, .. }
278 | ScenePrimitive::Image { id, .. }
279 | ScenePrimitive::Icon { id, .. }
280 | ScenePrimitive::Glow { id, .. }
281 | ScenePrimitive::BackdropBlur { id, .. }
282 | ScenePrimitive::BackdropBlurPath { id, .. }
283 | ScenePrimitive::Overlay { id, .. }
284 | ScenePrimitive::CompositingLayer { id, .. }
285 | ScenePrimitive::StaticLayer { id, .. }
286 | ScenePrimitive::ScrollRaster { id, .. }
287 | ScenePrimitive::Clip { id, .. }
288 | ScenePrimitive::ClipPath { id, .. } => id,
289 }
290 }
291
292 pub fn phase(&self) -> RenderPhase {
293 match self {
294 ScenePrimitive::Rect { phase, .. }
295 | ScenePrimitive::Ellipse { phase, .. }
296 | ScenePrimitive::Text { phase, .. }
297 | ScenePrimitive::Custom { phase, .. }
298 | ScenePrimitive::Line { phase, .. }
299 | ScenePrimitive::Path { phase, .. }
300 | ScenePrimitive::Image { phase, .. }
301 | ScenePrimitive::Icon { phase, .. }
302 | ScenePrimitive::Glow { phase, .. }
303 | ScenePrimitive::BackdropBlur { phase, .. }
304 | ScenePrimitive::BackdropBlurPath { phase, .. }
305 | ScenePrimitive::Overlay { phase, .. }
306 | ScenePrimitive::CompositingLayer { phase, .. }
307 | ScenePrimitive::StaticLayer { phase, .. }
308 | ScenePrimitive::ScrollRaster { phase, .. }
309 | ScenePrimitive::Clip { phase, .. }
310 | ScenePrimitive::ClipPath { phase, .. } => *phase,
311 }
312 }
313
314 pub fn rect(&self) -> UiRect {
315 match self {
316 ScenePrimitive::Rect { rect, .. }
317 | ScenePrimitive::Ellipse { rect, .. }
318 | ScenePrimitive::Text { rect, .. }
319 | ScenePrimitive::Custom { rect, .. }
320 | ScenePrimitive::Image { rect, .. }
321 | ScenePrimitive::Path { rect, .. }
322 | ScenePrimitive::Icon { rect, .. }
323 | ScenePrimitive::Glow { rect, .. }
324 | ScenePrimitive::BackdropBlur { rect, .. }
325 | ScenePrimitive::BackdropBlurPath { rect, .. }
326 | ScenePrimitive::Overlay { rect, .. } => *rect,
327 ScenePrimitive::CompositingLayer { rect, .. } => *rect,
328 ScenePrimitive::StaticLayer { rect, spec, .. } => {
329 rect.translate(spec.offset_x, spec.offset_y)
330 }
331 ScenePrimitive::ScrollRaster { viewport, .. } => *viewport,
332 ScenePrimitive::Clip { rect, .. } | ScenePrimitive::ClipPath { rect, .. } => *rect,
333 ScenePrimitive::Line { start, end, .. } => UiRect::new(
334 start.x.min(end.x),
335 start.y.min(end.y),
336 start.x.max(end.x) + 1.0,
337 start.y.max(end.y) + 1.0,
338 ),
339 }
340 }
341
342 pub fn paint_bounds(&self) -> UiRect {
343 let rect = match self {
344 ScenePrimitive::CompositingLayer { rect, spec, .. } => {
345 spec.transform.transformed_bounds(*rect)
346 }
347 _ => self.rect(),
348 };
349 let stroke_width = match self {
350 ScenePrimitive::Rect { style, .. } | ScenePrimitive::Ellipse { style, .. } => {
351 style.stroke.map(|stroke| stroke.width).unwrap_or(0.0)
352 }
353 ScenePrimitive::Line { stroke, .. } => stroke.width,
354 ScenePrimitive::Path { style, .. } => {
355 style.stroke.map(|stroke| stroke.width).unwrap_or(0.0)
356 }
357 _ => 0.0,
358 };
359 let outset = (stroke_width.max(0.0) + 1.0) / 2.0;
360 rect.inflate(outset, outset)
361 }
362
363 pub fn signature(&self) -> u64 {
364 let mut hasher = DefaultHasher::new();
365 command_signature_part(self, &mut hasher);
366 hasher.finish()
367 }
368}