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 ¤t.quads,
207 |(quad, _)| {
208 quad.bounds
209 .expand(1.0)
210 .intersection(¤t.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 ¤t.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 ¤t.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 ¤t.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}