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) shadow_transforms: Vec<TransformationMatrix>,
30 pub(crate) quads: Vec<Quad>,
31 pub(crate) quad_transforms: Vec<TransformationMatrix>,
32 pub(crate) backdrop_blurs: Vec<BackdropBlur>,
33 pub(crate) backdrop_blur_transforms: Vec<TransformationMatrix>,
34 pub(crate) paths: Vec<Path<ScaledPixels>>,
35 pub(crate) underlines: Vec<Underline>,
36 pub(crate) underline_transforms: Vec<TransformationMatrix>,
37 pub(crate) monochrome_sprites: Vec<MonochromeSprite>,
38 pub(crate) polychrome_sprites: Vec<PolychromeSprite>,
39 pub(crate) polychrome_sprite_transforms: Vec<TransformationMatrix>,
40 pub(crate) surfaces: Vec<PaintSurface>,
41}
42
43impl Scene {
44 pub fn clear(&mut self) {
45 self.paint_operations.clear();
46 self.primitive_bounds.clear();
47 self.layer_stack.clear();
48 self.paths.clear();
49 self.shadows.clear();
50 self.shadow_transforms.clear();
51 self.quads.clear();
52 self.quad_transforms.clear();
53 self.backdrop_blurs.clear();
54 self.backdrop_blur_transforms.clear();
55 self.underlines.clear();
56 self.underline_transforms.clear();
57 self.monochrome_sprites.clear();
58 self.polychrome_sprites.clear();
59 self.polychrome_sprite_transforms.clear();
60 self.surfaces.clear();
61 }
62
63 pub fn len(&self) -> usize {
64 self.paint_operations.len()
65 }
66
67 pub fn push_layer(&mut self, bounds: Bounds<ScaledPixels>) {
68 let order = self.primitive_bounds.insert(bounds);
69 self.layer_stack.push(order);
70 self.paint_operations
71 .push(PaintOperation::StartLayer(bounds));
72 }
73
74 pub fn pop_layer(&mut self) {
75 self.layer_stack.pop();
76 self.paint_operations.push(PaintOperation::EndLayer);
77 }
78
79 pub fn insert_primitive(&mut self, primitive: impl Into<Primitive>) {
80 let mut primitive = primitive.into();
81 let transformed_bounds = transformed_bounds(&primitive);
82 let clipped_bounds = transformed_bounds.intersect(&primitive.content_mask().bounds);
83
84 if clipped_bounds.is_empty() {
85 return;
86 }
87
88 let order = self
89 .layer_stack
90 .last()
91 .copied()
92 .unwrap_or_else(|| self.primitive_bounds.insert(clipped_bounds));
93 match &mut primitive {
94 Primitive::Shadow(shadow, transform) => {
95 shadow.order = order;
96 self.shadows.push(shadow.clone());
97 self.shadow_transforms.push(*transform);
98 }
99 Primitive::Quad(quad, transform) => {
100 quad.order = order;
101 self.quads.push(quad.clone());
102 self.quad_transforms.push(*transform);
103 }
104 Primitive::BackdropBlur(blur, transform) => {
105 blur.order = order;
106 self.backdrop_blurs.push(blur.clone());
107 self.backdrop_blur_transforms.push(*transform);
108 }
109 Primitive::Path(path) => {
110 path.order = order;
111 path.id = PathId(self.paths.len());
112 self.paths.push(path.clone());
113 }
114 Primitive::Underline(underline, transform) => {
115 underline.order = order;
116 self.underlines.push(underline.clone());
117 self.underline_transforms.push(*transform);
118 }
119 Primitive::MonochromeSprite(sprite) => {
120 sprite.order = order;
121 self.monochrome_sprites.push(sprite.clone());
122 }
123 Primitive::PolychromeSprite(sprite, transform) => {
124 sprite.order = order;
125 self.polychrome_sprites.push(sprite.clone());
126 self.polychrome_sprite_transforms.push(*transform);
127 }
128 Primitive::Surface(surface) => {
129 surface.order = order;
130 self.surfaces.push(surface.clone());
131 }
132 }
133
134 fn transformed_bounds(primitive: &Primitive) -> Bounds<ScaledPixels> {
136 fn apply_transform(
137 bounds: &Bounds<ScaledPixels>,
138 transform: &TransformationMatrix,
139 ) -> Bounds<ScaledPixels> {
140 if transform.is_unit() {
141 return *bounds;
142 }
143 let [[a, b], [c, d]] = transform.rotation_scale;
144 let tx = transform.translation[0];
145 let ty = transform.translation[1];
146
147 let x0 = bounds.origin.x.0;
148 let x1 = x0 + bounds.size.width.0;
149 let y0 = bounds.origin.y.0;
150 let y1 = y0 + bounds.size.height.0;
151
152 let ax0 = a * x0;
153 let ax1 = a * x1;
154 let by0 = b * y0;
155 let by1 = b * y1;
156
157 let cx0 = c * x0;
158 let cx1 = c * x1;
159 let dy0 = d * y0;
160 let dy1 = d * y1;
161
162 let min_x = tx + ax0.min(ax1) + by0.min(by1);
163 let max_x = tx + ax0.max(ax1) + by0.max(by1);
164 let min_y = ty + cx0.min(cx1) + dy0.min(dy1);
165 let max_y = ty + cx0.max(cx1) + dy0.max(dy1);
166
167 Bounds {
168 origin: point(ScaledPixels(min_x), ScaledPixels(min_y)),
169 size: Size {
170 width: ScaledPixels((max_x - min_x).max(0.0)),
171 height: ScaledPixels((max_y - min_y).max(0.0)),
172 },
173 }
174 }
175
176 match primitive {
177 Primitive::Shadow(shadow, transform) => apply_transform(&shadow.bounds, transform),
178 Primitive::Quad(quad, transform) => apply_transform(&quad.bounds, transform),
179 Primitive::BackdropBlur(blur, transform) => apply_transform(&blur.bounds, transform),
180 Primitive::Underline(underline, transform) => {
181 apply_transform(&underline.bounds, transform)
182 }
183 Primitive::MonochromeSprite(sprite) => {
184 apply_transform(&sprite.bounds, &sprite.transformation)
185 }
186 Primitive::PolychromeSprite(sprite, transform) => {
187 apply_transform(&sprite.bounds, transform)
188 }
189 Primitive::Path(path) => path.bounds,
190 Primitive::Surface(surface) => surface.bounds,
191 }
192 }
193 self.paint_operations
194 .push(PaintOperation::Primitive(primitive));
195 }
196
197 pub fn replay(&mut self, range: Range<usize>, prev_scene: &Scene) {
198 for operation in &prev_scene.paint_operations[range] {
199 match operation {
200 PaintOperation::Primitive(primitive) => self.insert_primitive(primitive.clone()),
201 PaintOperation::StartLayer(bounds) => self.push_layer(*bounds),
202 PaintOperation::EndLayer => self.pop_layer(),
203 }
204 }
205 }
206
207 fn sort_with_aux_by_key<T, U, K: Ord>(
208 items: &mut Vec<T>,
209 aux: &mut Vec<U>,
210 mut key_fn: impl FnMut(&T) -> K,
211 ) {
212 debug_assert_eq!(items.len(), aux.len());
213 if items.len() <= 1 {
214 return;
215 }
216
217 let mut perm: Vec<usize> = (0..items.len()).collect();
218 perm.sort_by_key(|&index| key_fn(&items[index]));
219
220 let mut desired_pos_by_current_pos = vec![0usize; perm.len()];
221 for (desired_pos, current_pos) in perm.into_iter().enumerate() {
222 desired_pos_by_current_pos[current_pos] = desired_pos;
223 }
224
225 for i in 0..items.len() {
226 while desired_pos_by_current_pos[i] != i {
227 let j = desired_pos_by_current_pos[i];
228 items.swap(i, j);
229 aux.swap(i, j);
230 desired_pos_by_current_pos.swap(i, j);
231 }
232 }
233 }
234
235 pub fn finish(&mut self) {
236 Self::sort_with_aux_by_key(&mut self.shadows, &mut self.shadow_transforms, |shadow| {
237 shadow.order
238 });
239 Self::sort_with_aux_by_key(&mut self.quads, &mut self.quad_transforms, |quad| {
240 quad.order
241 });
242 Self::sort_with_aux_by_key(
243 &mut self.backdrop_blurs,
244 &mut self.backdrop_blur_transforms,
245 |blur| blur.order,
246 );
247 self.paths.sort_by_key(|path| path.order);
248 Self::sort_with_aux_by_key(
249 &mut self.underlines,
250 &mut self.underline_transforms,
251 |underline| underline.order,
252 );
253 self.monochrome_sprites
254 .sort_by_key(|sprite| (sprite.order, sprite.tile.tile_id));
255 Self::sort_with_aux_by_key(
256 &mut self.polychrome_sprites,
257 &mut self.polychrome_sprite_transforms,
258 |sprite| (sprite.order, sprite.tile.tile_id),
259 );
260 self.surfaces.sort_by_key(|surface| surface.order);
261 }
262
263 #[cfg_attr(
264 all(
265 any(target_os = "linux", target_os = "freebsd"),
266 not(any(feature = "x11", feature = "wayland"))
267 ),
268 allow(dead_code)
269 )]
270 pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch<'_>> {
271 BatchIterator {
272 shadows: &self.shadows,
273 shadow_transforms: &self.shadow_transforms,
274 shadows_start: 0,
275 shadows_iter: self.shadows.iter().peekable(),
276 quads: &self.quads,
277 quad_transforms: &self.quad_transforms,
278 quads_start: 0,
279 quads_iter: self.quads.iter().peekable(),
280 backdrop_blurs: &self.backdrop_blurs,
281 backdrop_blur_transforms: &self.backdrop_blur_transforms,
282 backdrop_blurs_start: 0,
283 backdrop_blurs_iter: self.backdrop_blurs.iter().peekable(),
284 paths: &self.paths,
285 paths_start: 0,
286 paths_iter: self.paths.iter().peekable(),
287 underlines: &self.underlines,
288 underline_transforms: &self.underline_transforms,
289 underlines_start: 0,
290 underlines_iter: self.underlines.iter().peekable(),
291 monochrome_sprites: &self.monochrome_sprites,
292 monochrome_sprites_start: 0,
293 monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
294 polychrome_sprites: &self.polychrome_sprites,
295 polychrome_sprite_transforms: &self.polychrome_sprite_transforms,
296 polychrome_sprites_start: 0,
297 polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(),
298 surfaces: &self.surfaces,
299 surfaces_start: 0,
300 surfaces_iter: self.surfaces.iter().peekable(),
301 }
302 }
303}
304
305#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
306#[cfg_attr(
307 all(
308 any(target_os = "linux", target_os = "freebsd"),
309 not(any(feature = "x11", feature = "wayland"))
310 ),
311 allow(dead_code)
312)]
313pub(crate) enum PrimitiveKind {
314 Shadow,
315 #[default]
316 Quad,
317 BackdropBlur,
318 Path,
319 Underline,
320 MonochromeSprite,
321 PolychromeSprite,
322 Surface,
323}
324
325pub(crate) enum PaintOperation {
326 Primitive(Primitive),
327 StartLayer(Bounds<ScaledPixels>),
328 EndLayer,
329}
330
331#[derive(Clone)]
332pub(crate) enum Primitive {
333 Shadow(Shadow, TransformationMatrix),
334 Quad(Quad, TransformationMatrix),
335 BackdropBlur(BackdropBlur, TransformationMatrix),
336 Path(Path<ScaledPixels>),
337 Underline(Underline, TransformationMatrix),
338 MonochromeSprite(MonochromeSprite),
339 PolychromeSprite(PolychromeSprite, TransformationMatrix),
340 Surface(PaintSurface),
341}
342
343impl Primitive {
344 #[allow(dead_code)]
345 pub fn bounds(&self) -> &Bounds<ScaledPixels> {
346 match self {
347 Primitive::Shadow(shadow, _) => &shadow.bounds,
348 Primitive::Quad(quad, _) => &quad.bounds,
349 Primitive::BackdropBlur(blur, _) => &blur.bounds,
350 Primitive::Path(path) => &path.bounds,
351 Primitive::Underline(underline, _) => &underline.bounds,
352 Primitive::MonochromeSprite(sprite) => &sprite.bounds,
353 Primitive::PolychromeSprite(sprite, _) => &sprite.bounds,
354 Primitive::Surface(surface) => &surface.bounds,
355 }
356 }
357
358 pub fn content_mask(&self) -> &ContentMask<ScaledPixels> {
359 match self {
360 Primitive::Shadow(shadow, _) => &shadow.content_mask,
361 Primitive::Quad(quad, _) => &quad.content_mask,
362 Primitive::BackdropBlur(blur, _) => &blur.content_mask,
363 Primitive::Path(path) => &path.content_mask,
364 Primitive::Underline(underline, _) => &underline.content_mask,
365 Primitive::MonochromeSprite(sprite) => &sprite.content_mask,
366 Primitive::PolychromeSprite(sprite, _) => &sprite.content_mask,
367 Primitive::Surface(surface) => &surface.content_mask,
368 }
369 }
370}
371
372#[cfg_attr(
373 all(
374 any(target_os = "linux", target_os = "freebsd"),
375 not(any(feature = "x11", feature = "wayland"))
376 ),
377 allow(dead_code)
378)]
379struct BatchIterator<'a> {
380 shadows: &'a [Shadow],
381 shadow_transforms: &'a [TransformationMatrix],
382 shadows_start: usize,
383 shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
384 quads: &'a [Quad],
385 quad_transforms: &'a [TransformationMatrix],
386 quads_start: usize,
387 quads_iter: Peekable<slice::Iter<'a, Quad>>,
388 backdrop_blurs: &'a [BackdropBlur],
389 backdrop_blur_transforms: &'a [TransformationMatrix],
390 backdrop_blurs_start: usize,
391 backdrop_blurs_iter: Peekable<slice::Iter<'a, BackdropBlur>>,
392 paths: &'a [Path<ScaledPixels>],
393 paths_start: usize,
394 paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>,
395 underlines: &'a [Underline],
396 underline_transforms: &'a [TransformationMatrix],
397 underlines_start: usize,
398 underlines_iter: Peekable<slice::Iter<'a, Underline>>,
399 monochrome_sprites: &'a [MonochromeSprite],
400 monochrome_sprites_start: usize,
401 monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
402 polychrome_sprites: &'a [PolychromeSprite],
403 polychrome_sprite_transforms: &'a [TransformationMatrix],
404 polychrome_sprites_start: usize,
405 polychrome_sprites_iter: Peekable<slice::Iter<'a, PolychromeSprite>>,
406 surfaces: &'a [PaintSurface],
407 surfaces_start: usize,
408 surfaces_iter: Peekable<slice::Iter<'a, PaintSurface>>,
409}
410
411impl<'a> Iterator for BatchIterator<'a> {
412 type Item = PrimitiveBatch<'a>;
413
414 fn next(&mut self) -> Option<Self::Item> {
415 let mut orders_and_kinds = [
416 (
417 self.shadows_iter.peek().map(|s| s.order),
418 PrimitiveKind::Shadow,
419 ),
420 (self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
421 (
422 self.backdrop_blurs_iter.peek().map(|b| b.order),
423 PrimitiveKind::BackdropBlur,
424 ),
425 (self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
426 (
427 self.underlines_iter.peek().map(|u| u.order),
428 PrimitiveKind::Underline,
429 ),
430 (
431 self.monochrome_sprites_iter.peek().map(|s| s.order),
432 PrimitiveKind::MonochromeSprite,
433 ),
434 (
435 self.polychrome_sprites_iter.peek().map(|s| s.order),
436 PrimitiveKind::PolychromeSprite,
437 ),
438 (
439 self.surfaces_iter.peek().map(|s| s.order),
440 PrimitiveKind::Surface,
441 ),
442 ];
443 orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
444
445 let first = orders_and_kinds[0];
446 let second = orders_and_kinds[1];
447 let (batch_kind, max_order_and_kind) = if first.0.is_some() {
448 (first.1, (second.0.unwrap_or(u32::MAX), second.1))
449 } else {
450 return None;
451 };
452
453 match batch_kind {
454 PrimitiveKind::Shadow => {
455 let shadows_start = self.shadows_start;
456 let mut shadows_end = shadows_start + 1;
457 self.shadows_iter.next();
458 while self
459 .shadows_iter
460 .next_if(|shadow| (shadow.order, batch_kind) < max_order_and_kind)
461 .is_some()
462 {
463 shadows_end += 1;
464 }
465 self.shadows_start = shadows_end;
466 Some(PrimitiveBatch::Shadows(
467 &self.shadows[shadows_start..shadows_end],
468 &self.shadow_transforms[shadows_start..shadows_end],
469 ))
470 }
471 PrimitiveKind::Quad => {
472 let quads_start = self.quads_start;
473 let mut quads_end = quads_start + 1;
474 self.quads_iter.next();
475 while self
476 .quads_iter
477 .next_if(|quad| (quad.order, batch_kind) < max_order_and_kind)
478 .is_some()
479 {
480 quads_end += 1;
481 }
482 self.quads_start = quads_end;
483 Some(PrimitiveBatch::Quads(
484 &self.quads[quads_start..quads_end],
485 &self.quad_transforms[quads_start..quads_end],
486 ))
487 }
488 PrimitiveKind::BackdropBlur => {
489 let blurs_start = self.backdrop_blurs_start;
490 let mut blurs_end = blurs_start + 1;
491 self.backdrop_blurs_iter.next();
492 while self
493 .backdrop_blurs_iter
494 .next_if(|blur| (blur.order, batch_kind) < max_order_and_kind)
495 .is_some()
496 {
497 blurs_end += 1;
498 }
499 self.backdrop_blurs_start = blurs_end;
500 Some(PrimitiveBatch::BackdropBlurs(
501 &self.backdrop_blurs[blurs_start..blurs_end],
502 &self.backdrop_blur_transforms[blurs_start..blurs_end],
503 ))
504 }
505 PrimitiveKind::Path => {
506 let paths_start = self.paths_start;
507 let mut paths_end = paths_start + 1;
508 self.paths_iter.next();
509 while self
510 .paths_iter
511 .next_if(|path| (path.order, batch_kind) < max_order_and_kind)
512 .is_some()
513 {
514 paths_end += 1;
515 }
516 self.paths_start = paths_end;
517 Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end]))
518 }
519 PrimitiveKind::Underline => {
520 let underlines_start = self.underlines_start;
521 let mut underlines_end = underlines_start + 1;
522 self.underlines_iter.next();
523 while self
524 .underlines_iter
525 .next_if(|underline| (underline.order, batch_kind) < max_order_and_kind)
526 .is_some()
527 {
528 underlines_end += 1;
529 }
530 self.underlines_start = underlines_end;
531 Some(PrimitiveBatch::Underlines(
532 &self.underlines[underlines_start..underlines_end],
533 &self.underline_transforms[underlines_start..underlines_end],
534 ))
535 }
536 PrimitiveKind::MonochromeSprite => {
537 let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
538 let sprites_start = self.monochrome_sprites_start;
539 let mut sprites_end = sprites_start + 1;
540 self.monochrome_sprites_iter.next();
541 while self
542 .monochrome_sprites_iter
543 .next_if(|sprite| {
544 (sprite.order, batch_kind) < max_order_and_kind
545 && sprite.tile.texture_id == texture_id
546 })
547 .is_some()
548 {
549 sprites_end += 1;
550 }
551 self.monochrome_sprites_start = sprites_end;
552 Some(PrimitiveBatch::MonochromeSprites {
553 texture_id,
554 sprites: &self.monochrome_sprites[sprites_start..sprites_end],
555 })
556 }
557 PrimitiveKind::PolychromeSprite => {
558 let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
559 let sprites_start = self.polychrome_sprites_start;
560 let mut sprites_end = self.polychrome_sprites_start + 1;
561 self.polychrome_sprites_iter.next();
562 while self
563 .polychrome_sprites_iter
564 .next_if(|sprite| {
565 (sprite.order, batch_kind) < max_order_and_kind
566 && sprite.tile.texture_id == texture_id
567 })
568 .is_some()
569 {
570 sprites_end += 1;
571 }
572 self.polychrome_sprites_start = sprites_end;
573 Some(PrimitiveBatch::PolychromeSprites {
574 texture_id,
575 sprites: &self.polychrome_sprites[sprites_start..sprites_end],
576 transforms: &self.polychrome_sprite_transforms[sprites_start..sprites_end],
577 })
578 }
579 PrimitiveKind::Surface => {
580 let surfaces_start = self.surfaces_start;
581 let mut surfaces_end = surfaces_start + 1;
582 self.surfaces_iter.next();
583 while self
584 .surfaces_iter
585 .next_if(|surface| (surface.order, batch_kind) < max_order_and_kind)
586 .is_some()
587 {
588 surfaces_end += 1;
589 }
590 self.surfaces_start = surfaces_end;
591 Some(PrimitiveBatch::Surfaces(
592 &self.surfaces[surfaces_start..surfaces_end],
593 ))
594 }
595 }
596 }
597}
598
599#[derive(Debug)]
600#[cfg_attr(
601 all(
602 any(target_os = "linux", target_os = "freebsd"),
603 not(any(feature = "x11", feature = "wayland"))
604 ),
605 allow(dead_code)
606)]
607pub(crate) enum PrimitiveBatch<'a> {
608 Shadows(&'a [Shadow], &'a [TransformationMatrix]),
609 Quads(&'a [Quad], &'a [TransformationMatrix]),
610 BackdropBlurs(&'a [BackdropBlur], &'a [TransformationMatrix]),
611 Paths(&'a [Path<ScaledPixels>]),
612 Underlines(&'a [Underline], &'a [TransformationMatrix]),
613 MonochromeSprites {
614 texture_id: AtlasTextureId,
615 sprites: &'a [MonochromeSprite],
616 },
617 PolychromeSprites {
618 texture_id: AtlasTextureId,
619 sprites: &'a [PolychromeSprite],
620 transforms: &'a [TransformationMatrix],
621 },
622 Surfaces(&'a [PaintSurface]),
623}
624
625#[derive(Default, Debug, Clone)]
626#[repr(C)]
627pub(crate) struct Quad {
628 pub order: DrawOrder,
629 pub border_style: BorderStyle,
630 pub bounds: Bounds<ScaledPixels>,
631 pub content_mask: ContentMask<ScaledPixels>,
632 pub background: Background,
633 pub border_color: Hsla,
634 pub corner_radii: Corners<ScaledPixels>,
635 pub border_widths: Edges<ScaledPixels>,
636}
637
638impl From<(Quad, TransformationMatrix)> for Primitive {
639 fn from((quad, transform): (Quad, TransformationMatrix)) -> Self {
640 Primitive::Quad(quad, transform)
641 }
642}
643
644#[derive(Debug, Clone)]
645#[repr(C)]
646pub(crate) struct BackdropBlur {
647 pub order: DrawOrder,
648 pub blur_radius: ScaledPixels,
649 pub bounds: Bounds<ScaledPixels>,
650 pub corner_radii: Corners<ScaledPixels>,
651 pub content_mask: ContentMask<ScaledPixels>,
652 pub tint: Hsla,
653}
654
655impl From<(BackdropBlur, TransformationMatrix)> for Primitive {
656 fn from((blur, transform): (BackdropBlur, TransformationMatrix)) -> Self {
657 Primitive::BackdropBlur(blur, transform)
658 }
659}
660
661#[derive(Debug, Clone)]
662#[repr(C)]
663pub(crate) struct Underline {
664 pub order: DrawOrder,
665 pub pad: u32, pub bounds: Bounds<ScaledPixels>,
667 pub content_mask: ContentMask<ScaledPixels>,
668 pub color: Hsla,
669 pub thickness: ScaledPixels,
670 pub wavy: u32,
671}
672
673impl From<(Underline, TransformationMatrix)> for Primitive {
674 fn from((underline, transform): (Underline, TransformationMatrix)) -> Self {
675 Primitive::Underline(underline, transform)
676 }
677}
678
679#[derive(Debug, Clone)]
680#[repr(C)]
681pub(crate) struct Shadow {
682 pub order: DrawOrder,
683 pub blur_radius: ScaledPixels,
684 pub bounds: Bounds<ScaledPixels>,
685 pub corner_radii: Corners<ScaledPixels>,
686 pub content_mask: ContentMask<ScaledPixels>,
687 pub color: Hsla,
688}
689
690impl From<(Shadow, TransformationMatrix)> for Primitive {
691 fn from((shadow, transform): (Shadow, TransformationMatrix)) -> Self {
692 Primitive::Shadow(shadow, transform)
693 }
694}
695
696#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
698#[repr(C)]
699pub enum BorderStyle {
700 #[default]
702 Solid = 0,
703 Dashed = 1,
705}
706
707#[derive(Debug, Clone, Copy, PartialEq)]
713#[repr(C)]
714pub struct TransformationMatrix {
715 pub rotation_scale: [[f32; 2]; 2],
718 pub translation: [f32; 2],
720}
721
722impl Eq for TransformationMatrix {}
723
724impl TransformationMatrix {
725 pub fn unit() -> Self {
727 Self {
728 rotation_scale: [[1.0, 0.0], [0.0, 1.0]],
729 translation: [0.0, 0.0],
730 }
731 }
732
733 pub fn translate(mut self, point: Point<Pixels>) -> Self {
735 self.compose(Self {
736 rotation_scale: [[1.0, 0.0], [0.0, 1.0]],
737 translation: [point.x.0, point.y.0],
738 })
739 }
740
741 pub fn rotate(self, angle: Radians) -> Self {
743 self.compose(Self {
744 rotation_scale: [
745 [angle.0.cos(), -angle.0.sin()],
746 [angle.0.sin(), angle.0.cos()],
747 ],
748 translation: [0.0, 0.0],
749 })
750 }
751
752 pub fn scale(self, size: Size<f32>) -> Self {
754 self.compose(Self {
755 rotation_scale: [[size.width, 0.0], [0.0, size.height]],
756 translation: [0.0, 0.0],
757 })
758 }
759
760 #[inline]
764 pub fn compose(self, other: TransformationMatrix) -> TransformationMatrix {
765 if other == Self::unit() {
766 return self;
767 }
768 TransformationMatrix {
770 rotation_scale: [
771 [
772 self.rotation_scale[0][0] * other.rotation_scale[0][0]
773 + self.rotation_scale[0][1] * other.rotation_scale[1][0],
774 self.rotation_scale[0][0] * other.rotation_scale[0][1]
775 + self.rotation_scale[0][1] * other.rotation_scale[1][1],
776 ],
777 [
778 self.rotation_scale[1][0] * other.rotation_scale[0][0]
779 + self.rotation_scale[1][1] * other.rotation_scale[1][0],
780 self.rotation_scale[1][0] * other.rotation_scale[0][1]
781 + self.rotation_scale[1][1] * other.rotation_scale[1][1],
782 ],
783 ],
784 translation: [
785 self.translation[0]
786 + self.rotation_scale[0][0] * other.translation[0]
787 + self.rotation_scale[0][1] * other.translation[1],
788 self.translation[1]
789 + self.rotation_scale[1][0] * other.translation[0]
790 + self.rotation_scale[1][1] * other.translation[1],
791 ],
792 }
793 }
794
795 pub fn is_unit(&self) -> bool {
797 *self == Self::unit()
798 }
799
800 pub fn is_translation_only(&self) -> bool {
802 self.rotation_scale == [[1.0, 0.0], [0.0, 1.0]]
803 }
804
805 pub fn apply_inverse(&self, point: Point<Pixels>) -> Option<Point<Pixels>> {
808 let det = self.rotation_scale[0][0] * self.rotation_scale[1][1]
810 - self.rotation_scale[0][1] * self.rotation_scale[1][0];
811 if det == 0.0 {
812 return None;
813 }
814
815 let inv = [
816 [
817 self.rotation_scale[1][1] / det,
818 -self.rotation_scale[0][1] / det,
819 ],
820 [
821 -self.rotation_scale[1][0] / det,
822 self.rotation_scale[0][0] / det,
823 ],
824 ];
825
826 let translated = [
827 point.x.0 - self.translation[0],
828 point.y.0 - self.translation[1],
829 ];
830
831 let local = [
832 inv[0][0] * translated[0] + inv[0][1] * translated[1],
833 inv[1][0] * translated[0] + inv[1][1] * translated[1],
834 ];
835
836 Some(Point::new(local[0].into(), local[1].into()))
837 }
838
839 pub fn apply(&self, point: Point<Pixels>) -> Point<Pixels> {
841 let input = [point.x.0, point.y.0];
842 let mut output = self.translation;
843 for (i, output_cell) in output.iter_mut().enumerate() {
844 for (k, input_cell) in input.iter().enumerate() {
845 *output_cell += self.rotation_scale[i][k] * *input_cell;
846 }
847 }
848 Point::new(output[0].into(), output[1].into())
849 }
850}
851
852impl Default for TransformationMatrix {
853 fn default() -> Self {
854 Self::unit()
855 }
856}
857
858#[derive(Clone, Debug)]
859#[repr(C)]
860pub(crate) struct MonochromeSprite {
861 pub order: DrawOrder,
862 pub pad: u32, pub bounds: Bounds<ScaledPixels>,
864 pub content_mask: ContentMask<ScaledPixels>,
865 pub color: Hsla,
866 pub tile: AtlasTile,
867 pub transformation: TransformationMatrix,
868}
869
870impl From<MonochromeSprite> for Primitive {
871 fn from(sprite: MonochromeSprite) -> Self {
872 Primitive::MonochromeSprite(sprite)
873 }
874}
875
876#[derive(Clone, Debug)]
877#[repr(C)]
878pub(crate) struct PolychromeSprite {
879 pub order: DrawOrder,
880 pub pad: u32, pub grayscale: bool,
882 pub opacity: f32,
883 pub bounds: Bounds<ScaledPixels>,
884 pub content_mask: ContentMask<ScaledPixels>,
885 pub corner_radii: Corners<ScaledPixels>,
886 pub tile: AtlasTile,
887}
888
889impl From<(PolychromeSprite, TransformationMatrix)> for Primitive {
890 fn from((sprite, transform): (PolychromeSprite, TransformationMatrix)) -> Self {
891 Primitive::PolychromeSprite(sprite, transform)
892 }
893}
894
895#[derive(Clone, Debug)]
896pub(crate) struct PaintSurface {
897 pub order: DrawOrder,
898 pub bounds: Bounds<ScaledPixels>,
899 pub content_mask: ContentMask<ScaledPixels>,
900 #[cfg(target_os = "macos")]
901 pub image_buffer: core_video::pixel_buffer::CVPixelBuffer,
902}
903
904impl From<PaintSurface> for Primitive {
905 fn from(surface: PaintSurface) -> Self {
906 Primitive::Surface(surface)
907 }
908}
909
910#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
911pub(crate) struct PathId(pub(crate) usize);
912
913#[derive(Clone, Debug)]
915pub struct Path<P: Clone + Debug + Default + PartialEq> {
916 pub(crate) id: PathId,
917 pub(crate) order: DrawOrder,
918 pub(crate) bounds: Bounds<P>,
919 pub(crate) content_mask: ContentMask<P>,
920 pub(crate) vertices: Vec<PathVertex<P>>,
921 pub(crate) color: Background,
922 start: Point<P>,
923 current: Point<P>,
924 contour_count: usize,
925}
926
927impl Path<Pixels> {
928 pub fn new(start: Point<Pixels>) -> Self {
930 Self {
931 id: PathId(0),
932 order: DrawOrder::default(),
933 vertices: Vec::new(),
934 start,
935 current: start,
936 bounds: Bounds {
937 origin: start,
938 size: Default::default(),
939 },
940 content_mask: Default::default(),
941 color: Default::default(),
942 contour_count: 0,
943 }
944 }
945
946 pub fn scale(&self, factor: f32) -> Path<ScaledPixels> {
948 Path {
949 id: self.id,
950 order: self.order,
951 bounds: self.bounds.scale(factor),
952 content_mask: self.content_mask.scale(factor),
953 vertices: self
954 .vertices
955 .iter()
956 .map(|vertex| vertex.scale(factor))
957 .collect(),
958 start: self.start.map(|start| start.scale(factor)),
959 current: self.current.scale(factor),
960 contour_count: self.contour_count,
961 color: self.color,
962 }
963 }
964
965 pub fn move_to(&mut self, to: Point<Pixels>) {
967 self.contour_count += 1;
968 self.start = to;
969 self.current = to;
970 }
971
972 pub fn line_to(&mut self, to: Point<Pixels>) {
974 self.contour_count += 1;
975 if self.contour_count > 1 {
976 self.push_triangle(
977 (self.start, self.current, to),
978 (point(0., 1.), point(0., 1.), point(0., 1.)),
979 );
980 }
981 self.current = to;
982 }
983
984 pub fn curve_to(&mut self, to: Point<Pixels>, ctrl: Point<Pixels>) {
986 self.contour_count += 1;
987 if self.contour_count > 1 {
988 self.push_triangle(
989 (self.start, self.current, to),
990 (point(0., 1.), point(0., 1.), point(0., 1.)),
991 );
992 }
993
994 self.push_triangle(
995 (self.current, ctrl, to),
996 (point(0., 0.), point(0.5, 0.), point(1., 1.)),
997 );
998 self.current = to;
999 }
1000
1001 pub fn push_triangle(
1003 &mut self,
1004 xy: (Point<Pixels>, Point<Pixels>, Point<Pixels>),
1005 st: (Point<f32>, Point<f32>, Point<f32>),
1006 ) {
1007 self.bounds = self
1008 .bounds
1009 .union(&Bounds {
1010 origin: xy.0,
1011 size: Default::default(),
1012 })
1013 .union(&Bounds {
1014 origin: xy.1,
1015 size: Default::default(),
1016 })
1017 .union(&Bounds {
1018 origin: xy.2,
1019 size: Default::default(),
1020 });
1021
1022 self.vertices.push(PathVertex {
1023 xy_position: xy.0,
1024 st_position: st.0,
1025 content_mask: Default::default(),
1026 });
1027 self.vertices.push(PathVertex {
1028 xy_position: xy.1,
1029 st_position: st.1,
1030 content_mask: Default::default(),
1031 });
1032 self.vertices.push(PathVertex {
1033 xy_position: xy.2,
1034 st_position: st.2,
1035 content_mask: Default::default(),
1036 });
1037 }
1038}
1039
1040impl<T> Path<T>
1041where
1042 T: Clone + Debug + Default + PartialEq + PartialOrd + Add<T, Output = T> + Sub<Output = T>,
1043{
1044 #[allow(unused)]
1045 pub(crate) fn clipped_bounds(&self) -> Bounds<T> {
1046 self.bounds.intersect(&self.content_mask.bounds)
1047 }
1048}
1049
1050impl From<Path<ScaledPixels>> for Primitive {
1051 fn from(path: Path<ScaledPixels>) -> Self {
1052 Primitive::Path(path)
1053 }
1054}
1055
1056#[derive(Clone, Debug)]
1057#[repr(C)]
1058pub(crate) struct PathVertex<P: Clone + Debug + Default + PartialEq> {
1059 pub(crate) xy_position: Point<P>,
1060 pub(crate) st_position: Point<f32>,
1061 pub(crate) content_mask: ContentMask<P>,
1062}
1063
1064impl PathVertex<Pixels> {
1065 pub fn scale(&self, factor: f32) -> PathVertex<ScaledPixels> {
1066 PathVertex {
1067 xy_position: self.xy_position.scale(factor),
1068 st_position: self.st_position,
1069 content_mask: self.content_mask.scale(factor),
1070 }
1071 }
1072}