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