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, PartialEq)]
644#[repr(C)]
645pub(crate) struct PolychromeSprite {
646    pub order: DrawOrder,
647    pub pad: u32, // align to 8 bytes
648    pub grayscale: bool,
649    pub opacity: f32,
650    pub bounds: Bounds<ScaledPixels>,
651    pub content_mask: ContentMask<ScaledPixels>,
652    pub corner_radii: Corners<ScaledPixels>,
653    pub tile: AtlasTile,
654}
655impl Eq for PolychromeSprite {}
656
657impl Ord for PolychromeSprite {
658    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
659        match self.order.cmp(&other.order) {
660            std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
661            order => order,
662        }
663    }
664}
665
666impl PartialOrd for PolychromeSprite {
667    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
668        Some(self.cmp(other))
669    }
670}
671
672impl From<PolychromeSprite> for Primitive {
673    fn from(sprite: PolychromeSprite) -> Self {
674        Primitive::PolychromeSprite(sprite)
675    }
676}
677
678#[derive(Clone, Debug, Eq, PartialEq)]
679pub(crate) struct PaintSurface {
680    pub order: DrawOrder,
681    pub bounds: Bounds<ScaledPixels>,
682    pub content_mask: ContentMask<ScaledPixels>,
683    #[cfg(target_os = "macos")]
684    pub image_buffer: media::core_video::CVImageBuffer,
685}
686
687impl Ord for PaintSurface {
688    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
689        self.order.cmp(&other.order)
690    }
691}
692
693impl PartialOrd for PaintSurface {
694    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
695        Some(self.cmp(other))
696    }
697}
698
699impl From<PaintSurface> for Primitive {
700    fn from(surface: PaintSurface) -> Self {
701        Primitive::Surface(surface)
702    }
703}
704
705#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
706pub(crate) struct PathId(pub(crate) usize);
707
708/// A line made up of a series of vertices and control points.
709#[derive(Clone, Debug)]
710pub struct Path<P: Clone + Default + Debug> {
711    pub(crate) id: PathId,
712    order: DrawOrder,
713    pub(crate) bounds: Bounds<P>,
714    pub(crate) content_mask: ContentMask<P>,
715    pub(crate) vertices: Vec<PathVertex<P>>,
716    pub(crate) color: Hsla,
717    start: Point<P>,
718    current: Point<P>,
719    contour_count: usize,
720}
721
722impl Path<Pixels> {
723    /// Create a new path with the given starting point.
724    pub fn new(start: Point<Pixels>) -> Self {
725        Self {
726            id: PathId(0),
727            order: DrawOrder::default(),
728            vertices: Vec::new(),
729            start,
730            current: start,
731            bounds: Bounds {
732                origin: start,
733                size: Default::default(),
734            },
735            content_mask: Default::default(),
736            color: Default::default(),
737            contour_count: 0,
738        }
739    }
740
741    /// Scale this path by the given factor.
742    pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
743        Path {
744            id: self.id,
745            order: self.order,
746            bounds: self.bounds.scale(factor),
747            content_mask: self.content_mask.scale(factor),
748            vertices: self
749                .vertices
750                .iter()
751                .map(|vertex| vertex.scale(factor))
752                .collect(),
753            start: self.start.map(|start| start.scale(factor)),
754            current: self.current.scale(factor),
755            contour_count: self.contour_count,
756            color: self.color,
757        }
758    }
759
760    /// Draw a straight line from the current point to the given point.
761    pub fn line_to(&mut self, to: Point<Pixels>) {
762        self.contour_count += 1;
763        if self.contour_count > 1 {
764            self.push_triangle(
765                (self.start, self.current, to),
766                (point(0., 1.), point(0., 1.), point(0., 1.)),
767            );
768        }
769        self.current = to;
770    }
771
772    /// Draw a curve from the current point to the given point, using the given control point.
773    pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
774        self.contour_count += 1;
775        if self.contour_count > 1 {
776            self.push_triangle(
777                (self.start, self.current, to),
778                (point(0., 1.), point(0., 1.), point(0., 1.)),
779            );
780        }
781
782        self.push_triangle(
783            (self.current, ctrl, to),
784            (point(0., 0.), point(0.5, 0.), point(1., 1.)),
785        );
786        self.current = to;
787    }
788
789    fn push_triangle(
790        &mut self,
791        xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
792        st: (Point<f32>, Point<f32>, Point<f32>),
793    ) {
794        self.bounds = self
795            .bounds
796            .union(&Bounds {
797                origin: xy.0,
798                size: Default::default(),
799            })
800            .union(&Bounds {
801                origin: xy.1,
802                size: Default::default(),
803            })
804            .union(&Bounds {
805                origin: xy.2,
806                size: Default::default(),
807            });
808
809        self.vertices.push(PathVertex {
810            xy_position: xy.0,
811            st_position: st.0,
812            content_mask: Default::default(),
813        });
814        self.vertices.push(PathVertex {
815            xy_position: xy.1,
816            st_position: st.1,
817            content_mask: Default::default(),
818        });
819        self.vertices.push(PathVertex {
820            xy_position: xy.2,
821            st_position: st.2,
822            content_mask: Default::default(),
823        });
824    }
825}
826
827impl Eq for Path<ScaledPixels> {}
828
829impl PartialEq for Path<ScaledPixels> {
830    fn eq(&self, other: &Self) -> bool {
831        self.order == other.order
832    }
833}
834
835impl Ord for Path<ScaledPixels> {
836    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
837        self.order.cmp(&other.order)
838    }
839}
840
841impl PartialOrd for Path<ScaledPixels> {
842    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
843        Some(self.cmp(other))
844    }
845}
846
847impl From<Path<ScaledPixels>> for Primitive {
848    fn from(path: Path<ScaledPixels>) -> Self {
849        Primitive::Path(path)
850    }
851}
852
853#[derive(Clone, Debug)]
854#[repr(C)]
855pub(crate) struct PathVertex<P: Clone + Default + Debug> {
856    pub(crate) xy_position: Point<P>,
857    pub(crate) st_position: Point<f32>,
858    pub(crate) content_mask: ContentMask<P>,
859}
860
861impl PathVertex<Pixels> {
862    pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
863        PathVertex {
864            xy_position: self.xy_position.scale(factor),
865            st_position: self.st_position,
866            content_mask: self.content_mask.scale(factor),
867        }
868    }
869}