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, ScaledPixels,
  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<Surface>,
 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(Surface),
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 [Surface],
235    surfaces_start: usize,
236    surfaces_iter: Peekable<slice::Iter<'a, Surface>>,
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 [Surface]),
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#[derive(Clone, Debug, Eq, PartialEq)]
508#[repr(C)]
509pub(crate) struct MonochromeSprite {
510    pub order: DrawOrder,
511    pub pad: u32, // align to 8 bytes
512    pub bounds: Bounds<ScaledPixels>,
513    pub content_mask: ContentMask<ScaledPixels>,
514    pub color: Hsla,
515    pub tile: AtlasTile,
516}
517
518impl Ord for MonochromeSprite {
519    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
520        match self.order.cmp(&other.order) {
521            std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
522            order => order,
523        }
524    }
525}
526
527impl PartialOrd for MonochromeSprite {
528    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
529        Some(self.cmp(other))
530    }
531}
532
533impl From<MonochromeSprite> for Primitive {
534    fn from(sprite: MonochromeSprite) -> Self {
535        Primitive::MonochromeSprite(sprite)
536    }
537}
538
539#[derive(Clone, Debug, Eq, PartialEq)]
540#[repr(C)]
541pub(crate) struct PolychromeSprite {
542    pub order: DrawOrder,
543    pub grayscale: bool,
544    pub bounds: Bounds<ScaledPixels>,
545    pub content_mask: ContentMask<ScaledPixels>,
546    pub corner_radii: Corners<ScaledPixels>,
547    pub tile: AtlasTile,
548}
549
550impl Ord for PolychromeSprite {
551    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
552        match self.order.cmp(&other.order) {
553            std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
554            order => order,
555        }
556    }
557}
558
559impl PartialOrd for PolychromeSprite {
560    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
561        Some(self.cmp(other))
562    }
563}
564
565impl From<PolychromeSprite> for Primitive {
566    fn from(sprite: PolychromeSprite) -> Self {
567        Primitive::PolychromeSprite(sprite)
568    }
569}
570
571#[derive(Clone, Debug, Eq, PartialEq)]
572pub(crate) struct Surface {
573    pub order: DrawOrder,
574    pub bounds: Bounds<ScaledPixels>,
575    pub content_mask: ContentMask<ScaledPixels>,
576    #[cfg(target_os = "macos")]
577    pub image_buffer: media::core_video::CVImageBuffer,
578}
579
580impl Ord for Surface {
581    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
582        self.order.cmp(&other.order)
583    }
584}
585
586impl PartialOrd for Surface {
587    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
588        Some(self.cmp(other))
589    }
590}
591
592impl From<Surface> for Primitive {
593    fn from(surface: Surface) -> Self {
594        Primitive::Surface(surface)
595    }
596}
597
598#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
599pub(crate) struct PathId(pub(crate) usize);
600
601/// A line made up of a series of vertices and control points.
602#[derive(Clone, Debug)]
603pub struct Path<P: Clone + Default + Debug> {
604    pub(crate) id: PathId,
605    order: DrawOrder,
606    pub(crate) bounds: Bounds<P>,
607    pub(crate) content_mask: ContentMask<P>,
608    pub(crate) vertices: Vec<PathVertex<P>>,
609    pub(crate) color: Hsla,
610    start: Point<P>,
611    current: Point<P>,
612    contour_count: usize,
613}
614
615impl Path<Pixels> {
616    /// Create a new path with the given starting point.
617    pub fn new(start: Point<Pixels>) -> Self {
618        Self {
619            id: PathId(0),
620            order: DrawOrder::default(),
621            vertices: Vec::new(),
622            start,
623            current: start,
624            bounds: Bounds {
625                origin: start,
626                size: Default::default(),
627            },
628            content_mask: Default::default(),
629            color: Default::default(),
630            contour_count: 0,
631        }
632    }
633
634    /// Scale this path by the given factor.
635    pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
636        Path {
637            id: self.id,
638            order: self.order,
639            bounds: self.bounds.scale(factor),
640            content_mask: self.content_mask.scale(factor),
641            vertices: self
642                .vertices
643                .iter()
644                .map(|vertex| vertex.scale(factor))
645                .collect(),
646            start: self.start.map(|start| start.scale(factor)),
647            current: self.current.scale(factor),
648            contour_count: self.contour_count,
649            color: self.color,
650        }
651    }
652
653    /// Draw a straight line from the current point to the given point.
654    pub fn line_to(&mut self, to: Point<Pixels>) {
655        self.contour_count += 1;
656        if self.contour_count > 1 {
657            self.push_triangle(
658                (self.start, self.current, to),
659                (point(0., 1.), point(0., 1.), point(0., 1.)),
660            );
661        }
662        self.current = to;
663    }
664
665    /// Draw a curve from the current point to the given point, using the given control point.
666    pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
667        self.contour_count += 1;
668        if self.contour_count > 1 {
669            self.push_triangle(
670                (self.start, self.current, to),
671                (point(0., 1.), point(0., 1.), point(0., 1.)),
672            );
673        }
674
675        self.push_triangle(
676            (self.current, ctrl, to),
677            (point(0., 0.), point(0.5, 0.), point(1., 1.)),
678        );
679        self.current = to;
680    }
681
682    fn push_triangle(
683        &mut self,
684        xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
685        st: (Point<f32>, Point<f32>, Point<f32>),
686    ) {
687        self.bounds = self
688            .bounds
689            .union(&Bounds {
690                origin: xy.0,
691                size: Default::default(),
692            })
693            .union(&Bounds {
694                origin: xy.1,
695                size: Default::default(),
696            })
697            .union(&Bounds {
698                origin: xy.2,
699                size: Default::default(),
700            });
701
702        self.vertices.push(PathVertex {
703            xy_position: xy.0,
704            st_position: st.0,
705            content_mask: Default::default(),
706        });
707        self.vertices.push(PathVertex {
708            xy_position: xy.1,
709            st_position: st.1,
710            content_mask: Default::default(),
711        });
712        self.vertices.push(PathVertex {
713            xy_position: xy.2,
714            st_position: st.2,
715            content_mask: Default::default(),
716        });
717    }
718}
719
720impl Eq for Path<ScaledPixels> {}
721
722impl PartialEq for Path<ScaledPixels> {
723    fn eq(&self, other: &Self) -> bool {
724        self.order == other.order
725    }
726}
727
728impl Ord for Path<ScaledPixels> {
729    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
730        self.order.cmp(&other.order)
731    }
732}
733
734impl PartialOrd for Path<ScaledPixels> {
735    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
736        Some(self.cmp(other))
737    }
738}
739
740impl From<Path<ScaledPixels>> for Primitive {
741    fn from(path: Path<ScaledPixels>) -> Self {
742        Primitive::Path(path)
743    }
744}
745
746#[derive(Clone, Debug)]
747#[repr(C)]
748pub(crate) struct PathVertex<P: Clone + Default + Debug> {
749    pub(crate) xy_position: Point<P>,
750    pub(crate) st_position: Point<f32>,
751    pub(crate) content_mask: ContentMask<P>,
752}
753
754impl PathVertex<Pixels> {
755    pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
756        PathVertex {
757            xy_position: self.xy_position.scale(factor),
758            st_position: self.st_position,
759            content_mask: self.content_mask.scale(factor),
760        }
761    }
762}