scene.rs

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