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