1use crate::basics::{
12 is_close, is_move_to, is_stop, is_vertex, FillingRule, VertexSource, POLY_SUBPIXEL_SHIFT,
13};
14use crate::rasterizer_cells_aa::{CellAa, RasterizerCellsAa, ScanlineHitTest};
15use crate::rasterizer_sl_clip::{poly_coord, RasterizerSlClipInt};
16
17const AA_SHIFT: u32 = 8;
22const AA_SCALE: u32 = 1 << AA_SHIFT;
23const AA_MASK: u32 = AA_SCALE - 1;
24const AA_SCALE2: u32 = AA_SCALE * 2;
25const AA_MASK2: u32 = AA_SCALE2 - 1;
26
27pub trait Scanline {
36 fn reset_spans(&mut self);
38
39 fn add_cell(&mut self, x: i32, cover: u32);
41
42 fn add_span(&mut self, x: i32, len: u32, cover: u32);
44
45 fn finalize(&mut self, y: i32);
47
48 fn num_spans(&self) -> u32;
50
51 fn y(&self) -> i32;
53}
54
55#[derive(Debug, Clone, Copy, PartialEq)]
60enum Status {
61 Initial,
62 MoveTo,
63 LineTo,
64 Closed,
65}
66
67pub struct RasterizerScanlineAa {
76 outline: RasterizerCellsAa,
77 clipper: RasterizerSlClipInt,
78 filling_rule: FillingRule,
79 auto_close: bool,
80 start_x: i32,
81 start_y: i32,
82 status: Status,
83 scan_y: i32,
84}
85
86impl RasterizerScanlineAa {
87 pub fn new() -> Self {
88 Self {
89 outline: RasterizerCellsAa::new(),
90 clipper: RasterizerSlClipInt::new(),
91 filling_rule: FillingRule::NonZero,
92 auto_close: true,
93 start_x: 0,
94 start_y: 0,
95 status: Status::Initial,
96 scan_y: 0,
97 }
98 }
99
100 pub fn reset(&mut self) {
102 self.outline.reset();
103 self.status = Status::Initial;
104 }
105
106 pub fn filling_rule(&mut self, rule: FillingRule) {
108 self.filling_rule = rule;
109 }
110
111 pub fn auto_close(&mut self, flag: bool) {
113 self.auto_close = flag;
114 }
115
116 pub fn clip_box(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
118 self.reset();
119 self.clipper.clip_box(
120 poly_coord(x1),
121 poly_coord(y1),
122 poly_coord(x2),
123 poly_coord(y2),
124 );
125 }
126
127 pub fn reset_clipping(&mut self) {
129 self.reset();
130 self.clipper.reset_clipping();
131 }
132
133 pub fn close_polygon(&mut self) {
139 if self.status == Status::LineTo {
140 self.clipper
141 .line_to(&mut self.outline, self.start_x, self.start_y);
142 self.status = Status::Closed;
143 }
144 }
145
146 pub fn move_to(&mut self, x: i32, y: i32) {
148 if self.outline.sorted() {
149 self.reset();
150 }
151 if self.auto_close {
152 self.close_polygon();
153 }
154 self.start_x = x;
156 self.start_y = y;
157 self.clipper.move_to(x, y);
158 self.status = Status::MoveTo;
159 }
160
161 pub fn line_to(&mut self, x: i32, y: i32) {
163 self.clipper.line_to(&mut self.outline, x, y);
164 self.status = Status::LineTo;
165 }
166
167 pub fn move_to_d(&mut self, x: f64, y: f64) {
169 if self.outline.sorted() {
170 self.reset();
171 }
172 if self.auto_close {
173 self.close_polygon();
174 }
175 let sx = poly_coord(x);
176 let sy = poly_coord(y);
177 self.start_x = sx;
178 self.start_y = sy;
179 self.clipper.move_to(sx, sy);
180 self.status = Status::MoveTo;
181 }
182
183 pub fn line_to_d(&mut self, x: f64, y: f64) {
185 self.clipper
186 .line_to(&mut self.outline, poly_coord(x), poly_coord(y));
187 self.status = Status::LineTo;
188 }
189
190 pub fn add_vertex(&mut self, x: f64, y: f64, cmd: u32) {
192 if is_move_to(cmd) {
193 self.move_to_d(x, y);
194 } else if is_vertex(cmd) {
195 self.line_to_d(x, y);
196 } else if is_close(cmd) {
197 self.close_polygon();
198 }
199 }
200
201 pub fn edge(&mut self, x1: i32, y1: i32, x2: i32, y2: i32) {
203 if self.outline.sorted() {
204 self.reset();
205 }
206 self.clipper.move_to(x1, y1);
207 self.clipper.line_to(&mut self.outline, x2, y2);
208 self.status = Status::MoveTo;
209 }
210
211 pub fn edge_d(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
213 if self.outline.sorted() {
214 self.reset();
215 }
216 self.clipper.move_to(poly_coord(x1), poly_coord(y1));
217 self.clipper
218 .line_to(&mut self.outline, poly_coord(x2), poly_coord(y2));
219 self.status = Status::MoveTo;
220 }
221
222 pub fn add_path(&mut self, vs: &mut dyn VertexSource, path_id: u32) {
224 let mut x = 0.0;
225 let mut y = 0.0;
226
227 vs.rewind(path_id);
228 if self.outline.sorted() {
229 self.reset();
230 }
231 loop {
232 let cmd = vs.vertex(&mut x, &mut y);
233 if is_stop(cmd) {
234 break;
235 }
236 self.add_vertex(x, y, cmd);
237 }
238 }
239
240 pub fn outline_cells(&mut self) -> Vec<CellAa> {
252 self.outline.add_curr_cell();
254 self.outline.cells().to_vec()
255 }
256
257 pub fn add_cells_offset(&mut self, cells: &[CellAa], dx: i32, dy: i32) {
272 if self.outline.sorted() {
273 self.reset();
274 }
275 self.outline.add_cells_offset(cells, dx, dy);
276 }
277
278 pub fn min_x(&self) -> i32 {
283 self.outline.min_x()
284 }
285 pub fn min_y(&self) -> i32 {
286 self.outline.min_y()
287 }
288 pub fn max_x(&self) -> i32 {
289 self.outline.max_x()
290 }
291 pub fn max_y(&self) -> i32 {
292 self.outline.max_y()
293 }
294
295 pub fn rewind_scanlines(&mut self) -> bool {
302 if self.auto_close {
303 self.close_polygon();
304 }
305 self.outline.sort_cells();
306 if self.outline.total_cells() == 0 {
307 return false;
308 }
309 self.scan_y = self.outline.min_y();
310 true
311 }
312
313 pub fn navigate_scanline(&mut self, y: i32) -> bool {
315 if self.auto_close {
316 self.close_polygon();
317 }
318 self.outline.sort_cells();
319 if self.outline.total_cells() == 0 || y < self.outline.min_y() || y > self.outline.max_y() {
320 return false;
321 }
322 self.scan_y = y;
323 true
324 }
325
326 pub fn sort(&mut self) {
328 if self.auto_close {
329 self.close_polygon();
330 }
331 self.outline.sort_cells();
332 }
333
334 #[inline]
338 pub fn calculate_alpha(&self, area: i32) -> u32 {
339 let mut cover = area >> (POLY_SUBPIXEL_SHIFT * 2 + 1 - AA_SHIFT);
340
341 if cover < 0 {
342 cover = -cover;
343 }
344 if self.filling_rule == FillingRule::EvenOdd {
345 cover &= AA_MASK2 as i32;
346 if cover > AA_SCALE as i32 {
347 cover = AA_SCALE2 as i32 - cover;
348 }
349 }
350 if cover > AA_MASK as i32 {
351 cover = AA_MASK as i32;
352 }
353 cover as u32
354 }
355
356 pub fn sweep_scanline<SL: Scanline>(&mut self, sl: &mut SL) -> bool {
364 loop {
365 if self.scan_y > self.outline.max_y() {
366 return false;
367 }
368 sl.reset_spans();
369
370 let cell_indices = self.outline.scanline_cells(self.scan_y as u32);
371 let mut num_cells = cell_indices.len();
372 let mut idx = 0;
373 let mut cover: i32 = 0;
374
375 while num_cells > 0 {
376 let cur_idx = cell_indices[idx];
377 let cur_cell = self.outline.cell(cur_idx);
378 let x = cur_cell.x;
379 let mut area = cur_cell.area;
380
381 cover += cur_cell.cover;
382
383 num_cells -= 1;
385 idx += 1;
386 while num_cells > 0 {
387 let next_cell = self.outline.cell(cell_indices[idx]);
388 if next_cell.x != x {
389 break;
390 }
391 area += next_cell.area;
392 cover += next_cell.cover;
393 num_cells -= 1;
394 idx += 1;
395 }
396
397 if area != 0 {
398 let alpha = self.calculate_alpha((cover << (POLY_SUBPIXEL_SHIFT + 1)) - area);
399 if alpha != 0 {
400 sl.add_cell(x, alpha);
401 }
402 let x_next = x + 1;
404
405 if num_cells > 0 {
406 let next_cell = self.outline.cell(cell_indices[idx]);
407 if next_cell.x > x_next {
408 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
409 if alpha != 0 {
410 sl.add_span(x_next, (next_cell.x - x_next) as u32, alpha);
411 }
412 }
413 }
414 } else if num_cells > 0 {
415 let next_cell = self.outline.cell(cell_indices[idx]);
416 if next_cell.x > x {
417 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
418 if alpha != 0 {
419 sl.add_span(x, (next_cell.x - x) as u32, alpha);
420 }
421 }
422 }
423 }
424
425 if sl.num_spans() > 0 {
426 break;
427 }
428 self.scan_y += 1;
429 }
430
431 sl.finalize(self.scan_y);
432 self.scan_y += 1;
433 true
434 }
435
436 pub fn hit_test(&mut self, tx: i32, ty: i32) -> bool {
438 if !self.navigate_scanline(ty) {
439 return false;
440 }
441 let mut sl = ScanlineHitTest::new(tx);
442 self.sweep_scanline_hit_test(&mut sl);
443 sl.hit()
444 }
445
446 fn sweep_scanline_hit_test(&mut self, sl: &mut ScanlineHitTest) -> bool {
448 if self.scan_y > self.outline.max_y() {
449 return false;
450 }
451 sl.reset_spans();
452
453 let cell_indices = self.outline.scanline_cells(self.scan_y as u32);
454 let mut num_cells = cell_indices.len();
455 let mut idx = 0;
456 let mut cover: i32 = 0;
457
458 while num_cells > 0 {
459 let cur_cell = self.outline.cell(cell_indices[idx]);
460 let x = cur_cell.x;
461 let mut area = cur_cell.area;
462
463 cover += cur_cell.cover;
464
465 num_cells -= 1;
466 idx += 1;
467 while num_cells > 0 {
468 let next_cell = self.outline.cell(cell_indices[idx]);
469 if next_cell.x != x {
470 break;
471 }
472 area += next_cell.area;
473 cover += next_cell.cover;
474 num_cells -= 1;
475 idx += 1;
476 }
477
478 if area != 0 {
479 let alpha = self.calculate_alpha((cover << (POLY_SUBPIXEL_SHIFT + 1)) - area);
480 if alpha != 0 {
481 sl.add_cell(x, alpha);
482 }
483 let x_next = x + 1;
484 if num_cells > 0 {
485 let next_cell = self.outline.cell(cell_indices[idx]);
486 if next_cell.x > x_next {
487 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
488 if alpha != 0 {
489 sl.add_span(x_next, (next_cell.x - x_next) as u32, alpha);
490 }
491 }
492 }
493 } else if num_cells > 0 {
494 let next_cell = self.outline.cell(cell_indices[idx]);
495 if next_cell.x > x {
496 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
497 if alpha != 0 {
498 sl.add_span(x, (next_cell.x - x) as u32, alpha);
499 }
500 }
501 }
502 }
503
504 sl.finalize(self.scan_y);
505 self.scan_y += 1;
506 true
507 }
508}
509
510impl Default for RasterizerScanlineAa {
511 fn default() -> Self {
512 Self::new()
513 }
514}
515
516#[cfg(test)]
521mod tests {
522 use super::*;
523 use crate::basics::{PATH_FLAGS_NONE, POLY_SUBPIXEL_SCALE};
524 use crate::ellipse::Ellipse;
525 use crate::path_storage::PathStorage;
526
527 struct TestScanline {
529 spans: Vec<(i32, u32, u32)>, y_val: i32,
531 }
532
533 impl TestScanline {
534 fn new() -> Self {
535 Self {
536 spans: Vec::new(),
537 y_val: 0,
538 }
539 }
540 }
541
542 impl Scanline for TestScanline {
543 fn reset_spans(&mut self) {
544 self.spans.clear();
545 }
546 fn add_cell(&mut self, x: i32, cover: u32) {
547 self.spans.push((x, 1, cover));
548 }
549 fn add_span(&mut self, x: i32, len: u32, cover: u32) {
550 self.spans.push((x, len, cover));
551 }
552 fn finalize(&mut self, y: i32) {
553 self.y_val = y;
554 }
555 fn num_spans(&self) -> u32 {
556 self.spans.len() as u32
557 }
558 fn y(&self) -> i32 {
559 self.y_val
560 }
561 }
562
563 #[test]
564 fn test_new_rasterizer() {
565 let ras = RasterizerScanlineAa::new();
566 assert_eq!(ras.min_x(), i32::MAX);
567 assert_eq!(ras.min_y(), i32::MAX);
568 }
569
570 #[test]
571 fn test_filling_rule() {
572 let mut ras = RasterizerScanlineAa::new();
573 ras.filling_rule(FillingRule::EvenOdd);
574 assert_eq!(ras.filling_rule, FillingRule::EvenOdd);
575 }
576
577 #[test]
578 fn test_calculate_alpha_nonzero() {
579 let ras = RasterizerScanlineAa::new();
580 let full_area = (POLY_SUBPIXEL_SCALE as i32) << (POLY_SUBPIXEL_SHIFT + 1);
582 let alpha = ras.calculate_alpha(full_area);
583 assert_eq!(alpha, 255);
584 }
585
586 #[test]
587 fn test_calculate_alpha_zero_area() {
588 let ras = RasterizerScanlineAa::new();
589 assert_eq!(ras.calculate_alpha(0), 0);
590 }
591
592 #[test]
593 fn test_calculate_alpha_negative_area() {
594 let ras = RasterizerScanlineAa::new();
595 let area = 256 * 256; let alpha_pos = ras.calculate_alpha(area);
598 let alpha_neg = ras.calculate_alpha(-area);
599 assert_eq!(alpha_pos, alpha_neg);
600 }
601
602 #[test]
603 fn test_calculate_alpha_even_odd() {
604 let mut ras = RasterizerScanlineAa::new();
605 ras.filling_rule(FillingRule::EvenOdd);
606 let full_area = (POLY_SUBPIXEL_SCALE as i32) << (POLY_SUBPIXEL_SHIFT + 1);
608 let double_area = full_area * 2;
609 let alpha = ras.calculate_alpha(double_area);
610 assert!(
612 alpha < 10,
613 "Expected near-zero alpha for double even-odd, got {alpha}"
614 );
615 }
616
617 #[test]
618 fn test_triangle_sweep() {
619 let mut ras = RasterizerScanlineAa::new();
620 let s = POLY_SUBPIXEL_SCALE as i32;
621 ras.move_to(10 * s, 10 * s);
623 ras.line_to(20 * s, 10 * s);
624 ras.line_to(15 * s, 20 * s);
625 ras.close_polygon();
626
627 assert!(ras.rewind_scanlines());
628
629 let mut sl = TestScanline::new();
630 let mut scanline_count = 0;
631 while ras.sweep_scanline(&mut sl) {
632 scanline_count += 1;
633 assert!(sl.num_spans() > 0);
634 }
635 assert!(scanline_count > 0, "Should have at least one scanline");
636 assert_eq!(ras.min_y(), 10);
637 assert_eq!(ras.max_y(), 20);
638 }
639
640 #[test]
641 fn test_triangle_hit_test() {
642 let mut ras = RasterizerScanlineAa::new();
643 let s = POLY_SUBPIXEL_SCALE as i32;
644 ras.move_to(10 * s, 10 * s);
646 ras.line_to(30 * s, 10 * s);
647 ras.line_to(20 * s, 30 * s);
648
649 assert!(ras.hit_test(20, 15));
651 assert!(!ras.hit_test(0, 0));
653 assert!(!ras.hit_test(100, 100));
654 }
655
656 #[test]
657 fn test_move_to_d_line_to_d() {
658 let mut ras = RasterizerScanlineAa::new();
659 ras.move_to_d(10.0, 10.0);
660 ras.line_to_d(20.0, 10.0);
661 ras.line_to_d(15.0, 20.0);
662
663 assert!(ras.rewind_scanlines());
664 }
665
666 #[test]
667 fn test_edge_d() {
668 let mut ras = RasterizerScanlineAa::new();
669 ras.edge_d(10.0, 10.0, 20.0, 20.0);
670 ras.edge_d(20.0, 20.0, 10.0, 20.0);
671 ras.edge_d(10.0, 20.0, 10.0, 10.0);
672
673 assert!(ras.rewind_scanlines());
674 }
675
676 #[test]
677 fn test_add_path_with_path_storage() {
678 let mut ras = RasterizerScanlineAa::new();
679 let mut path = PathStorage::new();
680 path.move_to(10.0, 10.0);
681 path.line_to(50.0, 10.0);
682 path.line_to(30.0, 50.0);
683 path.close_polygon(PATH_FLAGS_NONE);
684
685 ras.add_path(&mut path, 0);
686 assert!(ras.rewind_scanlines());
687
688 let mut sl = TestScanline::new();
689 let mut count = 0;
690 while ras.sweep_scanline(&mut sl) {
691 count += 1;
692 }
693 assert!(count > 0);
694 }
695
696 #[test]
697 fn test_add_path_with_ellipse() {
698 let mut ras = RasterizerScanlineAa::new();
699 let mut ellipse = Ellipse::new(50.0, 50.0, 20.0, 20.0, 32, false);
700
701 ras.add_path(&mut ellipse, 0);
702 assert!(ras.rewind_scanlines());
703
704 assert!(ras.hit_test(50, 50));
706 }
707
708 #[test]
709 fn test_empty_rasterizer_no_scanlines() {
710 let mut ras = RasterizerScanlineAa::new();
711 assert!(!ras.rewind_scanlines());
712 }
713
714 #[test]
715 fn test_reset_clears_state() {
716 let mut ras = RasterizerScanlineAa::new();
717 let s = POLY_SUBPIXEL_SCALE as i32;
718 ras.move_to(10 * s, 10 * s);
719 ras.line_to(20 * s, 10 * s);
720 ras.line_to(15 * s, 20 * s);
721 ras.reset();
722 assert!(!ras.rewind_scanlines());
723 }
724
725 #[test]
726 fn test_clip_box() {
727 let mut ras = RasterizerScanlineAa::new();
728 ras.clip_box(0.0, 0.0, 50.0, 50.0);
729
730 ras.move_to_d(10.0, 10.0);
732 ras.line_to_d(100.0, 10.0);
733 ras.line_to_d(50.0, 100.0);
734
735 assert!(ras.rewind_scanlines());
736 assert!(ras.max_y() <= 50);
738 }
739
740 #[test]
741 fn test_navigate_scanline() {
742 let mut ras = RasterizerScanlineAa::new();
743 let s = POLY_SUBPIXEL_SCALE as i32;
744 ras.move_to(10 * s, 10 * s);
745 ras.line_to(20 * s, 10 * s);
746 ras.line_to(15 * s, 20 * s);
747
748 assert!(ras.navigate_scanline(15));
750 let mut sl = TestScanline::new();
751 assert!(ras.sweep_scanline(&mut sl));
752 assert_eq!(sl.y(), 15);
753
754 assert!(!ras.navigate_scanline(0));
756 assert!(!ras.navigate_scanline(100));
757 }
758
759 #[test]
760 fn test_auto_close_on_move_to() {
761 let mut ras = RasterizerScanlineAa::new();
762 ras.move_to_d(10.0, 10.0);
763 ras.line_to_d(20.0, 10.0);
764 ras.line_to_d(15.0, 20.0);
765 assert!(ras.rewind_scanlines());
767 }
768
769 fn collect_scanlines(ras: &mut RasterizerScanlineAa) -> Vec<(i32, i32, u32, u32)> {
771 let mut sl = TestScanline::new();
772 let mut result = Vec::new();
773 while ras.sweep_scanline(&mut sl) {
774 for &(x, len, cover) in &sl.spans {
775 result.push((sl.y_val, x, len, cover));
776 }
777 }
778 result
779 }
780
781 #[test]
788 fn test_outline_cells_round_trip() {
789 let mut path = PathStorage::new();
791 path.move_to(10.0, 10.0);
792 path.line_to(30.0, 10.0);
793 path.line_to(20.0, 25.0);
794 path.close_polygon(PATH_FLAGS_NONE);
795
796 let dx = 15i32;
797 let dy = 20i32;
798
799 let mut path_shifted = path.clone();
801 path_shifted.translate_all_paths(dx as f64, dy as f64);
802 let mut ras_direct = RasterizerScanlineAa::new();
803 ras_direct.add_path(&mut path_shifted, 0);
804 assert!(ras_direct.rewind_scanlines());
805 let direct = collect_scanlines(&mut ras_direct);
806
807 let mut ras_source = RasterizerScanlineAa::new();
809 ras_source.add_path(&mut path, 0);
810 let cached_cells = ras_source.outline_cells();
811 assert!(!cached_cells.is_empty(), "outline_cells() should return non-empty cells");
812
813 let mut ras_replay = RasterizerScanlineAa::new();
814 ras_replay.add_cells_offset(&cached_cells, dx, dy);
815 assert!(ras_replay.rewind_scanlines());
816 let replayed = collect_scanlines(&mut ras_replay);
817
818 assert_eq!(
819 direct, replayed,
820 "cell cache replay must produce identical scanlines to direct rasterization"
821 );
822 }
823
824 #[test]
827 fn test_outline_cells_multiple_offsets() {
828 let mut path = PathStorage::new();
829 path.move_to(0.0, 0.0);
830 path.line_to(8.0, 0.0);
831 path.line_to(8.0, 12.0);
832 path.line_to(0.0, 12.0);
833 path.close_polygon(PATH_FLAGS_NONE);
834
835 let mut ras_source = RasterizerScanlineAa::new();
837 ras_source.add_path(&mut path, 0);
838 let cells = ras_source.outline_cells();
839
840 for (dx, dy) in [(5i32, 10i32), (20i32, 10i32)] {
842 let mut path_shifted = path.clone();
843 path_shifted.translate_all_paths(dx as f64, dy as f64);
844 let mut ras_direct = RasterizerScanlineAa::new();
845 ras_direct.add_path(&mut path_shifted, 0);
846 assert!(ras_direct.rewind_scanlines());
847 let direct = collect_scanlines(&mut ras_direct);
848
849 let mut ras_replay = RasterizerScanlineAa::new();
850 ras_replay.add_cells_offset(&cells, dx, dy);
851 assert!(ras_replay.rewind_scanlines());
852 let replayed = collect_scanlines(&mut ras_replay);
853
854 assert_eq!(direct, replayed, "mismatch at offset ({dx}, {dy})");
855 }
856 }
857}