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