1use crate::basics::{
12 is_close, is_move_to, is_stop, is_vertex, FillingRule, VertexSource, POLY_SUBPIXEL_SHIFT,
13};
14use crate::rasterizer_cells_aa::{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 min_x(&self) -> i32 {
245 self.outline.min_x()
246 }
247 pub fn min_y(&self) -> i32 {
248 self.outline.min_y()
249 }
250 pub fn max_x(&self) -> i32 {
251 self.outline.max_x()
252 }
253 pub fn max_y(&self) -> i32 {
254 self.outline.max_y()
255 }
256
257 pub fn rewind_scanlines(&mut self) -> bool {
264 if self.auto_close {
265 self.close_polygon();
266 }
267 self.outline.sort_cells();
268 if self.outline.total_cells() == 0 {
269 return false;
270 }
271 self.scan_y = self.outline.min_y();
272 true
273 }
274
275 pub fn navigate_scanline(&mut self, y: i32) -> bool {
277 if self.auto_close {
278 self.close_polygon();
279 }
280 self.outline.sort_cells();
281 if self.outline.total_cells() == 0 || y < self.outline.min_y() || y > self.outline.max_y() {
282 return false;
283 }
284 self.scan_y = y;
285 true
286 }
287
288 pub fn sort(&mut self) {
290 if self.auto_close {
291 self.close_polygon();
292 }
293 self.outline.sort_cells();
294 }
295
296 #[inline]
300 pub fn calculate_alpha(&self, area: i32) -> u32 {
301 let mut cover = area >> (POLY_SUBPIXEL_SHIFT * 2 + 1 - AA_SHIFT);
302
303 if cover < 0 {
304 cover = -cover;
305 }
306 if self.filling_rule == FillingRule::EvenOdd {
307 cover &= AA_MASK2 as i32;
308 if cover > AA_SCALE as i32 {
309 cover = AA_SCALE2 as i32 - cover;
310 }
311 }
312 if cover > AA_MASK as i32 {
313 cover = AA_MASK as i32;
314 }
315 cover as u32
316 }
317
318 pub fn sweep_scanline<SL: Scanline>(&mut self, sl: &mut SL) -> bool {
326 loop {
327 if self.scan_y > self.outline.max_y() {
328 return false;
329 }
330 sl.reset_spans();
331
332 let cell_indices = self.outline.scanline_cells(self.scan_y as u32);
333 let mut num_cells = cell_indices.len();
334 let mut idx = 0;
335 let mut cover: i32 = 0;
336
337 while num_cells > 0 {
338 let cur_idx = cell_indices[idx];
339 let cur_cell = self.outline.cell(cur_idx);
340 let x = cur_cell.x;
341 let mut area = cur_cell.area;
342
343 cover += cur_cell.cover;
344
345 num_cells -= 1;
347 idx += 1;
348 while num_cells > 0 {
349 let next_cell = self.outline.cell(cell_indices[idx]);
350 if next_cell.x != x {
351 break;
352 }
353 area += next_cell.area;
354 cover += next_cell.cover;
355 num_cells -= 1;
356 idx += 1;
357 }
358
359 if area != 0 {
360 let alpha = self.calculate_alpha((cover << (POLY_SUBPIXEL_SHIFT + 1)) - area);
361 if alpha != 0 {
362 sl.add_cell(x, alpha);
363 }
364 let x_next = x + 1;
366
367 if num_cells > 0 {
368 let next_cell = self.outline.cell(cell_indices[idx]);
369 if next_cell.x > x_next {
370 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
371 if alpha != 0 {
372 sl.add_span(x_next, (next_cell.x - x_next) as u32, alpha);
373 }
374 }
375 }
376 } else if num_cells > 0 {
377 let next_cell = self.outline.cell(cell_indices[idx]);
378 if next_cell.x > x {
379 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
380 if alpha != 0 {
381 sl.add_span(x, (next_cell.x - x) as u32, alpha);
382 }
383 }
384 }
385 }
386
387 if sl.num_spans() > 0 {
388 break;
389 }
390 self.scan_y += 1;
391 }
392
393 sl.finalize(self.scan_y);
394 self.scan_y += 1;
395 true
396 }
397
398 pub fn hit_test(&mut self, tx: i32, ty: i32) -> bool {
400 if !self.navigate_scanline(ty) {
401 return false;
402 }
403 let mut sl = ScanlineHitTest::new(tx);
404 self.sweep_scanline_hit_test(&mut sl);
405 sl.hit()
406 }
407
408 fn sweep_scanline_hit_test(&mut self, sl: &mut ScanlineHitTest) -> bool {
410 if self.scan_y > self.outline.max_y() {
411 return false;
412 }
413 sl.reset_spans();
414
415 let cell_indices = self.outline.scanline_cells(self.scan_y as u32);
416 let mut num_cells = cell_indices.len();
417 let mut idx = 0;
418 let mut cover: i32 = 0;
419
420 while num_cells > 0 {
421 let cur_cell = self.outline.cell(cell_indices[idx]);
422 let x = cur_cell.x;
423 let mut area = cur_cell.area;
424
425 cover += cur_cell.cover;
426
427 num_cells -= 1;
428 idx += 1;
429 while num_cells > 0 {
430 let next_cell = self.outline.cell(cell_indices[idx]);
431 if next_cell.x != x {
432 break;
433 }
434 area += next_cell.area;
435 cover += next_cell.cover;
436 num_cells -= 1;
437 idx += 1;
438 }
439
440 if area != 0 {
441 let alpha = self.calculate_alpha((cover << (POLY_SUBPIXEL_SHIFT + 1)) - area);
442 if alpha != 0 {
443 sl.add_cell(x, alpha);
444 }
445 let x_next = x + 1;
446 if num_cells > 0 {
447 let next_cell = self.outline.cell(cell_indices[idx]);
448 if next_cell.x > x_next {
449 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
450 if alpha != 0 {
451 sl.add_span(x_next, (next_cell.x - x_next) as u32, alpha);
452 }
453 }
454 }
455 } else if num_cells > 0 {
456 let next_cell = self.outline.cell(cell_indices[idx]);
457 if next_cell.x > x {
458 let alpha = self.calculate_alpha(cover << (POLY_SUBPIXEL_SHIFT + 1));
459 if alpha != 0 {
460 sl.add_span(x, (next_cell.x - x) as u32, alpha);
461 }
462 }
463 }
464 }
465
466 sl.finalize(self.scan_y);
467 self.scan_y += 1;
468 true
469 }
470}
471
472impl Default for RasterizerScanlineAa {
473 fn default() -> Self {
474 Self::new()
475 }
476}
477
478#[cfg(test)]
483mod tests {
484 use super::*;
485 use crate::basics::{PATH_FLAGS_NONE, POLY_SUBPIXEL_SCALE};
486 use crate::ellipse::Ellipse;
487 use crate::path_storage::PathStorage;
488
489 struct TestScanline {
491 spans: Vec<(i32, u32, u32)>, y_val: i32,
493 }
494
495 impl TestScanline {
496 fn new() -> Self {
497 Self {
498 spans: Vec::new(),
499 y_val: 0,
500 }
501 }
502 }
503
504 impl Scanline for TestScanline {
505 fn reset_spans(&mut self) {
506 self.spans.clear();
507 }
508 fn add_cell(&mut self, x: i32, cover: u32) {
509 self.spans.push((x, 1, cover));
510 }
511 fn add_span(&mut self, x: i32, len: u32, cover: u32) {
512 self.spans.push((x, len, cover));
513 }
514 fn finalize(&mut self, y: i32) {
515 self.y_val = y;
516 }
517 fn num_spans(&self) -> u32 {
518 self.spans.len() as u32
519 }
520 fn y(&self) -> i32 {
521 self.y_val
522 }
523 }
524
525 #[test]
526 fn test_new_rasterizer() {
527 let ras = RasterizerScanlineAa::new();
528 assert_eq!(ras.min_x(), i32::MAX);
529 assert_eq!(ras.min_y(), i32::MAX);
530 }
531
532 #[test]
533 fn test_filling_rule() {
534 let mut ras = RasterizerScanlineAa::new();
535 ras.filling_rule(FillingRule::EvenOdd);
536 assert_eq!(ras.filling_rule, FillingRule::EvenOdd);
537 }
538
539 #[test]
540 fn test_calculate_alpha_nonzero() {
541 let ras = RasterizerScanlineAa::new();
542 let full_area = (POLY_SUBPIXEL_SCALE as i32) << (POLY_SUBPIXEL_SHIFT + 1);
544 let alpha = ras.calculate_alpha(full_area);
545 assert_eq!(alpha, 255);
546 }
547
548 #[test]
549 fn test_calculate_alpha_zero_area() {
550 let ras = RasterizerScanlineAa::new();
551 assert_eq!(ras.calculate_alpha(0), 0);
552 }
553
554 #[test]
555 fn test_calculate_alpha_negative_area() {
556 let ras = RasterizerScanlineAa::new();
557 let area = 256 * 256; let alpha_pos = ras.calculate_alpha(area);
560 let alpha_neg = ras.calculate_alpha(-area);
561 assert_eq!(alpha_pos, alpha_neg);
562 }
563
564 #[test]
565 fn test_calculate_alpha_even_odd() {
566 let mut ras = RasterizerScanlineAa::new();
567 ras.filling_rule(FillingRule::EvenOdd);
568 let full_area = (POLY_SUBPIXEL_SCALE as i32) << (POLY_SUBPIXEL_SHIFT + 1);
570 let double_area = full_area * 2;
571 let alpha = ras.calculate_alpha(double_area);
572 assert!(
574 alpha < 10,
575 "Expected near-zero alpha for double even-odd, got {alpha}"
576 );
577 }
578
579 #[test]
580 fn test_triangle_sweep() {
581 let mut ras = RasterizerScanlineAa::new();
582 let s = POLY_SUBPIXEL_SCALE as i32;
583 ras.move_to(10 * s, 10 * s);
585 ras.line_to(20 * s, 10 * s);
586 ras.line_to(15 * s, 20 * s);
587 ras.close_polygon();
588
589 assert!(ras.rewind_scanlines());
590
591 let mut sl = TestScanline::new();
592 let mut scanline_count = 0;
593 while ras.sweep_scanline(&mut sl) {
594 scanline_count += 1;
595 assert!(sl.num_spans() > 0);
596 }
597 assert!(scanline_count > 0, "Should have at least one scanline");
598 assert_eq!(ras.min_y(), 10);
599 assert_eq!(ras.max_y(), 20);
600 }
601
602 #[test]
603 fn test_triangle_hit_test() {
604 let mut ras = RasterizerScanlineAa::new();
605 let s = POLY_SUBPIXEL_SCALE as i32;
606 ras.move_to(10 * s, 10 * s);
608 ras.line_to(30 * s, 10 * s);
609 ras.line_to(20 * s, 30 * s);
610
611 assert!(ras.hit_test(20, 15));
613 assert!(!ras.hit_test(0, 0));
615 assert!(!ras.hit_test(100, 100));
616 }
617
618 #[test]
619 fn test_move_to_d_line_to_d() {
620 let mut ras = RasterizerScanlineAa::new();
621 ras.move_to_d(10.0, 10.0);
622 ras.line_to_d(20.0, 10.0);
623 ras.line_to_d(15.0, 20.0);
624
625 assert!(ras.rewind_scanlines());
626 }
627
628 #[test]
629 fn test_edge_d() {
630 let mut ras = RasterizerScanlineAa::new();
631 ras.edge_d(10.0, 10.0, 20.0, 20.0);
632 ras.edge_d(20.0, 20.0, 10.0, 20.0);
633 ras.edge_d(10.0, 20.0, 10.0, 10.0);
634
635 assert!(ras.rewind_scanlines());
636 }
637
638 #[test]
639 fn test_add_path_with_path_storage() {
640 let mut ras = RasterizerScanlineAa::new();
641 let mut path = PathStorage::new();
642 path.move_to(10.0, 10.0);
643 path.line_to(50.0, 10.0);
644 path.line_to(30.0, 50.0);
645 path.close_polygon(PATH_FLAGS_NONE);
646
647 ras.add_path(&mut path, 0);
648 assert!(ras.rewind_scanlines());
649
650 let mut sl = TestScanline::new();
651 let mut count = 0;
652 while ras.sweep_scanline(&mut sl) {
653 count += 1;
654 }
655 assert!(count > 0);
656 }
657
658 #[test]
659 fn test_add_path_with_ellipse() {
660 let mut ras = RasterizerScanlineAa::new();
661 let mut ellipse = Ellipse::new(50.0, 50.0, 20.0, 20.0, 32, false);
662
663 ras.add_path(&mut ellipse, 0);
664 assert!(ras.rewind_scanlines());
665
666 assert!(ras.hit_test(50, 50));
668 }
669
670 #[test]
671 fn test_empty_rasterizer_no_scanlines() {
672 let mut ras = RasterizerScanlineAa::new();
673 assert!(!ras.rewind_scanlines());
674 }
675
676 #[test]
677 fn test_reset_clears_state() {
678 let mut ras = RasterizerScanlineAa::new();
679 let s = POLY_SUBPIXEL_SCALE as i32;
680 ras.move_to(10 * s, 10 * s);
681 ras.line_to(20 * s, 10 * s);
682 ras.line_to(15 * s, 20 * s);
683 ras.reset();
684 assert!(!ras.rewind_scanlines());
685 }
686
687 #[test]
688 fn test_clip_box() {
689 let mut ras = RasterizerScanlineAa::new();
690 ras.clip_box(0.0, 0.0, 50.0, 50.0);
691
692 ras.move_to_d(10.0, 10.0);
694 ras.line_to_d(100.0, 10.0);
695 ras.line_to_d(50.0, 100.0);
696
697 assert!(ras.rewind_scanlines());
698 assert!(ras.max_y() <= 50);
700 }
701
702 #[test]
703 fn test_navigate_scanline() {
704 let mut ras = RasterizerScanlineAa::new();
705 let s = POLY_SUBPIXEL_SCALE as i32;
706 ras.move_to(10 * s, 10 * s);
707 ras.line_to(20 * s, 10 * s);
708 ras.line_to(15 * s, 20 * s);
709
710 assert!(ras.navigate_scanline(15));
712 let mut sl = TestScanline::new();
713 assert!(ras.sweep_scanline(&mut sl));
714 assert_eq!(sl.y(), 15);
715
716 assert!(!ras.navigate_scanline(0));
718 assert!(!ras.navigate_scanline(100));
719 }
720
721 #[test]
722 fn test_auto_close_on_move_to() {
723 let mut ras = RasterizerScanlineAa::new();
724 ras.move_to_d(10.0, 10.0);
725 ras.line_to_d(20.0, 10.0);
726 ras.line_to_d(15.0, 20.0);
727 assert!(ras.rewind_scanlines());
729 }
730}