gpui/
scene.rs

1// todo("windows"): remove
2#![cfg_attr(windows, allow(dead_code))]
3
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7use crate::{
8    AtlasTextureId, AtlasTile, Background, Bounds, ContentMask, Corners, Edges, Hsla, Pixels,
9    Point, Radians, ScaledPixels, Size, bounds_tree::BoundsTree, point,
10};
11use std::{
12    fmt::Debug,
13    iter::Peekable,
14    ops::{Add, Range, Sub},
15    slice,
16};
17
18#[allow(non_camel_case_types, unused)]
19pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
20
21pub(crate) type DrawOrder = u32;
22
23#[derive(Default)]
24pub(crate) struct Scene {
25    pub(crate) paint_operations: Vec<PaintOperation>,
26    primitive_bounds: BoundsTree<ScaledPixels>,
27    layer_stack: Vec<DrawOrder>,
28    pub(crate) shadows: Vec<Shadow>,
29    pub(crate) shadow_transforms: Vec<TransformationMatrix>,
30    pub(crate) quads: Vec<Quad>,
31    pub(crate) quad_transforms: Vec<TransformationMatrix>,
32    pub(crate) backdrop_blurs: Vec<BackdropBlur>,
33    pub(crate) backdrop_blur_transforms: Vec<TransformationMatrix>,
34    pub(crate) paths: Vec<Path<ScaledPixels>>,
35    pub(crate) underlines: Vec<Underline>,
36    pub(crate) underline_transforms: Vec<TransformationMatrix>,
37    pub(crate) monochrome_sprites: Vec<MonochromeSprite>,
38    pub(crate) subpixel_sprites: Vec<SubpixelSprite>,
39    pub(crate) polychrome_sprites: Vec<PolychromeSprite>,
40    pub(crate) polychrome_sprite_transforms: Vec<TransformationMatrix>,
41    pub(crate) surfaces: Vec<PaintSurface>,
42}
43
44impl Scene {
45    pub fn clear(&mut self) {
46        self.paint_operations.clear();
47        self.primitive_bounds.clear();
48        self.layer_stack.clear();
49        self.paths.clear();
50        self.shadows.clear();
51        self.shadow_transforms.clear();
52        self.quads.clear();
53        self.quad_transforms.clear();
54        self.backdrop_blurs.clear();
55        self.backdrop_blur_transforms.clear();
56        self.underlines.clear();
57        self.underline_transforms.clear();
58        self.monochrome_sprites.clear();
59        self.subpixel_sprites.clear();
60        self.polychrome_sprites.clear();
61        self.polychrome_sprite_transforms.clear();
62        self.surfaces.clear();
63    }
64
65    pub fn len(&self) -> usize {
66        self.paint_operations.len()
67    }
68
69    pub fn push_layer(&mut self, bounds: Bounds<ScaledPixels>) {
70        let order = self.primitive_bounds.insert(bounds);
71        self.layer_stack.push(order);
72        self.paint_operations
73            .push(PaintOperation::StartLayer(bounds));
74    }
75
76    pub fn pop_layer(&mut self) {
77        self.layer_stack.pop();
78        self.paint_operations.push(PaintOperation::EndLayer);
79    }
80
81    pub fn insert_primitive(&mut self, primitive: impl Into<Primitive>) {
82        let mut primitive = primitive.into();
83        let transformed_bounds = transformed_bounds(&primitive);
84        let clipped_bounds = transformed_bounds.intersect(&primitive.content_mask().bounds);
85
86        if clipped_bounds.is_empty() {
87            return;
88        }
89
90        let order = self
91            .layer_stack
92            .last()
93            .copied()
94            .unwrap_or_else(|| self.primitive_bounds.insert(clipped_bounds));
95        match &mut primitive {
96            Primitive::Shadow(shadow, transform) => {
97                shadow.order = order;
98                self.shadows.push(shadow.clone());
99                self.shadow_transforms.push(*transform);
100            }
101            Primitive::Quad(quad, transform) => {
102                quad.order = order;
103                self.quads.push(quad.clone());
104                self.quad_transforms.push(*transform);
105            }
106            Primitive::BackdropBlur(blur, transform) => {
107                blur.order = order;
108                self.backdrop_blurs.push(blur.clone());
109                self.backdrop_blur_transforms.push(*transform);
110            }
111            Primitive::Path(path) => {
112                path.order = order;
113                path.id = PathId(self.paths.len());
114                self.paths.push(path.clone());
115            }
116            Primitive::Underline(underline, transform) => {
117                underline.order = order;
118                self.underlines.push(underline.clone());
119                self.underline_transforms.push(*transform);
120            }
121            Primitive::MonochromeSprite(sprite) => {
122                sprite.order = order;
123                self.monochrome_sprites.push(sprite.clone());
124            }
125            Primitive::SubpixelSprite(sprite) => {
126                sprite.order = order;
127                self.subpixel_sprites.push(sprite.clone());
128            }
129            Primitive::PolychromeSprite(sprite, transform) => {
130                sprite.order = order;
131                self.polychrome_sprites.push(sprite.clone());
132                self.polychrome_sprite_transforms.push(*transform);
133            }
134            Primitive::Surface(surface) => {
135                surface.order = order;
136                self.surfaces.push(surface.clone());
137            }
138        }
139
140        /// Compute an axis-aligned bounding box for a transformed primitive.
141        fn transformed_bounds(primitive: &Primitive) -> Bounds<ScaledPixels> {
142            fn apply_transform(
143                bounds: &Bounds<ScaledPixels>,
144                transform: &TransformationMatrix,
145            ) -> Bounds<ScaledPixels> {
146                if transform.is_unit() {
147                    return *bounds;
148                }
149                let [[a, b], [c, d]] = transform.rotation_scale;
150                let tx = transform.translation[0];
151                let ty = transform.translation[1];
152
153                let x0 = bounds.origin.x.0;
154                let x1 = x0 + bounds.size.width.0;
155                let y0 = bounds.origin.y.0;
156                let y1 = y0 + bounds.size.height.0;
157
158                let ax0 = a * x0;
159                let ax1 = a * x1;
160                let by0 = b * y0;
161                let by1 = b * y1;
162
163                let cx0 = c * x0;
164                let cx1 = c * x1;
165                let dy0 = d * y0;
166                let dy1 = d * y1;
167
168                let min_x = tx + ax0.min(ax1) + by0.min(by1);
169                let max_x = tx + ax0.max(ax1) + by0.max(by1);
170                let min_y = ty + cx0.min(cx1) + dy0.min(dy1);
171                let max_y = ty + cx0.max(cx1) + dy0.max(dy1);
172
173                Bounds {
174                    origin: point(ScaledPixels(min_x), ScaledPixels(min_y)),
175                    size: Size {
176                        width: ScaledPixels((max_x - min_x).max(0.0)),
177                        height: ScaledPixels((max_y - min_y).max(0.0)),
178                    },
179                }
180            }
181
182            match primitive {
183                Primitive::Shadow(shadow, transform) => apply_transform(&shadow.bounds, transform),
184                Primitive::Quad(quad, transform) => apply_transform(&quad.bounds, transform),
185                Primitive::BackdropBlur(blur, transform) => apply_transform(&blur.bounds, transform),
186                Primitive::Underline(underline, transform) => {
187                    apply_transform(&underline.bounds, transform)
188                }
189                Primitive::MonochromeSprite(sprite) => {
190                    apply_transform(&sprite.bounds, &sprite.transformation)
191                }
192                Primitive::PolychromeSprite(sprite, transform) => {
193                    apply_transform(&sprite.bounds, transform)
194                }
195                Primitive::SubpixelSprite(sprite) => {
196                    apply_transform(&sprite.bounds, &sprite.transformation)
197                }
198                Primitive::Path(path) => path.bounds,
199                Primitive::Surface(surface) => surface.bounds,
200            }
201        }
202        self.paint_operations
203            .push(PaintOperation::Primitive(primitive));
204    }
205
206    pub fn replay(&mut self, range: Range<usize>, prev_scene: &Scene) {
207        for operation in &prev_scene.paint_operations[range] {
208            match operation {
209                PaintOperation::Primitive(primitive) => self.insert_primitive(primitive.clone()),
210                PaintOperation::StartLayer(bounds) => self.push_layer(*bounds),
211                PaintOperation::EndLayer => self.pop_layer(),
212            }
213        }
214    }
215
216    fn sort_with_aux_by_key<T, U, K: Ord>(
217        items: &mut Vec<T>,
218        aux: &mut Vec<U>,
219        mut key_fn: impl FnMut(&T) -> K,
220    ) {
221        debug_assert_eq!(items.len(), aux.len());
222        if items.len() <= 1 {
223            return;
224        }
225
226        let mut perm: Vec<usize> = (0..items.len()).collect();
227        perm.sort_by_key(|&index| key_fn(&items[index]));
228
229        let mut desired_pos_by_current_pos = vec![0usize; perm.len()];
230        for (desired_pos, current_pos) in perm.into_iter().enumerate() {
231            desired_pos_by_current_pos[current_pos] = desired_pos;
232        }
233
234        for i in 0..items.len() {
235            while desired_pos_by_current_pos[i] != i {
236                let j = desired_pos_by_current_pos[i];
237                items.swap(i, j);
238                aux.swap(i, j);
239                desired_pos_by_current_pos.swap(i, j);
240            }
241        }
242    }
243
244    pub fn finish(&mut self) {
245        Self::sort_with_aux_by_key(&mut self.shadows, &mut self.shadow_transforms, |shadow| {
246            shadow.order
247        });
248        Self::sort_with_aux_by_key(&mut self.quads, &mut self.quad_transforms, |quad| {
249            quad.order
250        });
251        Self::sort_with_aux_by_key(
252            &mut self.backdrop_blurs,
253            &mut self.backdrop_blur_transforms,
254            |blur| blur.order,
255        );
256        self.paths.sort_by_key(|path| path.order);
257        Self::sort_with_aux_by_key(
258            &mut self.underlines,
259            &mut self.underline_transforms,
260            |underline| underline.order,
261        );
262        self.monochrome_sprites
263            .sort_by_key(|sprite| (sprite.order, sprite.tile.tile_id));
264        self.subpixel_sprites
265            .sort_by_key(|sprite| (sprite.order, sprite.tile.tile_id));
266        self.polychrome_sprites
267            .sort_by_key(|sprite| (sprite.order, sprite.tile.tile_id));
268        Self::sort_with_aux_by_key(
269            &mut self.polychrome_sprites,
270            &mut self.polychrome_sprite_transforms,
271            |sprite| (sprite.order, sprite.tile.tile_id),
272        );
273        self.surfaces.sort_by_key(|surface| surface.order);
274    }
275
276    #[cfg_attr(
277        all(
278            any(target_os = "linux", target_os = "freebsd"),
279            not(any(feature = "x11", feature = "wayland"))
280        ),
281        allow(dead_code)
282    )]
283    pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch<'_>> {
284        BatchIterator {
285            shadows: &self.shadows,
286            shadow_transforms: &self.shadow_transforms,
287            shadows_start: 0,
288            shadows_iter: self.shadows.iter().peekable(),
289            quads: &self.quads,
290            quad_transforms: &self.quad_transforms,
291            quads_start: 0,
292            quads_iter: self.quads.iter().peekable(),
293            backdrop_blurs: &self.backdrop_blurs,
294            backdrop_blur_transforms: &self.backdrop_blur_transforms,
295            backdrop_blurs_start: 0,
296            backdrop_blurs_iter: self.backdrop_blurs.iter().peekable(),
297            paths: &self.paths,
298            paths_start: 0,
299            paths_iter: self.paths.iter().peekable(),
300            underlines: &self.underlines,
301            underline_transforms: &self.underline_transforms,
302            underlines_start: 0,
303            underlines_iter: self.underlines.iter().peekable(),
304            monochrome_sprites: &self.monochrome_sprites,
305            monochrome_sprites_start: 0,
306            monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
307            subpixel_sprites: &self.subpixel_sprites,
308            subpixel_sprites_start: 0,
309            subpixel_sprites_iter: self.subpixel_sprites.iter().peekable(),
310            polychrome_sprites: &self.polychrome_sprites,
311            polychrome_sprite_transforms: &self.polychrome_sprite_transforms,
312            polychrome_sprites_start: 0,
313            polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(),
314            surfaces: &self.surfaces,
315            surfaces_start: 0,
316            surfaces_iter: self.surfaces.iter().peekable(),
317        }
318    }
319}
320
321#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
322#[cfg_attr(
323    all(
324        any(target_os = "linux", target_os = "freebsd"),
325        not(any(feature = "x11", feature = "wayland"))
326    ),
327    allow(dead_code)
328)]
329pub(crate) enum PrimitiveKind {
330    Shadow,
331    #[default]
332    Quad,
333    BackdropBlur,
334    Path,
335    Underline,
336    MonochromeSprite,
337    SubpixelSprite,
338    PolychromeSprite,
339    Surface,
340}
341
342pub(crate) enum PaintOperation {
343    Primitive(Primitive),
344    StartLayer(Bounds<ScaledPixels>),
345    EndLayer,
346}
347
348#[derive(Clone)]
349pub(crate) enum Primitive {
350    Shadow(Shadow, TransformationMatrix),
351    Quad(Quad, TransformationMatrix),
352    BackdropBlur(BackdropBlur, TransformationMatrix),
353    Path(Path<ScaledPixels>),
354    Underline(Underline, TransformationMatrix),
355    MonochromeSprite(MonochromeSprite),
356    SubpixelSprite(SubpixelSprite),
357    PolychromeSprite(PolychromeSprite, TransformationMatrix),
358    Surface(PaintSurface),
359}
360
361impl Primitive {
362    #[allow(dead_code)]
363    pub fn bounds(&self) -> &Bounds<ScaledPixels> {
364        match self {
365            Primitive::Shadow(shadow, _) => &shadow.bounds,
366            Primitive::Quad(quad, _) => &quad.bounds,
367            Primitive::BackdropBlur(blur, _) => &blur.bounds,
368            Primitive::Path(path) => &path.bounds,
369            Primitive::Underline(underline, _) => &underline.bounds,
370            Primitive::MonochromeSprite(sprite) => &sprite.bounds,
371            Primitive::SubpixelSprite(sprite) => &sprite.bounds,
372            Primitive::PolychromeSprite(sprite, _) => &sprite.bounds,
373            Primitive::Surface(surface) => &surface.bounds,
374        }
375    }
376
377    pub fn content_mask(&self) -> &ContentMask<ScaledPixels> {
378        match self {
379            Primitive::Shadow(shadow, _) => &shadow.content_mask,
380            Primitive::Quad(quad, _) => &quad.content_mask,
381            Primitive::BackdropBlur(blur, _) => &blur.content_mask,
382            Primitive::Path(path) => &path.content_mask,
383            Primitive::Underline(underline, _) => &underline.content_mask,
384            Primitive::MonochromeSprite(sprite) => &sprite.content_mask,
385            Primitive::SubpixelSprite(sprite) => &sprite.content_mask,
386            Primitive::PolychromeSprite(sprite, _) => &sprite.content_mask,
387            Primitive::Surface(surface) => &surface.content_mask,
388        }
389    }
390}
391
392#[cfg_attr(
393    all(
394        any(target_os = "linux", target_os = "freebsd"),
395        not(any(feature = "x11", feature = "wayland"))
396    ),
397    allow(dead_code)
398)]
399struct BatchIterator<'a> {
400    shadows: &'a [Shadow],
401    shadow_transforms: &'a [TransformationMatrix],
402    shadows_start: usize,
403    shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
404    quads: &'a [Quad],
405    quad_transforms: &'a [TransformationMatrix],
406    quads_start: usize,
407    quads_iter: Peekable<slice::Iter<'a, Quad>>,
408    backdrop_blurs: &'a [BackdropBlur],
409    backdrop_blur_transforms: &'a [TransformationMatrix],
410    backdrop_blurs_start: usize,
411    backdrop_blurs_iter: Peekable<slice::Iter<'a, BackdropBlur>>,
412    paths: &'a [Path<ScaledPixels>],
413    paths_start: usize,
414    paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>,
415    underlines: &'a [Underline],
416    underline_transforms: &'a [TransformationMatrix],
417    underlines_start: usize,
418    underlines_iter: Peekable<slice::Iter<'a, Underline>>,
419    monochrome_sprites: &'a [MonochromeSprite],
420    monochrome_sprites_start: usize,
421    monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
422    subpixel_sprites: &'a [SubpixelSprite],
423    subpixel_sprites_start: usize,
424    subpixel_sprites_iter: Peekable<slice::Iter<'a, SubpixelSprite>>,
425    polychrome_sprites: &'a [PolychromeSprite],
426    polychrome_sprite_transforms: &'a [TransformationMatrix],
427    polychrome_sprites_start: usize,
428    polychrome_sprites_iter: Peekable<slice::Iter<'a, PolychromeSprite>>,
429    surfaces: &'a [PaintSurface],
430    surfaces_start: usize,
431    surfaces_iter: Peekable<slice::Iter<'a, PaintSurface>>,
432}
433
434impl<'a> Iterator for BatchIterator<'a> {
435    type Item = PrimitiveBatch<'a>;
436
437    fn next(&mut self) -> Option<Self::Item> {
438        let mut orders_and_kinds = [
439            (
440                self.shadows_iter.peek().map(|s| s.order),
441                PrimitiveKind::Shadow,
442            ),
443            (self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
444            (
445                self.backdrop_blurs_iter.peek().map(|b| b.order),
446                PrimitiveKind::BackdropBlur,
447            ),
448            (self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
449            (
450                self.underlines_iter.peek().map(|u| u.order),
451                PrimitiveKind::Underline,
452            ),
453            (
454                self.monochrome_sprites_iter.peek().map(|s| s.order),
455                PrimitiveKind::MonochromeSprite,
456            ),
457            (
458                self.subpixel_sprites_iter.peek().map(|s| s.order),
459                PrimitiveKind::SubpixelSprite,
460            ),
461            (
462                self.polychrome_sprites_iter.peek().map(|s| s.order),
463                PrimitiveKind::PolychromeSprite,
464            ),
465            (
466                self.surfaces_iter.peek().map(|s| s.order),
467                PrimitiveKind::Surface,
468            ),
469        ];
470        orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
471
472        let first = orders_and_kinds[0];
473        let second = orders_and_kinds[1];
474        let (batch_kind, max_order_and_kind) = if first.0.is_some() {
475            (first.1, (second.0.unwrap_or(u32::MAX), second.1))
476        } else {
477            return None;
478        };
479
480        match batch_kind {
481            PrimitiveKind::Shadow => {
482                let shadows_start = self.shadows_start;
483                let mut shadows_end = shadows_start + 1;
484                self.shadows_iter.next();
485                while self
486                    .shadows_iter
487                    .next_if(|shadow| (shadow.order, batch_kind) < max_order_and_kind)
488                    .is_some()
489                {
490                    shadows_end += 1;
491                }
492                self.shadows_start = shadows_end;
493                Some(PrimitiveBatch::Shadows(
494                    &self.shadows[shadows_start..shadows_end],
495                    &self.shadow_transforms[shadows_start..shadows_end],
496                ))
497            }
498            PrimitiveKind::Quad => {
499                let quads_start = self.quads_start;
500                let mut quads_end = quads_start + 1;
501                self.quads_iter.next();
502                while self
503                    .quads_iter
504                    .next_if(|quad| (quad.order, batch_kind) < max_order_and_kind)
505                    .is_some()
506                {
507                    quads_end += 1;
508                }
509                self.quads_start = quads_end;
510                Some(PrimitiveBatch::Quads(
511                    &self.quads[quads_start..quads_end],
512                    &self.quad_transforms[quads_start..quads_end],
513                ))
514            }
515            PrimitiveKind::BackdropBlur => {
516                let blurs_start = self.backdrop_blurs_start;
517                let mut blurs_end = blurs_start + 1;
518                self.backdrop_blurs_iter.next();
519                while self
520                    .backdrop_blurs_iter
521                    .next_if(|blur| (blur.order, batch_kind) < max_order_and_kind)
522                    .is_some()
523                {
524                    blurs_end += 1;
525                }
526                self.backdrop_blurs_start = blurs_end;
527                Some(PrimitiveBatch::BackdropBlurs(
528                    &self.backdrop_blurs[blurs_start..blurs_end],
529                    &self.backdrop_blur_transforms[blurs_start..blurs_end],
530                ))
531            }
532            PrimitiveKind::Path => {
533                let paths_start = self.paths_start;
534                let mut paths_end = paths_start + 1;
535                self.paths_iter.next();
536                while self
537                    .paths_iter
538                    .next_if(|path| (path.order, batch_kind) < max_order_and_kind)
539                    .is_some()
540                {
541                    paths_end += 1;
542                }
543                self.paths_start = paths_end;
544                Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end]))
545            }
546            PrimitiveKind::Underline => {
547                let underlines_start = self.underlines_start;
548                let mut underlines_end = underlines_start + 1;
549                self.underlines_iter.next();
550                while self
551                    .underlines_iter
552                    .next_if(|underline| (underline.order, batch_kind) < max_order_and_kind)
553                    .is_some()
554                {
555                    underlines_end += 1;
556                }
557                self.underlines_start = underlines_end;
558                Some(PrimitiveBatch::Underlines(
559                    &self.underlines[underlines_start..underlines_end],
560                    &self.underline_transforms[underlines_start..underlines_end],
561                ))
562            }
563            PrimitiveKind::MonochromeSprite => {
564                let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
565                let sprites_start = self.monochrome_sprites_start;
566                let mut sprites_end = sprites_start + 1;
567                self.monochrome_sprites_iter.next();
568                while self
569                    .monochrome_sprites_iter
570                    .next_if(|sprite| {
571                        (sprite.order, batch_kind) < max_order_and_kind
572                            && sprite.tile.texture_id == texture_id
573                    })
574                    .is_some()
575                {
576                    sprites_end += 1;
577                }
578                self.monochrome_sprites_start = sprites_end;
579                Some(PrimitiveBatch::MonochromeSprites {
580                    texture_id,
581                    sprites: &self.monochrome_sprites[sprites_start..sprites_end],
582                })
583            }
584            PrimitiveKind::SubpixelSprite => {
585                let texture_id = self.subpixel_sprites_iter.peek().unwrap().tile.texture_id;
586                let sprites_start = self.subpixel_sprites_start;
587                let mut sprites_end = sprites_start + 1;
588                self.subpixel_sprites_iter.next();
589                while self
590                    .subpixel_sprites_iter
591                    .next_if(|sprite| {
592                        (sprite.order, batch_kind) < max_order_and_kind
593                            && sprite.tile.texture_id == texture_id
594                    })
595                    .is_some()
596                {
597                    sprites_end += 1;
598                }
599                self.subpixel_sprites_start = sprites_end;
600                Some(PrimitiveBatch::SubpixelSprites {
601                    texture_id,
602                    sprites: &self.subpixel_sprites[sprites_start..sprites_end],
603                })
604            }
605            PrimitiveKind::PolychromeSprite => {
606                let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
607                let sprites_start = self.polychrome_sprites_start;
608                let mut sprites_end = self.polychrome_sprites_start + 1;
609                self.polychrome_sprites_iter.next();
610                while self
611                    .polychrome_sprites_iter
612                    .next_if(|sprite| {
613                        (sprite.order, batch_kind) < max_order_and_kind
614                            && sprite.tile.texture_id == texture_id
615                    })
616                    .is_some()
617                {
618                    sprites_end += 1;
619                }
620                self.polychrome_sprites_start = sprites_end;
621                Some(PrimitiveBatch::PolychromeSprites {
622                    texture_id,
623                    sprites: &self.polychrome_sprites[sprites_start..sprites_end],
624                    transforms: &self.polychrome_sprite_transforms[sprites_start..sprites_end],
625                })
626            }
627            PrimitiveKind::Surface => {
628                let surfaces_start = self.surfaces_start;
629                let mut surfaces_end = surfaces_start + 1;
630                self.surfaces_iter.next();
631                while self
632                    .surfaces_iter
633                    .next_if(|surface| (surface.order, batch_kind) < max_order_and_kind)
634                    .is_some()
635                {
636                    surfaces_end += 1;
637                }
638                self.surfaces_start = surfaces_end;
639                Some(PrimitiveBatch::Surfaces(
640                    &self.surfaces[surfaces_start..surfaces_end],
641                ))
642            }
643        }
644    }
645}
646
647#[derive(Debug)]
648#[cfg_attr(
649    all(
650        any(target_os = "linux", target_os = "freebsd"),
651        not(any(feature = "x11", feature = "wayland"))
652    ),
653    allow(dead_code)
654)]
655pub(crate) enum PrimitiveBatch<'a> {
656    Shadows(&'a [Shadow], &'a [TransformationMatrix]),
657    Quads(&'a [Quad], &'a [TransformationMatrix]),
658    BackdropBlurs(&'a [BackdropBlur], &'a [TransformationMatrix]),
659    Paths(&'a [Path<ScaledPixels>]),
660    Underlines(&'a [Underline], &'a [TransformationMatrix]),
661    MonochromeSprites {
662        texture_id: AtlasTextureId,
663        sprites: &'a [MonochromeSprite],
664    },
665    #[cfg_attr(target_os = "macos", allow(dead_code))]
666    SubpixelSprites {
667        texture_id: AtlasTextureId,
668        sprites: &'a [SubpixelSprite],
669    },
670    PolychromeSprites {
671        texture_id: AtlasTextureId,
672        sprites: &'a [PolychromeSprite],
673        transforms: &'a [TransformationMatrix],
674    },
675    Surfaces(&'a [PaintSurface]),
676}
677
678#[derive(Default, Debug, Clone)]
679#[repr(C)]
680pub(crate) struct Quad {
681    pub order: DrawOrder,
682    pub border_style: BorderStyle,
683    pub bounds: Bounds<ScaledPixels>,
684    pub content_mask: ContentMask<ScaledPixels>,
685    pub background: Background,
686    pub border_color: Hsla,
687    pub corner_radii: Corners<ScaledPixels>,
688    pub border_widths: Edges<ScaledPixels>,
689}
690
691impl From<(Quad, TransformationMatrix)> for Primitive {
692    fn from((quad, transform): (Quad, TransformationMatrix)) -> Self {
693        Primitive::Quad(quad, transform)
694    }
695}
696
697#[derive(Debug, Clone)]
698#[repr(C)]
699pub(crate) struct BackdropBlur {
700    pub order: DrawOrder,
701    pub blur_radius: ScaledPixels,
702    pub bounds: Bounds<ScaledPixels>,
703    pub corner_radii: Corners<ScaledPixels>,
704    pub content_mask: ContentMask<ScaledPixels>,
705    pub tint: Hsla,
706}
707
708impl From<(BackdropBlur, TransformationMatrix)> for Primitive {
709    fn from((blur, transform): (BackdropBlur, TransformationMatrix)) -> Self {
710        Primitive::BackdropBlur(blur, transform)
711    }
712}
713
714#[derive(Debug, Clone)]
715#[repr(C)]
716pub(crate) struct Underline {
717    pub order: DrawOrder,
718    pub pad: u32, // align to 8 bytes
719    pub bounds: Bounds<ScaledPixels>,
720    pub content_mask: ContentMask<ScaledPixels>,
721    pub color: Hsla,
722    pub thickness: ScaledPixels,
723    pub wavy: u32,
724}
725
726impl From<(Underline, TransformationMatrix)> for Primitive {
727    fn from((underline, transform): (Underline, TransformationMatrix)) -> Self {
728        Primitive::Underline(underline, transform)
729    }
730}
731
732#[derive(Debug, Clone)]
733#[repr(C)]
734pub(crate) struct Shadow {
735    pub order: DrawOrder,
736    pub blur_radius: ScaledPixels,
737    pub bounds: Bounds<ScaledPixels>,
738    pub corner_radii: Corners<ScaledPixels>,
739    pub content_mask: ContentMask<ScaledPixels>,
740    pub color: Hsla,
741}
742
743impl From<(Shadow, TransformationMatrix)> for Primitive {
744    fn from((shadow, transform): (Shadow, TransformationMatrix)) -> Self {
745        Primitive::Shadow(shadow, transform)
746    }
747}
748
749/// The style of a border.
750#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
751#[repr(C)]
752pub enum BorderStyle {
753    /// A solid border.
754    #[default]
755    Solid = 0,
756    /// A dashed border.
757    Dashed = 1,
758}
759
760/// A data type representing a 2 dimensional transformation that can be applied to an element.
761///
762/// Matrices are stored in row-major order and applied as `M * position + t` in logical
763/// (window) space. Callers should scale the translation exactly once when converting to
764/// device space.
765#[derive(Debug, Clone, Copy, PartialEq)]
766#[repr(C)]
767pub struct TransformationMatrix {
768    /// 2x2 matrix containing rotation and scale,
769    /// stored row-major
770    pub rotation_scale: [[f32; 2]; 2],
771    /// translation vector
772    pub translation: [f32; 2],
773}
774
775impl Eq for TransformationMatrix {}
776
777impl TransformationMatrix {
778    /// The unit matrix, has no effect.
779    pub fn unit() -> Self {
780        Self {
781            rotation_scale: [[1.0, 0.0], [0.0, 1.0]],
782            translation: [0.0, 0.0],
783        }
784    }
785
786    /// Move the origin by a given point in logical pixels.
787    pub fn translate(mut self, point: Point<Pixels>) -> Self {
788        self.compose(Self {
789            rotation_scale: [[1.0, 0.0], [0.0, 1.0]],
790            translation: [point.x.0, point.y.0],
791        })
792    }
793
794    /// Clockwise rotation in radians around the origin
795    pub fn rotate(self, angle: Radians) -> Self {
796        self.compose(Self {
797            rotation_scale: [
798                [angle.0.cos(), -angle.0.sin()],
799                [angle.0.sin(), angle.0.cos()],
800            ],
801            translation: [0.0, 0.0],
802        })
803    }
804
805    /// Scale around the origin
806    pub fn scale(self, size: Size<f32>) -> Self {
807        self.compose(Self {
808            rotation_scale: [[size.width, 0.0], [0.0, size.height]],
809            translation: [0.0, 0.0],
810        })
811    }
812
813    /// Perform matrix multiplication with another transformation
814    /// to produce a new transformation that is the result of
815    /// applying both transformations: first, `other`, then `self`.
816    #[inline]
817    pub fn compose(self, other: TransformationMatrix) -> TransformationMatrix {
818        if other == Self::unit() {
819            return self;
820        }
821        // Perform matrix multiplication
822        TransformationMatrix {
823            rotation_scale: [
824                [
825                    self.rotation_scale[0][0] * other.rotation_scale[0][0]
826                        + self.rotation_scale[0][1] * other.rotation_scale[1][0],
827                    self.rotation_scale[0][0] * other.rotation_scale[0][1]
828                        + self.rotation_scale[0][1] * other.rotation_scale[1][1],
829                ],
830                [
831                    self.rotation_scale[1][0] * other.rotation_scale[0][0]
832                        + self.rotation_scale[1][1] * other.rotation_scale[1][0],
833                    self.rotation_scale[1][0] * other.rotation_scale[0][1]
834                        + self.rotation_scale[1][1] * other.rotation_scale[1][1],
835                ],
836            ],
837            translation: [
838                self.translation[0]
839                    + self.rotation_scale[0][0] * other.translation[0]
840                    + self.rotation_scale[0][1] * other.translation[1],
841                self.translation[1]
842                    + self.rotation_scale[1][0] * other.translation[0]
843                    + self.rotation_scale[1][1] * other.translation[1],
844            ],
845        }
846    }
847
848    /// Returns true when the matrix has no effect (identity rotation/scale and zero translation).
849    pub fn is_unit(&self) -> bool {
850        *self == Self::unit()
851    }
852
853    /// Returns true when only translation is present (rotation/scale is the identity).
854    pub fn is_translation_only(&self) -> bool {
855        self.rotation_scale == [[1.0, 0.0], [0.0, 1.0]]
856    }
857
858    /// Apply the inverse transform to the given point. Returns `None` if the matrix
859    /// is not invertible.
860    pub fn apply_inverse(&self, point: Point<Pixels>) -> Option<Point<Pixels>> {
861        // Inverse of a 2x2 matrix
862        let det = self.rotation_scale[0][0] * self.rotation_scale[1][1]
863            - self.rotation_scale[0][1] * self.rotation_scale[1][0];
864        if det == 0.0 {
865            return None;
866        }
867
868        let inv = [
869            [
870                self.rotation_scale[1][1] / det,
871                -self.rotation_scale[0][1] / det,
872            ],
873            [
874                -self.rotation_scale[1][0] / det,
875                self.rotation_scale[0][0] / det,
876            ],
877        ];
878
879        let translated = [
880            point.x.0 - self.translation[0],
881            point.y.0 - self.translation[1],
882        ];
883
884        let local = [
885            inv[0][0] * translated[0] + inv[0][1] * translated[1],
886            inv[1][0] * translated[0] + inv[1][1] * translated[1],
887        ];
888
889        Some(Point::new(local[0].into(), local[1].into()))
890    }
891
892    /// Apply transformation to a point, mainly useful for debugging
893    pub fn apply(&self, point: Point<Pixels>) -> Point<Pixels> {
894        let input = [point.x.0, point.y.0];
895        let mut output = self.translation;
896        for (i, output_cell) in output.iter_mut().enumerate() {
897            for (k, input_cell) in input.iter().enumerate() {
898                *output_cell += self.rotation_scale[i][k] * *input_cell;
899            }
900        }
901        Point::new(output[0].into(), output[1].into())
902    }
903}
904
905impl Default for TransformationMatrix {
906    fn default() -> Self {
907        Self::unit()
908    }
909}
910
911#[derive(Clone, Debug)]
912#[repr(C)]
913pub(crate) struct MonochromeSprite {
914    pub order: DrawOrder,
915    pub pad: u32, // align to 8 bytes
916    pub bounds: Bounds<ScaledPixels>,
917    pub content_mask: ContentMask<ScaledPixels>,
918    pub color: Hsla,
919    pub tile: AtlasTile,
920    pub transformation: TransformationMatrix,
921}
922
923impl From<MonochromeSprite> for Primitive {
924    fn from(sprite: MonochromeSprite) -> Self {
925        Primitive::MonochromeSprite(sprite)
926    }
927}
928
929#[derive(Clone, Debug)]
930#[repr(C)]
931pub(crate) struct SubpixelSprite {
932    pub order: DrawOrder,
933    pub pad: u32, // align to 8 bytes
934    pub bounds: Bounds<ScaledPixels>,
935    pub content_mask: ContentMask<ScaledPixels>,
936    pub color: Hsla,
937    pub tile: AtlasTile,
938    pub transformation: TransformationMatrix,
939}
940
941impl From<SubpixelSprite> for Primitive {
942    fn from(sprite: SubpixelSprite) -> Self {
943        Primitive::SubpixelSprite(sprite)
944    }
945}
946
947#[derive(Clone, Debug)]
948#[repr(C)]
949pub(crate) struct PolychromeSprite {
950    pub order: DrawOrder,
951    pub pad: u32, // align to 8 bytes
952    pub grayscale: bool,
953    pub opacity: f32,
954    pub bounds: Bounds<ScaledPixels>,
955    pub content_mask: ContentMask<ScaledPixels>,
956    pub corner_radii: Corners<ScaledPixels>,
957    pub tile: AtlasTile,
958}
959
960impl From<(PolychromeSprite, TransformationMatrix)> for Primitive {
961    fn from((sprite, transform): (PolychromeSprite, TransformationMatrix)) -> Self {
962        Primitive::PolychromeSprite(sprite, transform)
963    }
964}
965
966#[derive(Clone, Debug)]
967pub(crate) struct PaintSurface {
968    pub order: DrawOrder,
969    pub bounds: Bounds<ScaledPixels>,
970    pub content_mask: ContentMask<ScaledPixels>,
971    #[cfg(target_os = "macos")]
972    pub image_buffer: core_video::pixel_buffer::CVPixelBuffer,
973}
974
975impl From<PaintSurface> for Primitive {
976    fn from(surface: PaintSurface) -> Self {
977        Primitive::Surface(surface)
978    }
979}
980
981#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
982pub(crate) struct PathId(pub(crate) usize);
983
984/// A line made up of a series of vertices and control points.
985#[derive(Clone, Debug)]
986pub struct Path<P: Clone + Debug + Default + PartialEq> {
987    pub(crate) id: PathId,
988    pub(crate) order: DrawOrder,
989    pub(crate) bounds: Bounds<P>,
990    pub(crate) content_mask: ContentMask<P>,
991    pub(crate) vertices: Vec<PathVertex<P>>,
992    pub(crate) color: Background,
993    start: Point<P>,
994    current: Point<P>,
995    contour_count: usize,
996}
997
998impl Path<Pixels> {
999    /// Create a new path with the given starting point.
1000    pub fn new(start: Point<Pixels>) -> Self {
1001        Self {
1002            id: PathId(0),
1003            order: DrawOrder::default(),
1004            vertices: Vec::new(),
1005            start,
1006            current: start,
1007            bounds: Bounds {
1008                origin: start,
1009                size: Default::default(),
1010            },
1011            content_mask: Default::default(),
1012            color: Default::default(),
1013            contour_count: 0,
1014        }
1015    }
1016
1017    /// Scale this path by the given factor.
1018    pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
1019        Path {
1020            id: self.id,
1021            order: self.order,
1022            bounds: self.bounds.scale(factor),
1023            content_mask: self.content_mask.scale(factor),
1024            vertices: self
1025                .vertices
1026                .iter()
1027                .map(|vertex| vertex.scale(factor))
1028                .collect(),
1029            start: self.start.map(|start| start.scale(factor)),
1030            current: self.current.scale(factor),
1031            contour_count: self.contour_count,
1032            color: self.color,
1033        }
1034    }
1035
1036    /// Move the start, current point to the given point.
1037    pub fn move_to(&mut self, to: Point<Pixels>) {
1038        self.contour_count += 1;
1039        self.start = to;
1040        self.current = to;
1041    }
1042
1043    /// Draw a straight line from the current point to the given point.
1044    pub fn line_to(&mut self, to: Point<Pixels>) {
1045        self.contour_count += 1;
1046        if self.contour_count > 1 {
1047            self.push_triangle(
1048                (self.start, self.current, to),
1049                (point(0., 1.), point(0., 1.), point(0., 1.)),
1050            );
1051        }
1052        self.current = to;
1053    }
1054
1055    /// Draw a curve from the current point to the given point, using the given control point.
1056    pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
1057        self.contour_count += 1;
1058        if self.contour_count > 1 {
1059            self.push_triangle(
1060                (self.start, self.current, to),
1061                (point(0., 1.), point(0., 1.), point(0., 1.)),
1062            );
1063        }
1064
1065        self.push_triangle(
1066            (self.current, ctrl, to),
1067            (point(0., 0.), point(0.5, 0.), point(1., 1.)),
1068        );
1069        self.current = to;
1070    }
1071
1072    /// Push a triangle to the Path.
1073    pub fn push_triangle(
1074        &mut self,
1075        xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
1076        st: (Point<f32>, Point<f32>, Point<f32>),
1077    ) {
1078        self.bounds = self
1079            .bounds
1080            .union(&Bounds {
1081                origin: xy.0,
1082                size: Default::default(),
1083            })
1084            .union(&Bounds {
1085                origin: xy.1,
1086                size: Default::default(),
1087            })
1088            .union(&Bounds {
1089                origin: xy.2,
1090                size: Default::default(),
1091            });
1092
1093        self.vertices.push(PathVertex {
1094            xy_position: xy.0,
1095            st_position: st.0,
1096            content_mask: Default::default(),
1097        });
1098        self.vertices.push(PathVertex {
1099            xy_position: xy.1,
1100            st_position: st.1,
1101            content_mask: Default::default(),
1102        });
1103        self.vertices.push(PathVertex {
1104            xy_position: xy.2,
1105            st_position: st.2,
1106            content_mask: Default::default(),
1107        });
1108    }
1109}
1110
1111impl<T> Path<T>
1112where
1113    T: Clone + Debug + Default + PartialEq + PartialOrd + Add<T, Output = T> + Sub<Output = T>,
1114{
1115    #[allow(unused)]
1116    pub(crate) fn clipped_bounds(&self) -> Bounds<T> {
1117        self.bounds.intersect(&self.content_mask.bounds)
1118    }
1119}
1120
1121impl From<Path<ScaledPixels>> for Primitive {
1122    fn from(path: Path<ScaledPixels>) -> Self {
1123        Primitive::Path(path)
1124    }
1125}
1126
1127#[derive(Clone, Debug)]
1128#[repr(C)]
1129pub(crate) struct PathVertex<P: Clone + Debug + Default + PartialEq> {
1130    pub(crate) xy_position: Point<P>,
1131    pub(crate) st_position: Point<f32>,
1132    pub(crate) content_mask: ContentMask<P>,
1133}
1134
1135impl PathVertex<Pixels> {
1136    pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
1137        PathVertex {
1138            xy_position: self.xy_position.scale(factor),
1139            st_position: self.st_position,
1140            content_mask: self.content_mask.scale(factor),
1141        }
1142    }
1143}