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 ¤t.quads,
185 |(quad, _)| {
186 quad.bounds
187 .expand(1.0)
188 .intersection(¤t.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 ¤t.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 ¤t.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 ¤t.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}