scene.rs

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