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