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