scene.rs

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