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