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 + 1;
273                self.shadows_iter.next();
274                while self
275                    .shadows_iter
276                    .next_if(|shadow| shadow.order < max_order)
277                    .is_some()
278                {
279                    shadows_end += 1;
280                }
281                self.shadows_start = shadows_end;
282                Some(PrimitiveBatch::Shadows(
283                    &self.shadows[shadows_start..shadows_end],
284                ))
285            }
286            PrimitiveKind::Quad => {
287                let quads_start = self.quads_start;
288                let mut quads_end = quads_start + 1;
289                self.quads_iter.next();
290                while self
291                    .quads_iter
292                    .next_if(|quad| quad.order < max_order)
293                    .is_some()
294                {
295                    quads_end += 1;
296                }
297                self.quads_start = quads_end;
298                Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
299            }
300            PrimitiveKind::Path => {
301                let paths_start = self.paths_start;
302                let mut paths_end = paths_start + 1;
303                self.paths_iter.next();
304                while self
305                    .paths_iter
306                    .next_if(|path| path.order < max_order)
307                    .is_some()
308                {
309                    paths_end += 1;
310                }
311                self.paths_start = paths_end;
312                Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end]))
313            }
314            PrimitiveKind::Underline => {
315                let underlines_start = self.underlines_start;
316                let mut underlines_end = underlines_start + 1;
317                self.underlines_iter.next();
318                while self
319                    .underlines_iter
320                    .next_if(|underline| underline.order < max_order)
321                    .is_some()
322                {
323                    underlines_end += 1;
324                }
325                self.underlines_start = underlines_end;
326                Some(PrimitiveBatch::Underlines(
327                    &self.underlines[underlines_start..underlines_end],
328                ))
329            }
330            PrimitiveKind::MonochromeSprite => {
331                let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
332                let sprites_start = self.monochrome_sprites_start;
333                let mut sprites_end = sprites_start + 1;
334                self.monochrome_sprites_iter.next();
335                while self
336                    .monochrome_sprites_iter
337                    .next_if(|sprite| {
338                        sprite.order < max_order && sprite.tile.texture_id == texture_id
339                    })
340                    .is_some()
341                {
342                    sprites_end += 1;
343                }
344                self.monochrome_sprites_start = sprites_end;
345                Some(PrimitiveBatch::MonochromeSprites {
346                    texture_id,
347                    sprites: &self.monochrome_sprites[sprites_start..sprites_end],
348                })
349            }
350            PrimitiveKind::PolychromeSprite => {
351                let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
352                let sprites_start = self.polychrome_sprites_start;
353                let mut sprites_end = self.polychrome_sprites_start + 1;
354                self.polychrome_sprites_iter.next();
355                while self
356                    .polychrome_sprites_iter
357                    .next_if(|sprite| {
358                        sprite.order < max_order && sprite.tile.texture_id == texture_id
359                    })
360                    .is_some()
361                {
362                    sprites_end += 1;
363                }
364                self.polychrome_sprites_start = sprites_end;
365                Some(PrimitiveBatch::PolychromeSprites {
366                    texture_id,
367                    sprites: &self.polychrome_sprites[sprites_start..sprites_end],
368                })
369            }
370            PrimitiveKind::Surface => {
371                let surfaces_start = self.surfaces_start;
372                let mut surfaces_end = surfaces_start + 1;
373                self.surfaces_iter.next();
374                while self
375                    .surfaces_iter
376                    .next_if(|surface| surface.order < max_order)
377                    .is_some()
378                {
379                    surfaces_end += 1;
380                }
381                self.surfaces_start = surfaces_end;
382                Some(PrimitiveBatch::Surfaces(
383                    &self.surfaces[surfaces_start..surfaces_end],
384                ))
385            }
386        }
387    }
388}
389
390#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
391pub enum PrimitiveKind {
392    Shadow,
393    #[default]
394    Quad,
395    Path,
396    Underline,
397    MonochromeSprite,
398    PolychromeSprite,
399    Surface,
400}
401
402pub enum Primitive {
403    Shadow(Shadow),
404    Quad(Quad),
405    Path(Path<ScaledPixels>),
406    Underline(Underline),
407    MonochromeSprite(MonochromeSprite),
408    PolychromeSprite(PolychromeSprite),
409    Surface(Surface),
410}
411
412impl Primitive {
413    pub fn bounds(&self) -> &Bounds<ScaledPixels> {
414        match self {
415            Primitive::Shadow(shadow) => &shadow.bounds,
416            Primitive::Quad(quad) => &quad.bounds,
417            Primitive::Path(path) => &path.bounds,
418            Primitive::Underline(underline) => &underline.bounds,
419            Primitive::MonochromeSprite(sprite) => &sprite.bounds,
420            Primitive::PolychromeSprite(sprite) => &sprite.bounds,
421            Primitive::Surface(surface) => &surface.bounds,
422        }
423    }
424
425    pub fn content_mask(&self) -> &ContentMask<ScaledPixels> {
426        match self {
427            Primitive::Shadow(shadow) => &shadow.content_mask,
428            Primitive::Quad(quad) => &quad.content_mask,
429            Primitive::Path(path) => &path.content_mask,
430            Primitive::Underline(underline) => &underline.content_mask,
431            Primitive::MonochromeSprite(sprite) => &sprite.content_mask,
432            Primitive::PolychromeSprite(sprite) => &sprite.content_mask,
433            Primitive::Surface(surface) => &surface.content_mask,
434        }
435    }
436}
437
438#[derive(Debug)]
439pub(crate) enum PrimitiveBatch<'a> {
440    Shadows(&'a [Shadow]),
441    Quads(&'a [Quad]),
442    Paths(&'a [Path<ScaledPixels>]),
443    Underlines(&'a [Underline]),
444    MonochromeSprites {
445        texture_id: AtlasTextureId,
446        sprites: &'a [MonochromeSprite],
447    },
448    PolychromeSprites {
449        texture_id: AtlasTextureId,
450        sprites: &'a [PolychromeSprite],
451    },
452    Surfaces(&'a [Surface]),
453}
454
455#[derive(Default, Debug, Clone, Eq, PartialEq)]
456#[repr(C)]
457pub struct Quad {
458    pub order: u32, // Initially a LayerId, then a DrawOrder.
459    pub bounds: Bounds<ScaledPixels>,
460    pub content_mask: ContentMask<ScaledPixels>,
461    pub background: Hsla,
462    pub border_color: Hsla,
463    pub corner_radii: Corners<ScaledPixels>,
464    pub border_widths: Edges<ScaledPixels>,
465}
466
467impl Ord for Quad {
468    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
469        self.order.cmp(&other.order)
470    }
471}
472
473impl PartialOrd for Quad {
474    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
475        Some(self.cmp(other))
476    }
477}
478
479impl From<Quad> for Primitive {
480    fn from(quad: Quad) -> Self {
481        Primitive::Quad(quad)
482    }
483}
484
485#[derive(Debug, Clone, Eq, PartialEq)]
486#[repr(C)]
487pub struct Underline {
488    pub order: u32,
489    pub bounds: Bounds<ScaledPixels>,
490    pub content_mask: ContentMask<ScaledPixels>,
491    pub thickness: ScaledPixels,
492    pub color: Hsla,
493    pub wavy: bool,
494}
495
496impl Ord for Underline {
497    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
498        self.order.cmp(&other.order)
499    }
500}
501
502impl PartialOrd for Underline {
503    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
504        Some(self.cmp(other))
505    }
506}
507
508impl From<Underline> for Primitive {
509    fn from(underline: Underline) -> Self {
510        Primitive::Underline(underline)
511    }
512}
513
514#[derive(Debug, Clone, Eq, PartialEq)]
515#[repr(C)]
516pub struct Shadow {
517    pub order: u32,
518    pub bounds: Bounds<ScaledPixels>,
519    pub corner_radii: Corners<ScaledPixels>,
520    pub content_mask: ContentMask<ScaledPixels>,
521    pub color: Hsla,
522    pub blur_radius: ScaledPixels,
523}
524
525impl Ord for Shadow {
526    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
527        self.order.cmp(&other.order)
528    }
529}
530
531impl PartialOrd for Shadow {
532    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
533        Some(self.cmp(other))
534    }
535}
536
537impl From<Shadow> for Primitive {
538    fn from(shadow: Shadow) -> Self {
539        Primitive::Shadow(shadow)
540    }
541}
542
543#[derive(Clone, Debug, Eq, PartialEq)]
544#[repr(C)]
545pub struct MonochromeSprite {
546    pub order: u32,
547    pub bounds: Bounds<ScaledPixels>,
548    pub content_mask: ContentMask<ScaledPixels>,
549    pub color: Hsla,
550    pub tile: AtlasTile,
551}
552
553impl Ord for MonochromeSprite {
554    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
555        match self.order.cmp(&other.order) {
556            std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
557            order => order,
558        }
559    }
560}
561
562impl PartialOrd for MonochromeSprite {
563    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
564        Some(self.cmp(other))
565    }
566}
567
568impl From<MonochromeSprite> for Primitive {
569    fn from(sprite: MonochromeSprite) -> Self {
570        Primitive::MonochromeSprite(sprite)
571    }
572}
573
574#[derive(Clone, Debug, Eq, PartialEq)]
575#[repr(C)]
576pub struct PolychromeSprite {
577    pub order: u32,
578    pub bounds: Bounds<ScaledPixels>,
579    pub content_mask: ContentMask<ScaledPixels>,
580    pub corner_radii: Corners<ScaledPixels>,
581    pub tile: AtlasTile,
582    pub grayscale: bool,
583}
584
585impl Ord for PolychromeSprite {
586    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
587        match self.order.cmp(&other.order) {
588            std::cmp::Ordering::Equal => self.tile.tile_id.cmp(&other.tile.tile_id),
589            order => order,
590        }
591    }
592}
593
594impl PartialOrd for PolychromeSprite {
595    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
596        Some(self.cmp(other))
597    }
598}
599
600impl From<PolychromeSprite> for Primitive {
601    fn from(sprite: PolychromeSprite) -> Self {
602        Primitive::PolychromeSprite(sprite)
603    }
604}
605
606#[derive(Clone, Debug, Eq, PartialEq)]
607pub struct Surface {
608    pub order: u32,
609    pub bounds: Bounds<ScaledPixels>,
610    pub content_mask: ContentMask<ScaledPixels>,
611    pub image_buffer: media::core_video::CVImageBuffer,
612}
613
614impl Ord for Surface {
615    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
616        self.order.cmp(&other.order)
617    }
618}
619
620impl PartialOrd for Surface {
621    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
622        Some(self.cmp(other))
623    }
624}
625
626impl From<Surface> for Primitive {
627    fn from(surface: Surface) -> Self {
628        Primitive::Surface(surface)
629    }
630}
631
632#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
633pub(crate) struct PathId(pub(crate) usize);
634
635#[derive(Debug)]
636pub struct Path<P: Clone + Default + Debug> {
637    pub(crate) id: PathId,
638    order: u32,
639    pub(crate) bounds: Bounds<P>,
640    pub(crate) content_mask: ContentMask<P>,
641    pub(crate) vertices: Vec<PathVertex<P>>,
642    pub(crate) color: Hsla,
643    start: Point<P>,
644    current: Point<P>,
645    contour_count: usize,
646}
647
648impl Path<Pixels> {
649    pub fn new(start: Point<Pixels>) -> Self {
650        Self {
651            id: PathId(0),
652            order: 0,
653            vertices: Vec::new(),
654            start,
655            current: start,
656            bounds: Bounds {
657                origin: start,
658                size: Default::default(),
659            },
660            content_mask: Default::default(),
661            color: Default::default(),
662            contour_count: 0,
663        }
664    }
665
666    pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
667        Path {
668            id: self.id,
669            order: self.order,
670            bounds: self.bounds.scale(factor),
671            content_mask: self.content_mask.scale(factor),
672            vertices: self
673                .vertices
674                .iter()
675                .map(|vertex| vertex.scale(factor))
676                .collect(),
677            start: self.start.map(|start| start.scale(factor)),
678            current: self.current.scale(factor),
679            contour_count: self.contour_count,
680            color: self.color,
681        }
682    }
683
684    pub fn line_to(&mut self, to: Point<Pixels>) {
685        self.contour_count += 1;
686        if self.contour_count > 1 {
687            self.push_triangle(
688                (self.start, self.current, to),
689                (point(0., 1.), point(0., 1.), point(0., 1.)),
690            );
691        }
692        self.current = to;
693    }
694
695    pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
696        self.contour_count += 1;
697        if self.contour_count > 1 {
698            self.push_triangle(
699                (self.start, self.current, to),
700                (point(0., 1.), point(0., 1.), point(0., 1.)),
701            );
702        }
703
704        self.push_triangle(
705            (self.current, ctrl, to),
706            (point(0., 0.), point(0.5, 0.), point(1., 1.)),
707        );
708        self.current = to;
709    }
710
711    fn push_triangle(
712        &mut self,
713        xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
714        st: (Point<f32>, Point<f32>, Point<f32>),
715    ) {
716        self.bounds = self
717            .bounds
718            .union(&Bounds {
719                origin: xy.0,
720                size: Default::default(),
721            })
722            .union(&Bounds {
723                origin: xy.1,
724                size: Default::default(),
725            })
726            .union(&Bounds {
727                origin: xy.2,
728                size: Default::default(),
729            });
730
731        self.vertices.push(PathVertex {
732            xy_position: xy.0,
733            st_position: st.0,
734            content_mask: Default::default(),
735        });
736        self.vertices.push(PathVertex {
737            xy_position: xy.1,
738            st_position: st.1,
739            content_mask: Default::default(),
740        });
741        self.vertices.push(PathVertex {
742            xy_position: xy.2,
743            st_position: st.2,
744            content_mask: Default::default(),
745        });
746    }
747}
748
749impl Eq for Path<ScaledPixels> {}
750
751impl PartialEq for Path<ScaledPixels> {
752    fn eq(&self, other: &Self) -> bool {
753        self.order == other.order
754    }
755}
756
757impl Ord for Path<ScaledPixels> {
758    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
759        self.order.cmp(&other.order)
760    }
761}
762
763impl PartialOrd for Path<ScaledPixels> {
764    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
765        Some(self.cmp(other))
766    }
767}
768
769impl From<Path<ScaledPixels>> for Primitive {
770    fn from(path: Path<ScaledPixels>) -> Self {
771        Primitive::Path(path)
772    }
773}
774
775#[derive(Clone, Debug)]
776#[repr(C)]
777pub struct PathVertex<P: Clone + Default + Debug> {
778    pub(crate) xy_position: Point<P>,
779    pub(crate) st_position: Point<f32>,
780    pub(crate) content_mask: ContentMask<P>,
781}
782
783impl PathVertex<Pixels> {
784    pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
785        PathVertex {
786            xy_position: self.xy_position.scale(factor),
787            st_position: self.st_position,
788            content_mask: self.content_mask.scale(factor),
789        }
790    }
791}
792
793#[derive(Copy, Clone, Debug)]
794pub struct AtlasId(pub(crate) usize);