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