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 ¤t.quads,
212 |(quad, _)| {
213 quad.bounds
214 .expand(1.0)
215 .intersection(¤t.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 ¤t.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 ¤t.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 ¤t.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}