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