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            clip_bounds: clip_bounds * transformation,
90        };
91
92        self.text.push(Item::Live(text));
93    }
94
95    pub fn draw_text_raw(&mut self, raw: graphics::text::Raw, transformation: Transformation) {
96        let raw = Text::Raw {
97            raw,
98            transformation,
99        };
100
101        self.text.push(Item::Live(raw));
102    }
103
104    pub fn draw_text_group(
105        &mut self,
106        text: Vec<Text>,
107        clip_bounds: Rectangle,
108        transformation: Transformation,
109    ) {
110        self.text
111            .push(Item::Group(text, clip_bounds, transformation));
112    }
113
114    pub fn draw_text_cache(
115        &mut self,
116        text: Arc<[Text]>,
117        clip_bounds: Rectangle,
118        transformation: Transformation,
119    ) {
120        self.text
121            .push(Item::Cached(text, clip_bounds, transformation));
122    }
123
124    pub fn draw_image(&mut self, image: Image, transformation: Transformation) {
125        match image {
126            Image::Raster {
127                image,
128                bounds,
129                clip_bounds,
130            } => {
131                self.draw_raster(image, bounds, clip_bounds, transformation);
132            }
133            Image::Vector {
134                svg,
135                bounds,
136                clip_bounds,
137            } => {
138                self.draw_svg(svg, bounds, clip_bounds, transformation);
139            }
140        }
141    }
142
143    pub fn draw_raster(
144        &mut self,
145        image: core::Image,
146        bounds: Rectangle,
147        clip_bounds: Rectangle,
148        transformation: Transformation,
149    ) {
150        let image = Image::Raster {
151            image: core::Image {
152                border_radius: image.border_radius * transformation.scale_factor(),
153                ..image
154            },
155            bounds: bounds * transformation,
156            clip_bounds: clip_bounds * transformation,
157        };
158
159        self.images.push(image);
160    }
161
162    pub fn draw_svg(
163        &mut self,
164        svg: Svg,
165        bounds: Rectangle,
166        clip_bounds: Rectangle,
167        transformation: Transformation,
168    ) {
169        let svg = Image::Vector {
170            svg,
171            bounds: bounds * transformation,
172            clip_bounds: clip_bounds * transformation,
173        };
174
175        self.images.push(svg);
176    }
177
178    pub fn draw_primitive_group(
179        &mut self,
180        primitives: Vec<Primitive>,
181        clip_bounds: Rectangle,
182        transformation: Transformation,
183    ) {
184        self.primitives.push(Item::Group(
185            primitives,
186            clip_bounds * transformation,
187            transformation,
188        ));
189    }
190
191    pub fn draw_primitive_cache(
192        &mut self,
193        primitives: Arc<[Primitive]>,
194        clip_bounds: Rectangle,
195        transformation: Transformation,
196    ) {
197        self.primitives.push(Item::Cached(
198            primitives,
199            clip_bounds * transformation,
200            transformation,
201        ));
202    }
203
204    pub fn damage(previous: &Self, current: &Self) -> Vec<Rectangle> {
205        if previous.bounds != current.bounds {
206            return vec![previous.bounds, current.bounds];
207        }
208
209        let mut damage = damage::list(
210            &previous.quads,
211            &current.quads,
212            |(quad, _)| {
213                quad.bounds
214                    .expand(1.0)
215                    .intersection(&current.bounds)
216                    .into_iter()
217                    .collect()
218            },
219            |(quad_a, background_a), (quad_b, background_b)| {
220                quad_a == quad_b && background_a == background_b
221            },
222        );
223
224        let text = damage::diff(
225            &previous.text,
226            &current.text,
227            |item| {
228                item.as_slice()
229                    .iter()
230                    .filter_map(Text::visible_bounds)
231                    .map(|bounds| bounds * item.transformation())
232                    .collect()
233            },
234            |text_a, text_b| {
235                damage::list(
236                    text_a.as_slice(),
237                    text_b.as_slice(),
238                    |text| {
239                        text.visible_bounds()
240                            .into_iter()
241                            .map(|bounds| bounds * text_a.transformation())
242                            .collect()
243                    },
244                    |text_a, text_b| text_a == text_b,
245                )
246            },
247        );
248
249        let primitives = damage::list(
250            &previous.primitives,
251            &current.primitives,
252            |item| match item {
253                Item::Live(primitive) => vec![primitive.visible_bounds()],
254                Item::Group(primitives, group_bounds, transformation) => primitives
255                    .as_slice()
256                    .iter()
257                    .map(Primitive::visible_bounds)
258                    .map(|bounds| bounds * *transformation)
259                    .filter_map(|bounds| bounds.intersection(group_bounds))
260                    .collect(),
261                Item::Cached(_, bounds, transformation) => {
262                    vec![*bounds * *transformation]
263                }
264            },
265            |primitive_a, primitive_b| match (primitive_a, primitive_b) {
266                (
267                    Item::Cached(cache_a, bounds_a, transformation_a),
268                    Item::Cached(cache_b, bounds_b, transformation_b),
269                ) => {
270                    Arc::ptr_eq(cache_a, cache_b)
271                        && bounds_a == bounds_b
272                        && transformation_a == transformation_b
273                }
274                _ => false,
275            },
276        );
277
278        let images = damage::list(
279            &previous.images,
280            &current.images,
281            |image| vec![image.bounds().expand(1.0)],
282            Image::eq,
283        );
284
285        damage.extend(text);
286        damage.extend(primitives);
287        damage.extend(images);
288        damage
289    }
290}
291
292impl Default for Layer {
293    fn default() -> Self {
294        Self {
295            bounds: Rectangle::INFINITE,
296            quads: Vec::new(),
297            primitives: Vec::new(),
298            text: Vec::new(),
299            images: Vec::new(),
300        }
301    }
302}
303
304impl graphics::Layer for Layer {
305    fn with_bounds(bounds: Rectangle) -> Self {
306        Self {
307            bounds,
308            ..Self::default()
309        }
310    }
311
312    fn bounds(&self) -> Rectangle {
313        self.bounds
314    }
315
316    fn flush(&mut self) {}
317
318    fn resize(&mut self, bounds: Rectangle) {
319        self.bounds = bounds;
320    }
321
322    fn reset(&mut self) {
323        self.bounds = Rectangle::INFINITE;
324
325        self.quads.clear();
326        self.primitives.clear();
327        self.text.clear();
328        self.images.clear();
329    }
330
331    fn start(&self) -> usize {
332        if !self.quads.is_empty() {
333            return 1;
334        }
335
336        if !self.primitives.is_empty() {
337            return 2;
338        }
339
340        if !self.images.is_empty() {
341            return 3;
342        }
343
344        if !self.text.is_empty() {
345            return 4;
346        }
347
348        usize::MAX
349    }
350
351    fn end(&self) -> usize {
352        if !self.text.is_empty() {
353            return 4;
354        }
355
356        if !self.images.is_empty() {
357            return 3;
358        }
359
360        if !self.primitives.is_empty() {
361            return 2;
362        }
363
364        if !self.quads.is_empty() {
365            return 1;
366        }
367
368        0
369    }
370
371    fn merge(&mut self, layer: &mut Self) {
372        self.quads.append(&mut layer.quads);
373        self.primitives.append(&mut layer.primitives);
374        self.text.append(&mut layer.text);
375        self.images.append(&mut layer.images);
376    }
377}
378
379#[derive(Debug, Clone)]
380pub enum Item<T> {
381    Live(T),
382    Group(Vec<T>, Rectangle, Transformation),
383    Cached(Arc<[T]>, Rectangle, Transformation),
384}
385
386impl<T> Item<T> {
387    pub fn transformation(&self) -> Transformation {
388        match self {
389            Item::Live(_) => Transformation::IDENTITY,
390            Item::Group(_, _, transformation) | Item::Cached(_, _, transformation) => {
391                *transformation
392            }
393        }
394    }
395
396    pub fn clip_bounds(&self) -> Rectangle {
397        match self {
398            Item::Live(_) => Rectangle::INFINITE,
399            Item::Group(_, clip_bounds, _) | Item::Cached(_, clip_bounds, _) => *clip_bounds,
400        }
401    }
402
403    pub fn as_slice(&self) -> &[T] {
404        match self {
405            Item::Live(item) => std::slice::from_ref(item),
406            Item::Group(group, _, _) => group.as_slice(),
407            Item::Cached(cache, _, _) => cache,
408        }
409    }
410}