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