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