scene.rs

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