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