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