scene.rs

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