iced_tiny_skia/
layer.rs

1use crate::core::renderer::Quad;
2use crate::core::{
3    self, Background, Color, Point, Rectangle, Svg, Transformation,
4};
5use crate::graphics::damage;
6use crate::graphics::layer;
7use crate::graphics::text::{Editor, Paragraph, Raw, Text};
8use crate::graphics::{self, Image};
9use crate::Primitive;
10
11use std::rc::Rc;
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 text: Vec<Item<Text>>,
21    pub images: Vec<Image>,
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            horizontal_alignment: text.horizontal_alignment,
90            vertical_alignment: text.vertical_alignment,
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_group(
99        &mut self,
100        text: Vec<Text>,
101        clip_bounds: Rectangle,
102        transformation: Transformation,
103    ) {
104        self.text
105            .push(Item::Group(text, clip_bounds, transformation));
106    }
107
108    pub fn draw_text_cache(
109        &mut self,
110        text: Rc<[Text]>,
111        clip_bounds: Rectangle,
112        transformation: Transformation,
113    ) {
114        self.text
115            .push(Item::Cached(text, clip_bounds, transformation));
116    }
117
118    pub fn draw_raw(&mut self, raw: Raw, transformation: Transformation) {
119        let text = Text::Raw {
120            raw,
121            transformation,
122        };
123
124        self.text.push(Item::Live(text));
125    }
126
127    pub fn draw_image(&mut self, image: Image, transformation: Transformation) {
128        match image {
129            Image::Raster { handle, bounds } => {
130                self.draw_raster(handle, bounds, transformation);
131            }
132            Image::Vector { handle, bounds } => {
133                self.draw_svg(handle, bounds, transformation);
134            }
135        }
136    }
137
138    pub fn draw_raster(
139        &mut self,
140        image: core::Image,
141        bounds: Rectangle,
142        transformation: Transformation,
143    ) {
144        let image = Image::Raster {
145            handle: crate::core::Image {
146                handle: image.handle,
147                filter_method: image.filter_method,
148                rotation: image.rotation,
149                opacity: image.opacity,
150                snap: image.snap,
151                border_radius: image.border_radius,
152            },
153            bounds: bounds * transformation,
154        };
155
156        self.images.push(image);
157    }
158
159    pub fn draw_svg(
160        &mut self,
161        svg: Svg,
162        bounds: Rectangle,
163        transformation: Transformation,
164    ) {
165        let svg = Image::Vector {
166            handle: svg,
167            bounds: bounds * transformation,
168        };
169
170        self.images.push(svg);
171    }
172
173    pub fn draw_primitive_group(
174        &mut self,
175        primitives: Vec<Primitive>,
176        clip_bounds: Rectangle,
177        transformation: Transformation,
178    ) {
179        self.primitives.push(Item::Group(
180            primitives,
181            clip_bounds,
182            transformation,
183        ));
184    }
185
186    pub fn draw_primitive_cache(
187        &mut self,
188        primitives: Rc<[Primitive]>,
189        clip_bounds: Rectangle,
190        transformation: Transformation,
191    ) {
192        self.primitives.push(Item::Cached(
193            primitives,
194            clip_bounds,
195            transformation,
196        ));
197    }
198
199    pub fn damage(previous: &Self, current: &Self) -> Vec<Rectangle> {
200        if previous.bounds != current.bounds {
201            return vec![previous.bounds, current.bounds];
202        }
203
204        let mut damage = damage::list(
205            &previous.quads,
206            &current.quads,
207            |(quad, _)| {
208                quad.bounds
209                    .expand(1.0)
210                    .intersection(&current.bounds)
211                    .into_iter()
212                    .collect()
213            },
214            |(quad_a, background_a), (quad_b, background_b)| {
215                quad_a == quad_b && background_a == background_b
216            },
217        );
218
219        let text = damage::diff(
220            &previous.text,
221            &current.text,
222            |item| {
223                item.as_slice()
224                    .iter()
225                    .filter_map(Text::visible_bounds)
226                    .map(|bounds| bounds * item.transformation())
227                    .collect()
228            },
229            |text_a, text_b| {
230                damage::list(
231                    text_a.as_slice(),
232                    text_b.as_slice(),
233                    |text| {
234                        text.visible_bounds()
235                            .into_iter()
236                            .map(|bounds| bounds * text_a.transformation())
237                            .collect()
238                    },
239                    |text_a, text_b| text_a == text_b,
240                )
241            },
242        );
243
244        let primitives = damage::list(
245            &previous.primitives,
246            &current.primitives,
247            |item| match item {
248                Item::Live(primitive) => vec![primitive.visible_bounds()],
249                Item::Group(primitives, group_bounds, transformation) => {
250                    primitives
251                        .as_slice()
252                        .iter()
253                        .map(Primitive::visible_bounds)
254                        .map(|bounds| bounds * *transformation)
255                        .filter_map(|bounds| bounds.intersection(group_bounds))
256                        .collect()
257                }
258                Item::Cached(_, bounds, _) => {
259                    vec![*bounds]
260                }
261            },
262            |primitive_a, primitive_b| match (primitive_a, primitive_b) {
263                (
264                    Item::Cached(cache_a, bounds_a, transformation_a),
265                    Item::Cached(cache_b, bounds_b, transformation_b),
266                ) => {
267                    Rc::ptr_eq(cache_a, cache_b)
268                        && bounds_a == bounds_b
269                        && transformation_a == transformation_b
270                }
271                _ => false,
272            },
273        );
274
275        let images = damage::list(
276            &previous.images,
277            &current.images,
278            |image| vec![image.bounds().expand(1.0)],
279            Image::eq,
280        );
281
282        damage.extend(text);
283        damage.extend(primitives);
284        damage.extend(images);
285        damage
286    }
287}
288
289impl Default for Layer {
290    fn default() -> Self {
291        Self {
292            bounds: Rectangle::INFINITE,
293            quads: Vec::new(),
294            primitives: Vec::new(),
295            text: Vec::new(),
296            images: Vec::new(),
297        }
298    }
299}
300
301impl graphics::Layer for Layer {
302    fn with_bounds(bounds: Rectangle) -> Self {
303        Self {
304            bounds,
305            ..Self::default()
306        }
307    }
308
309    fn flush(&mut self) {}
310
311    fn resize(&mut self, bounds: Rectangle) {
312        self.bounds = bounds;
313    }
314
315    fn reset(&mut self) {
316        self.bounds = Rectangle::INFINITE;
317
318        self.quads.clear();
319        self.primitives.clear();
320        self.text.clear();
321        self.images.clear();
322    }
323}
324
325#[derive(Debug, Clone)]
326pub enum Item<T> {
327    Live(T),
328    Group(Vec<T>, Rectangle, Transformation),
329    Cached(Rc<[T]>, Rectangle, Transformation),
330}
331
332impl<T> Item<T> {
333    pub fn transformation(&self) -> Transformation {
334        match self {
335            Item::Live(_) => Transformation::IDENTITY,
336            Item::Group(_, _, transformation)
337            | Item::Cached(_, _, transformation) => *transformation,
338        }
339    }
340
341    pub fn clip_bounds(&self) -> Rectangle {
342        match self {
343            Item::Live(_) => Rectangle::INFINITE,
344            Item::Group(_, clip_bounds, _)
345            | Item::Cached(_, clip_bounds, _) => *clip_bounds,
346        }
347    }
348
349    pub fn as_slice(&self) -> &[T] {
350        match self {
351            Item::Live(item) => std::slice::from_ref(item),
352            Item::Group(group, _, _) => group.as_slice(),
353            Item::Cached(cache, _, _) => cache,
354        }
355    }
356}