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