1use serde::Deserialize;
2use serde_json::json;
3use std::{borrow::Cow, sync::Arc};
4
5use crate::{
6 color::Color,
7 fonts::{FontId, GlyphId},
8 geometry::{rect::RectF, vector::Vector2F},
9 json::ToJson,
10 ImageData,
11};
12
13pub struct Scene {
14 scale_factor: f32,
15 stacking_contexts: Vec<StackingContext>,
16 active_stacking_context_stack: Vec<usize>,
17}
18
19struct StackingContext {
20 layers: Vec<Layer>,
21 active_layer_stack: Vec<usize>,
22}
23
24#[derive(Default)]
25pub struct Layer {
26 clip_bounds: Option<RectF>,
27 quads: Vec<Quad>,
28 underlines: Vec<Underline>,
29 images: Vec<Image>,
30 shadows: Vec<Shadow>,
31 glyphs: Vec<Glyph>,
32 image_glyphs: Vec<ImageGlyph>,
33 icons: Vec<Icon>,
34 paths: Vec<Path>,
35}
36
37#[derive(Default, Debug)]
38pub struct Quad {
39 pub bounds: RectF,
40 pub background: Option<Color>,
41 pub border: Border,
42 pub corner_radius: f32,
43}
44
45#[derive(Debug)]
46pub struct Shadow {
47 pub bounds: RectF,
48 pub corner_radius: f32,
49 pub sigma: f32,
50 pub color: Color,
51}
52
53#[derive(Debug)]
54pub struct Glyph {
55 pub font_id: FontId,
56 pub font_size: f32,
57 pub id: GlyphId,
58 pub origin: Vector2F,
59 pub color: Color,
60}
61
62#[derive(Debug)]
63pub struct ImageGlyph {
64 pub font_id: FontId,
65 pub font_size: f32,
66 pub id: GlyphId,
67 pub origin: Vector2F,
68}
69
70pub struct Icon {
71 pub bounds: RectF,
72 pub svg: usvg::Tree,
73 pub path: Cow<'static, str>,
74 pub color: Color,
75}
76
77#[derive(Clone, Copy, Default, Debug)]
78pub struct Border {
79 pub width: f32,
80 pub color: Color,
81 pub overlay: bool,
82 pub top: bool,
83 pub right: bool,
84 pub bottom: bool,
85 pub left: bool,
86}
87
88#[derive(Clone, Copy, Default, Debug)]
89pub struct Underline {
90 pub origin: Vector2F,
91 pub width: f32,
92 pub thickness: f32,
93 pub color: Color,
94 pub squiggly: bool,
95}
96
97impl<'de> Deserialize<'de> for Border {
98 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99 where
100 D: serde::Deserializer<'de>,
101 {
102 #[derive(Deserialize)]
103 struct BorderData {
104 pub width: f32,
105 pub color: Color,
106 #[serde(default)]
107 pub overlay: bool,
108 #[serde(default)]
109 pub top: bool,
110 #[serde(default)]
111 pub right: bool,
112 #[serde(default)]
113 pub bottom: bool,
114 #[serde(default)]
115 pub left: bool,
116 }
117
118 let data = BorderData::deserialize(deserializer)?;
119 let mut border = Border {
120 width: data.width,
121 color: data.color,
122 overlay: data.overlay,
123 top: data.top,
124 bottom: data.bottom,
125 left: data.left,
126 right: data.right,
127 };
128 if !border.top && !border.bottom && !border.left && !border.right {
129 border.top = true;
130 border.bottom = true;
131 border.left = true;
132 border.right = true;
133 }
134 Ok(border)
135 }
136}
137
138#[derive(Debug)]
139pub struct Path {
140 pub bounds: RectF,
141 pub color: Color,
142 pub vertices: Vec<PathVertex>,
143}
144
145#[derive(Debug)]
146pub struct PathVertex {
147 pub xy_position: Vector2F,
148 pub st_position: Vector2F,
149}
150
151pub struct Image {
152 pub bounds: RectF,
153 pub border: Border,
154 pub corner_radius: f32,
155 pub data: Arc<ImageData>,
156}
157
158impl Scene {
159 pub fn new(scale_factor: f32) -> Self {
160 let stacking_context = StackingContext::new(None);
161 Scene {
162 scale_factor,
163 stacking_contexts: vec![stacking_context],
164 active_stacking_context_stack: vec![0],
165 }
166 }
167
168 pub fn scale_factor(&self) -> f32 {
169 self.scale_factor
170 }
171
172 pub fn layers(&self) -> impl Iterator<Item = &Layer> {
173 self.stacking_contexts.iter().flat_map(|s| &s.layers)
174 }
175
176 pub fn push_stacking_context(&mut self, clip_bounds: Option<RectF>) {
177 self.active_stacking_context_stack
178 .push(self.stacking_contexts.len());
179 self.stacking_contexts
180 .push(StackingContext::new(clip_bounds))
181 }
182
183 pub fn pop_stacking_context(&mut self) {
184 self.active_stacking_context_stack.pop();
185 assert!(!self.active_stacking_context_stack.is_empty());
186 }
187
188 pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
189 self.active_stacking_context().push_layer(clip_bounds);
190 }
191
192 pub fn pop_layer(&mut self) {
193 self.active_stacking_context().pop_layer();
194 }
195
196 pub fn push_quad(&mut self, quad: Quad) {
197 self.active_layer().push_quad(quad)
198 }
199
200 pub fn push_image(&mut self, image: Image) {
201 self.active_layer().push_image(image)
202 }
203
204 pub fn push_underline(&mut self, underline: Underline) {
205 self.active_layer().push_underline(underline)
206 }
207
208 pub fn push_shadow(&mut self, shadow: Shadow) {
209 self.active_layer().push_shadow(shadow)
210 }
211
212 pub fn push_glyph(&mut self, glyph: Glyph) {
213 self.active_layer().push_glyph(glyph)
214 }
215
216 pub fn push_image_glyph(&mut self, image_glyph: ImageGlyph) {
217 self.active_layer().push_image_glyph(image_glyph)
218 }
219
220 pub fn push_icon(&mut self, icon: Icon) {
221 self.active_layer().push_icon(icon)
222 }
223
224 pub fn push_path(&mut self, path: Path) {
225 self.active_layer().push_path(path);
226 }
227
228 fn active_stacking_context(&mut self) -> &mut StackingContext {
229 let ix = *self.active_stacking_context_stack.last().unwrap();
230 &mut self.stacking_contexts[ix]
231 }
232
233 fn active_layer(&mut self) -> &mut Layer {
234 self.active_stacking_context().active_layer()
235 }
236}
237
238impl StackingContext {
239 fn new(clip_bounds: Option<RectF>) -> Self {
240 Self {
241 layers: vec![Layer::new(clip_bounds)],
242 active_layer_stack: vec![0],
243 }
244 }
245
246 fn active_layer(&mut self) -> &mut Layer {
247 &mut self.layers[*self.active_layer_stack.last().unwrap()]
248 }
249
250 fn push_layer(&mut self, clip_bounds: Option<RectF>) {
251 let parent_clip_bounds = self.active_layer().clip_bounds();
252 let clip_bounds = clip_bounds
253 .map(|clip_bounds| {
254 clip_bounds
255 .intersection(parent_clip_bounds.unwrap_or(clip_bounds))
256 .unwrap_or_else(|| {
257 if !clip_bounds.is_empty() {
258 log::warn!("specified clip bounds are disjoint from parent layer");
259 }
260 RectF::default()
261 })
262 })
263 .or(parent_clip_bounds);
264
265 let ix = self.layers.len();
266 self.layers.push(Layer::new(clip_bounds));
267 self.active_layer_stack.push(ix);
268 }
269
270 fn pop_layer(&mut self) {
271 self.active_layer_stack.pop().unwrap();
272 assert!(!self.active_layer_stack.is_empty());
273 }
274}
275
276impl Layer {
277 pub fn new(clip_bounds: Option<RectF>) -> Self {
278 Self {
279 clip_bounds,
280 quads: Default::default(),
281 underlines: Default::default(),
282 images: Default::default(),
283 shadows: Default::default(),
284 image_glyphs: Default::default(),
285 glyphs: Default::default(),
286 icons: Default::default(),
287 paths: Default::default(),
288 }
289 }
290
291 pub fn clip_bounds(&self) -> Option<RectF> {
292 self.clip_bounds
293 }
294
295 fn push_quad(&mut self, quad: Quad) {
296 if can_draw(quad.bounds) {
297 self.quads.push(quad);
298 }
299 }
300
301 pub fn quads(&self) -> &[Quad] {
302 self.quads.as_slice()
303 }
304
305 fn push_underline(&mut self, underline: Underline) {
306 if underline.width > 0. {
307 self.underlines.push(underline);
308 }
309 }
310
311 pub fn underlines(&self) -> &[Underline] {
312 self.underlines.as_slice()
313 }
314
315 fn push_image(&mut self, image: Image) {
316 if can_draw(image.bounds) {
317 self.images.push(image);
318 }
319 }
320
321 pub fn images(&self) -> &[Image] {
322 self.images.as_slice()
323 }
324
325 fn push_shadow(&mut self, shadow: Shadow) {
326 if can_draw(shadow.bounds) {
327 self.shadows.push(shadow);
328 }
329 }
330
331 pub fn shadows(&self) -> &[Shadow] {
332 self.shadows.as_slice()
333 }
334
335 fn push_image_glyph(&mut self, glyph: ImageGlyph) {
336 self.image_glyphs.push(glyph);
337 }
338
339 pub fn image_glyphs(&self) -> &[ImageGlyph] {
340 self.image_glyphs.as_slice()
341 }
342
343 fn push_glyph(&mut self, glyph: Glyph) {
344 self.glyphs.push(glyph);
345 }
346
347 pub fn glyphs(&self) -> &[Glyph] {
348 self.glyphs.as_slice()
349 }
350
351 pub fn push_icon(&mut self, icon: Icon) {
352 if can_draw(icon.bounds) {
353 self.icons.push(icon);
354 }
355 }
356
357 pub fn icons(&self) -> &[Icon] {
358 self.icons.as_slice()
359 }
360
361 fn push_path(&mut self, path: Path) {
362 if can_draw(path.bounds) {
363 self.paths.push(path);
364 }
365 }
366
367 pub fn paths(&self) -> &[Path] {
368 self.paths.as_slice()
369 }
370}
371
372impl Border {
373 pub fn new(width: f32, color: Color) -> Self {
374 Self {
375 width,
376 color,
377 overlay: false,
378 top: false,
379 left: false,
380 bottom: false,
381 right: false,
382 }
383 }
384
385 pub fn all(width: f32, color: Color) -> Self {
386 Self {
387 width,
388 color,
389 overlay: false,
390 top: true,
391 left: true,
392 bottom: true,
393 right: true,
394 }
395 }
396
397 pub fn top(width: f32, color: Color) -> Self {
398 let mut border = Self::new(width, color);
399 border.top = true;
400 border
401 }
402
403 pub fn left(width: f32, color: Color) -> Self {
404 let mut border = Self::new(width, color);
405 border.left = true;
406 border
407 }
408
409 pub fn bottom(width: f32, color: Color) -> Self {
410 let mut border = Self::new(width, color);
411 border.bottom = true;
412 border
413 }
414
415 pub fn right(width: f32, color: Color) -> Self {
416 let mut border = Self::new(width, color);
417 border.right = true;
418 border
419 }
420
421 pub fn with_sides(mut self, top: bool, left: bool, bottom: bool, right: bool) -> Self {
422 self.top = top;
423 self.left = left;
424 self.bottom = bottom;
425 self.right = right;
426 self
427 }
428
429 pub fn top_width(&self) -> f32 {
430 if self.top {
431 self.width
432 } else {
433 0.0
434 }
435 }
436
437 pub fn left_width(&self) -> f32 {
438 if self.left {
439 self.width
440 } else {
441 0.0
442 }
443 }
444}
445
446impl ToJson for Border {
447 fn to_json(&self) -> serde_json::Value {
448 let mut value = json!({});
449 if self.top {
450 value["top"] = json!(self.width);
451 }
452 if self.right {
453 value["right"] = json!(self.width);
454 }
455 if self.bottom {
456 value["bottom"] = json!(self.width);
457 }
458 if self.left {
459 value["left"] = json!(self.width);
460 }
461 value
462 }
463}
464
465fn can_draw(bounds: RectF) -> bool {
466 let size = bounds.size();
467 size.x() > 0. && size.y() > 0.
468}