scene.rs

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