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