iced_tiny_skia/
layer.rs

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