Skip to main content

iced_tiny_skia/
layer.rs

1use crate::Primitive;
2use crate::core::renderer::Quad;
3use crate::core::{self, Background, Color, Point, Rectangle, Svg, Transformation};
4use crate::graphics::damage;
5use crate::graphics::layer;
6use crate::graphics::text::{Editor, Paragraph, Text};
7use crate::graphics::{self, Image};
8
9use std::sync::Arc;
10
11pub type Stack = layer::Stack<Layer>;
12
13#[derive(Debug, Clone)]
14pub struct Layer {
15    pub bounds: Rectangle,
16    pub quads: Vec<(Quad, Background)>,
17    pub primitives: Vec<Item<Primitive>>,
18    pub images: Vec<Image>,
19    pub text: Vec<Item<Text>>,
20}
21
22impl Layer {
23    pub fn draw_quad(
24        &mut self,
25        mut quad: Quad,
26        background: Background,
27        transformation: Transformation,
28    ) {
29        quad.bounds = quad.bounds * transformation;
30        self.quads.push((quad, background));
31    }
32
33    pub fn draw_paragraph(
34        &mut self,
35        paragraph: &Paragraph,
36        position: Point,
37        color: Color,
38        clip_bounds: Rectangle,
39        transformation: Transformation,
40    ) {
41        let paragraph = Text::Paragraph {
42            paragraph: paragraph.downgrade(),
43            position,
44            color,
45            clip_bounds,
46            transformation,
47        };
48
49        self.text.push(Item::Live(paragraph));
50    }
51
52    pub fn draw_editor(
53        &mut self,
54        editor: &Editor,
55        position: Point,
56        color: Color,
57        clip_bounds: Rectangle,
58        transformation: Transformation,
59    ) {
60        let editor = Text::Editor {
61            editor: editor.downgrade(),
62            position,
63            color,
64            clip_bounds,
65            transformation,
66        };
67
68        self.text.push(Item::Live(editor));
69    }
70
71    pub fn draw_text(
72        &mut self,
73        text: core::Text,
74        position: Point,
75        color: Color,
76        clip_bounds: Rectangle,
77        transformation: Transformation,
78    ) {
79        let text = Text::Cached {
80            content: text.content,
81            bounds: Rectangle::new(position, text.bounds) * transformation,
82            color,
83            size: text.size * transformation.scale_factor(),
84            line_height: text.line_height.to_absolute(text.size) * transformation.scale_factor(),
85            font: text.font,
86            align_x: text.align_x,
87            align_y: text.align_y,
88            shaping: text.shaping,
89            wrapping: text.wrapping,
90            ellipsis: text.ellipsis,
91            clip_bounds: clip_bounds * transformation,
92        };
93
94        self.text.push(Item::Live(text));
95    }
96
97    pub fn draw_text_raw(&mut self, raw: graphics::text::Raw, transformation: Transformation) {
98        let raw = Text::Raw {
99            raw,
100            transformation,
101        };
102
103        self.text.push(Item::Live(raw));
104    }
105
106    pub fn draw_text_group(
107        &mut self,
108        text: Vec<Text>,
109        clip_bounds: Rectangle,
110        transformation: Transformation,
111    ) {
112        self.text
113            .push(Item::Group(text, clip_bounds, transformation));
114    }
115
116    pub fn draw_text_cache(
117        &mut self,
118        text: Arc<[Text]>,
119        clip_bounds: Rectangle,
120        transformation: Transformation,
121    ) {
122        self.text
123            .push(Item::Cached(text, clip_bounds, transformation));
124    }
125
126    pub fn draw_image(&mut self, image: Image, transformation: Transformation) {
127        match image {
128            Image::Raster {
129                image,
130                bounds,
131                clip_bounds,
132            } => {
133                self.draw_raster(image, bounds, clip_bounds, transformation);
134            }
135            Image::Vector {
136                svg,
137                bounds,
138                clip_bounds,
139            } => {
140                self.draw_svg(svg, bounds, clip_bounds, transformation);
141            }
142        }
143    }
144
145    pub fn draw_raster(
146        &mut self,
147        image: core::Image,
148        bounds: Rectangle,
149        clip_bounds: Rectangle,
150        transformation: Transformation,
151    ) {
152        let image = Image::Raster {
153            image: core::Image {
154                border_radius: image.border_radius * transformation.scale_factor(),
155                ..image
156            },
157            bounds: bounds * transformation,
158            clip_bounds: clip_bounds * transformation,
159        };
160
161        self.images.push(image);
162    }
163
164    pub fn draw_svg(
165        &mut self,
166        svg: Svg,
167        bounds: Rectangle,
168        clip_bounds: Rectangle,
169        transformation: Transformation,
170    ) {
171        let svg = Image::Vector {
172            svg,
173            bounds: bounds * transformation,
174            clip_bounds: clip_bounds * transformation,
175        };
176
177        self.images.push(svg);
178    }
179
180    pub fn draw_primitive_group(
181        &mut self,
182        primitives: Vec<Primitive>,
183        clip_bounds: Rectangle,
184        transformation: Transformation,
185    ) {
186        self.primitives.push(Item::Group(
187            primitives,
188            clip_bounds * transformation,
189            transformation,
190        ));
191    }
192
193    pub fn draw_primitive_cache(
194        &mut self,
195        primitives: Arc<[Primitive]>,
196        clip_bounds: Rectangle,
197        transformation: Transformation,
198    ) {
199        self.primitives.push(Item::Cached(
200            primitives,
201            clip_bounds * transformation,
202            transformation,
203        ));
204    }
205
206    pub fn damage(previous: &Self, current: &Self) -> Vec<Rectangle> {
207        if previous.bounds != current.bounds {
208            return vec![previous.bounds, current.bounds];
209        }
210
211        let layer_bounds = current.bounds.expand(1.0);
212
213        let mut damage = damage::list(
214            &previous.quads,
215            &current.quads,
216            |(quad, _)| {
217                let Some(bounds) = quad.bounds.expand(1.0).intersection(&layer_bounds) else {
218                    return vec![];
219                };
220
221                vec![if quad.shadow.color.a > 0.0 {
222                    bounds.expand(
223                        quad.shadow.offset.x.abs().max(quad.shadow.offset.y.abs())
224                            + quad.shadow.blur_radius,
225                    )
226                } else {
227                    bounds
228                }]
229            },
230            |(quad_a, background_a), (quad_b, background_b)| {
231                quad_a == quad_b && background_a == background_b
232            },
233        );
234
235        let text = damage::diff(
236            &previous.text,
237            &current.text,
238            |item| {
239                item.as_slice()
240                    .iter()
241                    .filter_map(Text::visible_bounds)
242                    .map(|bounds| bounds * item.transformation())
243                    .collect()
244            },
245            |text_a, text_b| {
246                damage::list(
247                    text_a.as_slice(),
248                    text_b.as_slice(),
249                    |text| {
250                        text.visible_bounds()
251                            .into_iter()
252                            .map(|bounds| bounds * text_a.transformation())
253                            .collect()
254                    },
255                    |text_a, text_b| text_a == text_b,
256                )
257            },
258        );
259
260        let primitives = damage::list(
261            &previous.primitives,
262            &current.primitives,
263            |item| match item {
264                Item::Live(primitive) => vec![primitive.visible_bounds()],
265                Item::Group(primitives, group_bounds, transformation) => primitives
266                    .as_slice()
267                    .iter()
268                    .map(Primitive::visible_bounds)
269                    .map(|bounds| bounds * *transformation)
270                    .filter_map(|bounds| bounds.intersection(group_bounds))
271                    .collect(),
272                Item::Cached(_primitives, bounds, _transformation) => {
273                    vec![*bounds]
274                }
275            },
276            |primitive_a, primitive_b| match (primitive_a, primitive_b) {
277                (
278                    Item::Cached(cache_a, bounds_a, transformation_a),
279                    Item::Cached(cache_b, bounds_b, transformation_b),
280                ) => {
281                    Arc::ptr_eq(cache_a, cache_b)
282                        && bounds_a == bounds_b
283                        && transformation_a == transformation_b
284                }
285                _ => false,
286            },
287        );
288
289        let images = damage::list(
290            &previous.images,
291            &current.images,
292            |image| vec![image.bounds().expand(1.0)],
293            Image::eq,
294        );
295
296        damage.extend(text);
297        damage.extend(primitives);
298        damage.extend(images);
299        damage
300    }
301}
302
303impl Default for Layer {
304    fn default() -> Self {
305        Self {
306            bounds: Rectangle::INFINITE,
307            quads: Vec::new(),
308            primitives: Vec::new(),
309            text: Vec::new(),
310            images: Vec::new(),
311        }
312    }
313}
314
315impl graphics::Layer for Layer {
316    fn with_bounds(bounds: Rectangle) -> Self {
317        Self {
318            bounds,
319            ..Self::default()
320        }
321    }
322
323    fn bounds(&self) -> Rectangle {
324        self.bounds
325    }
326
327    fn flush(&mut self) {}
328
329    fn resize(&mut self, bounds: Rectangle) {
330        self.bounds = bounds;
331    }
332
333    fn reset(&mut self) {
334        self.bounds = Rectangle::INFINITE;
335
336        self.quads.clear();
337        self.primitives.clear();
338        self.text.clear();
339        self.images.clear();
340    }
341
342    fn start(&self) -> usize {
343        if !self.quads.is_empty() {
344            return 1;
345        }
346
347        if !self.primitives.is_empty() {
348            return 2;
349        }
350
351        if !self.images.is_empty() {
352            return 3;
353        }
354
355        if !self.text.is_empty() {
356            return 4;
357        }
358
359        usize::MAX
360    }
361
362    fn end(&self) -> usize {
363        if !self.text.is_empty() {
364            return 4;
365        }
366
367        if !self.images.is_empty() {
368            return 3;
369        }
370
371        if !self.primitives.is_empty() {
372            return 2;
373        }
374
375        if !self.quads.is_empty() {
376            return 1;
377        }
378
379        0
380    }
381
382    fn merge(&mut self, layer: &mut Self) {
383        self.quads.append(&mut layer.quads);
384        self.primitives.append(&mut layer.primitives);
385        self.text.append(&mut layer.text);
386        self.images.append(&mut layer.images);
387    }
388}
389
390#[derive(Debug, Clone)]
391pub enum Item<T> {
392    Live(T),
393    Group(Vec<T>, Rectangle, Transformation),
394    Cached(Arc<[T]>, Rectangle, Transformation),
395}
396
397impl<T> Item<T> {
398    pub fn transformation(&self) -> Transformation {
399        match self {
400            Item::Live(_) => Transformation::IDENTITY,
401            Item::Group(_, _, transformation) | Item::Cached(_, _, transformation) => {
402                *transformation
403            }
404        }
405    }
406
407    pub fn clip_bounds(&self) -> Rectangle {
408        match self {
409            Item::Live(_) => Rectangle::INFINITE,
410            Item::Group(_, clip_bounds, _) | Item::Cached(_, clip_bounds, _) => *clip_bounds,
411        }
412    }
413
414    pub fn as_slice(&self) -> &[T] {
415        match self {
416            Item::Live(item) => std::slice::from_ref(item),
417            Item::Group(group, _, _) => group.as_slice(),
418            Item::Cached(cache, _, _) => cache,
419        }
420    }
421}