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}