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