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