1use crate::kurbo::{Affine, BezPath};
7use crate::strip::Strip;
8use crate::strip_generator::{GenerationMode, StripGenerator, StripStorage};
9use crate::tile::Tile;
10use crate::util::normalized_mul_u8x16;
11use alloc::vec;
12use alloc::vec::Vec;
13use fearless_simd::{Level, Simd, SimdBase, dispatch, u8x16};
14use peniko::Fill;
15
16#[derive(Debug)]
17struct ClipData {
18 alpha_start: u32,
19 strip_start: u32,
20}
21
22impl ClipData {
23 fn to_path_data_ref<'a>(&self, storage: &'a StripStorage) -> PathDataRef<'a> {
24 PathDataRef {
25 strips: storage
26 .strips
27 .get(self.strip_start as usize..)
28 .unwrap_or(&[]),
29 alphas: storage
30 .alphas
31 .get(self.alpha_start as usize..)
32 .unwrap_or(&[]),
33 }
34 }
35}
36
37#[derive(Debug)]
39pub struct ClipContext {
40 storage: StripStorage,
41 temp_storage: StripStorage,
42 clip_stack: Vec<ClipData>,
43}
44
45impl Default for ClipContext {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl ClipContext {
52 #[inline]
54 pub fn new() -> Self {
55 let mut main_storage = StripStorage::default();
56 main_storage.set_generation_mode(GenerationMode::Append);
57 Self {
58 storage: main_storage,
59 temp_storage: Default::default(),
60 clip_stack: vec![],
61 }
62 }
63
64 #[inline]
66 pub fn reset(&mut self) {
67 self.clip_stack.clear();
68 self.storage.clear();
69 self.temp_storage.clear();
70 }
71
72 #[inline]
74 pub fn get(&self) -> Option<PathDataRef<'_>> {
75 self.clip_stack
76 .last()
77 .map(|c| c.to_path_data_ref(&self.storage))
78 }
79
80 #[inline]
82 pub fn push_clip(
83 &mut self,
84 clip_path: &BezPath,
85 strip_generator: &mut StripGenerator,
86 fill_rule: Fill,
87 transform: Affine,
88 aliasing_threshold: Option<u8>,
89 ) {
90 self.temp_storage.clear();
91
92 let alpha_start = self.storage.alphas.len() as u32;
93 let strip_start = self.storage.strips.len() as u32;
94
95 let clip_data = ClipData {
96 alpha_start,
97 strip_start,
98 };
99
100 let existing_clip = self
101 .clip_stack
102 .last()
103 .map(|c| c.to_path_data_ref(&self.storage));
104
105 strip_generator.generate_filled_path(
106 clip_path,
107 fill_rule,
108 transform,
109 aliasing_threshold,
110 &mut self.temp_storage,
111 existing_clip,
112 );
113
114 self.storage.extend(&self.temp_storage);
115 self.clip_stack.push(clip_data);
116 }
117
118 #[inline]
120 pub fn pop_clip(&mut self) {
121 let data = self.clip_stack.pop().expect("clip stack underflowed");
122 self.storage.strips.truncate(data.strip_start as usize);
123 self.storage.alphas.truncate(data.alpha_start as usize);
124 }
125}
126
127#[derive(Clone, Copy, Debug)]
129pub struct PathDataRef<'a> {
130 pub strips: &'a [Strip],
132 pub alphas: &'a [u8],
134}
135
136pub fn intersect(
140 level: Level,
141 path_1: PathDataRef<'_>,
142 path_2: PathDataRef<'_>,
143 target: &mut StripStorage,
144) {
145 dispatch!(level, simd => intersect_impl(simd, path_1, path_2, target));
146}
147
148fn intersect_impl<S: Simd>(
160 simd: S,
161 path_1: PathDataRef<'_>,
162 path_2: PathDataRef<'_>,
163 target: &mut StripStorage,
164) {
165 if path_1.strips.is_empty() || path_2.strips.is_empty() {
167 return;
168 }
169
170 let mut cur_y = path_1.strips[0].strip_y().min(path_2.strips[0].strip_y());
173 let end_y = path_1.strips[path_1.strips.len() - 1]
174 .strip_y()
175 .min(path_2.strips[path_2.strips.len() - 1].strip_y());
176
177 let mut path_1_idx = 0;
178 let mut path_2_idx = 0;
179 let mut strip_state = None;
180
181 while cur_y <= end_y {
183 let mut p1_iter = RowIterator::new(path_1, &mut path_1_idx, cur_y);
186 let mut p2_iter = RowIterator::new(path_2, &mut path_2_idx, cur_y);
187
188 let mut p1_region = p1_iter.next();
189 let mut p2_region = p2_iter.next();
190
191 while let (Some(region_1), Some(region_2)) = (p1_region, p2_region) {
197 match region_1.overlap_relationship(®ion_2) {
198 OverlapRelationship::Advance(advance) => {
201 match advance {
202 Advance::Left => p1_region = p1_iter.next(),
203 Advance::Right => p2_region = p2_iter.next(),
204 };
205
206 continue;
207 }
208 OverlapRelationship::Overlap(overlap) => {
210 match (region_1, region_2) {
211 (Region::Fill(_), Region::Fill(_)) => {
216 flush_strip(&mut strip_state, &mut target.strips, cur_y);
217 start_strip(&mut strip_state, &target.alphas, overlap.end, true);
218 }
219 (Region::Strip(s), Region::Fill(_))
221 | (Region::Fill(_), Region::Strip(s)) => {
222 if should_create_new_strip(&strip_state, &target.alphas, overlap.start)
224 {
225 flush_strip(&mut strip_state, &mut target.strips, cur_y);
226 start_strip(&mut strip_state, &target.alphas, overlap.start, false);
227 }
228
229 let s_alphas = &s.alphas[(overlap.start - s.start) as usize * 4..]
230 [..overlap.width() as usize * 4];
231 target.alphas.extend_from_slice(s_alphas);
232 }
233 (Region::Strip(s_region_1), Region::Strip(s_region_2)) => {
235 if should_create_new_strip(&strip_state, &target.alphas, overlap.start)
237 {
238 flush_strip(&mut strip_state, &mut target.strips, cur_y);
239 start_strip(&mut strip_state, &target.alphas, overlap.start, false);
240 }
241
242 let num_blocks = overlap.width() / Tile::HEIGHT;
243
244 let s1_alphas = s_region_1.alphas
246 [(overlap.start - s_region_1.start) as usize * 4..]
247 .chunks_exact(16)
248 .take(num_blocks as usize);
249 let s2_alphas = s_region_2.alphas
250 [(overlap.start - s_region_2.start) as usize * 4..]
251 .chunks_exact(16)
252 .take(num_blocks as usize);
253
254 for (s1_alpha, s2_alpha) in s1_alphas.zip(s2_alphas) {
255 let s1 = u8x16::from_slice(simd, s1_alpha);
256 let s2 = u8x16::from_slice(simd, s2_alpha);
257
258 let res = simd.narrow_u16x16(normalized_mul_u8x16(s1, s2));
260 target.alphas.extend(res.as_slice());
261 }
262 }
263 }
264
265 match overlap.advance {
267 Advance::Left => p1_region = p1_iter.next(),
268 Advance::Right => p2_region = p2_iter.next(),
269 };
270 }
271 }
272 }
273
274 flush_strip(&mut strip_state, &mut target.strips, cur_y);
276 cur_y += 1;
277 }
278
279 target.strips.push(Strip::new(
281 u16::MAX,
282 end_y * Tile::HEIGHT,
283 target.alphas.len() as u32,
284 false,
285 ));
286}
287
288struct Overlap {
290 start: u16,
292 end: u16,
294 advance: Advance,
296}
297
298impl Overlap {
299 fn width(&self) -> u16 {
300 self.end - self.start
301 }
302}
303
304enum Advance {
305 Left,
306 Right,
307}
308
309enum OverlapRelationship {
311 Advance(Advance),
313 Overlap(Overlap),
315}
316
317#[derive(Debug, Clone, Copy)]
318struct FillRegion {
319 start: u16,
320 width: u16,
321}
322
323#[derive(Debug, Clone, Copy)]
324struct StripRegion<'a> {
325 start: u16,
326 width: u16,
327 alphas: &'a [u8],
328}
329
330#[derive(Debug, Clone, Copy)]
331enum Region<'a> {
332 Fill(FillRegion),
333 Strip(StripRegion<'a>),
334}
335
336impl Region<'_> {
337 #[inline(always)]
338 fn start(&self) -> u16 {
339 match self {
340 Region::Fill(fill) => fill.start,
341 Region::Strip(strip) => strip.start,
342 }
343 }
344
345 #[inline(always)]
346 fn width(&self) -> u16 {
347 match self {
348 Region::Fill(fill) => fill.width,
349 Region::Strip(strip) => strip.width,
350 }
351 }
352
353 #[inline(always)]
354 fn end(&self) -> u16 {
355 self.start() + self.width()
356 }
357
358 fn overlap_relationship(&self, other: &Region<'_>) -> OverlapRelationship {
359 if self.end() <= other.start() {
360 OverlapRelationship::Advance(Advance::Left)
361 } else if self.start() >= other.end() {
362 OverlapRelationship::Advance(Advance::Right)
363 } else {
364 let start = self.start().max(other.start());
365 let end = self.end().min(other.end());
366
367 let shift = if self.end() <= other.end() {
368 Advance::Left
369 } else {
370 Advance::Right
371 };
372
373 OverlapRelationship::Overlap(Overlap {
374 advance: shift,
375 start,
376 end,
377 })
378 }
379 }
380}
381
382struct RowIterator<'a> {
384 input: PathDataRef<'a>,
386 strip_y: u16,
388 cur_idx: &'a mut usize,
390 on_strip: bool,
395}
396
397impl<'a> RowIterator<'a> {
398 fn new(input: PathDataRef<'a>, cur_idx: &'a mut usize, strip_y: u16) -> Self {
399 while input.strips[*cur_idx].strip_y() < strip_y {
401 *cur_idx += 1;
402 }
403
404 Self {
405 input,
406 cur_idx,
407 strip_y,
408 on_strip: true,
409 }
410 }
411
412 #[inline(always)]
413 fn cur_strip(&self) -> &Strip {
414 &self.input.strips[*self.cur_idx]
415 }
416
417 #[inline(always)]
418 fn next_strip(&self) -> &Strip {
419 &self.input.strips[*self.cur_idx + 1]
420 }
421
422 #[inline(always)]
423 fn cur_strip_width(&self) -> u16 {
424 let cur = self.cur_strip();
425 let next = self.next_strip();
426 ((next.alpha_idx() - cur.alpha_idx()) / Tile::HEIGHT as u32) as u16
427 }
428
429 #[inline(always)]
430 fn cur_strip_alphas(&self) -> &'a [u8] {
431 let cur = self.cur_strip();
432 let next = self.next_strip();
433 &self.input.alphas[cur.alpha_idx() as usize..next.alpha_idx() as usize]
434 }
435
436 fn cur_strip_fill_area(&self) -> Option<FillRegion> {
437 let next = self.next_strip();
438
439 if next.fill_gap() {
442 let cur = self.cur_strip();
443 let x = cur.x + self.cur_strip_width();
444 let width = next.x - x;
445
446 Some(FillRegion { start: x, width })
447 } else {
448 None
449 }
450 }
451}
452
453impl<'a> Iterator for RowIterator<'a> {
454 type Item = Region<'a>;
455
456 #[inline(always)]
457 fn next(&mut self) -> Option<Self::Item> {
458 if !self.on_strip {
460 self.on_strip = true;
462
463 if let Some(fill_area) = self.cur_strip_fill_area() {
467 *self.cur_idx += 1;
468
469 return Some(Region::Fill(fill_area));
470 } else {
471 *self.cur_idx += 1;
472 }
473 }
474
475 self.on_strip = false;
478
479 if self.cur_strip().is_sentinel() || self.cur_strip().strip_y() != self.strip_y {
481 return None;
482 }
483
484 let x = self.cur_strip().x;
486 let width = self.cur_strip_width();
487 let alphas = self.cur_strip_alphas();
488
489 Some(Region::Strip(StripRegion {
490 start: x,
491 width,
492 alphas,
493 }))
494 }
495}
496
497struct StripState {
499 x: u16,
500 alpha_idx: u32,
501 fill_gap: bool,
502}
503
504fn flush_strip(strip_state: &mut Option<StripState>, strips: &mut Vec<Strip>, cur_y: u16) {
505 if let Some(state) = core::mem::take(strip_state) {
506 strips.push(Strip::new(
507 state.x,
508 cur_y * Tile::HEIGHT,
509 state.alpha_idx,
510 state.fill_gap,
511 ));
512 }
513}
514
515#[inline(always)]
516fn start_strip(strip_data: &mut Option<StripState>, alphas: &[u8], x: u16, fill_gap: bool) {
517 *strip_data = Some(StripState {
518 x,
519 alpha_idx: alphas.len() as u32,
520 fill_gap,
521 });
522}
523
524fn should_create_new_strip(
525 strip_state: &Option<StripState>,
526 alphas: &[u8],
527 overlap_start: u16,
528) -> bool {
529 strip_state.as_ref().is_none_or(|state| {
531 let width = ((alphas.len() as u32 - state.alpha_idx) / Tile::HEIGHT as u32) as u16;
532 let strip_end = state.x + width;
533
534 strip_end < overlap_start - 1
535 })
536}
537
538#[cfg(test)]
539mod tests {
540 use crate::clip::{PathDataRef, RowIterator, intersect};
541 use crate::strip::Strip;
542 use crate::strip_generator::StripStorage;
543 use crate::tile::Tile;
544 use fearless_simd::Level;
545 use std::vec;
546
547 #[test]
548 fn intersect_partly_overlapping_strips() {
549 let path_1 = StripBuilder::new().add_strip(0, 0, 32, false).finish();
550
551 let path_2 = StripBuilder::new().add_strip(8, 0, 44, false).finish();
552
553 let expected = StripBuilder::new().add_strip(8, 0, 32, false).finish();
554
555 run_test(expected, path_1, path_2);
556 }
557
558 #[test]
559 fn intersect_multiple_overlapping_strips() {
560 let path_1 = StripBuilder::new()
561 .add_strip(0, 1, 4, false)
562 .add_strip(12, 1, 20, true)
563 .add_strip(28, 1, 32, false)
564 .add_strip(44, 1, 52, true)
565 .finish();
566
567 let path_2 = StripBuilder::new()
568 .add_strip(4, 1, 8, false)
569 .add_strip(16, 1, 20, true)
570 .add_strip(24, 1, 28, false)
571 .add_strip(32, 1, 36, false)
572 .add_strip(44, 1, 48, true)
573 .finish();
574
575 let expected = StripBuilder::new()
576 .add_strip(4, 1, 8, false)
577 .add_strip(12, 1, 20, true)
578 .add_strip(32, 1, 36, false)
579 .add_strip(44, 1, 48, true)
580 .finish();
581
582 run_test(expected, path_1, path_2);
583 }
584
585 #[test]
586 fn multiple_rows() {
587 let path_1 = StripBuilder::new()
588 .add_strip(0, 0, 4, false)
589 .add_strip(16, 0, 20, true)
590 .add_strip(4, 1, 8, false)
591 .add_strip(12, 1, 24, true)
592 .add_strip(4, 2, 8, false)
593 .add_strip(16, 2, 32, true)
594 .finish();
595
596 let path_2 = StripBuilder::new()
597 .add_strip(0, 2, 4, false)
598 .add_strip(16, 2, 24, true)
599 .add_strip(8, 3, 12, false)
600 .add_strip(16, 3, 28, true)
601 .finish();
602
603 let expected = StripBuilder::new()
604 .add_strip(4, 2, 8, false)
605 .add_strip(16, 2, 24, true)
606 .finish();
607
608 run_test(expected, path_1, path_2);
609 }
610
611 #[test]
612 fn alpha_buffer_correct_width() {
613 let path_1 = StripBuilder::new()
614 .add_strip(0, 0, 4, false)
615 .add_strip(0, 1, 12, false)
616 .finish();
617
618 let path_2 = StripBuilder::new()
619 .add_strip(4, 0, 8, false)
620 .add_strip(0, 1, 4, false)
621 .add_strip(12, 1, 16, true)
622 .finish();
623
624 let expected = StripBuilder::new().add_strip(0, 1, 12, false).finish();
625
626 run_test(expected, path_1, path_2);
627 }
628
629 #[test]
630 fn row_iterator_abort_next_line() {
631 let path_1 = StripBuilder::new()
632 .add_strip(0, 0, 4, false)
633 .add_strip(0, 1, 4, false)
634 .finish();
635
636 let path_ref = PathDataRef {
637 strips: &path_1.strips,
638 alphas: &path_1.alphas,
639 };
640
641 let mut idx = 0;
642 let mut iter = RowIterator::new(path_ref, &mut idx, 0);
643
644 assert!(iter.next().is_some());
645 assert!(iter.next().is_none());
646 }
647
648 fn run_test(expected: StripStorage, path_1: StripStorage, path_2: StripStorage) {
649 let mut write_target = StripStorage::default();
650
651 let path_1 = PathDataRef {
652 strips: &path_1.strips,
653 alphas: &path_1.alphas,
654 };
655
656 let path_2 = PathDataRef {
657 strips: &path_2.strips,
658 alphas: &path_2.alphas,
659 };
660
661 intersect(Level::new(), path_1, path_2, &mut write_target);
662
663 assert_eq!(write_target, expected);
664 }
665
666 struct StripBuilder {
667 storage: StripStorage,
668 }
669
670 impl StripBuilder {
671 fn new() -> Self {
672 Self {
673 storage: StripStorage::default(),
674 }
675 }
676
677 fn add_strip(self, x: u16, strip_y: u16, end: u16, fill_gap: bool) -> Self {
678 let width = end - x;
679 self.add_strip_with(
680 x,
681 strip_y,
682 end,
683 fill_gap,
684 &vec![0; (width * Tile::HEIGHT) as usize],
685 )
686 }
687
688 fn add_strip_with(
689 mut self,
690 x: u16,
691 strip_y: u16,
692 end: u16,
693 fill_gap: bool,
694 alphas: &[u8],
695 ) -> Self {
696 let width = end - x;
697 assert_eq!(alphas.len(), (width * Tile::HEIGHT) as usize);
698 let idx = self.storage.alphas.len();
699 self.storage
700 .strips
701 .push(Strip::new(x, strip_y * Tile::HEIGHT, idx as u32, fill_gap));
702 self.storage.alphas.extend_from_slice(alphas);
703
704 self
705 }
706
707 fn finish(mut self) -> StripStorage {
708 let last_y = self.storage.strips.last().unwrap().y;
709 let idx = self.storage.alphas.len();
710
711 self.storage
712 .strips
713 .push(Strip::new(u16::MAX, last_y, idx as u32, false));
714
715 self.storage
716 }
717 }
718}