1use core::convert::TryFrom;
8use core::num::NonZeroU16;
9
10use crate::{IntRect, LengthU32, LineCap, Path, Point, Rect};
11
12use crate::alpha_runs::{AlphaRun, AlphaRuns};
13use crate::blitter::Blitter;
14use crate::color::AlphaU8;
15use crate::fixed_point::{fdot16, fdot6, fdot8, FDot16, FDot6, FDot8};
16use crate::geom::{IntRectExt, ScreenIntRect};
17use crate::line_clipper;
18use crate::math::LENGTH_U32_ONE;
19
20#[derive(Copy, Clone, Debug)]
21struct FixedRect {
22 left: FDot16,
23 top: FDot16,
24 right: FDot16,
25 bottom: FDot16,
26}
27
28impl FixedRect {
29 fn from_rect(src: &Rect) -> Self {
30 FixedRect {
31 left: fdot16::from_f32(src.left()),
32 top: fdot16::from_f32(src.top()),
33 right: fdot16::from_f32(src.right()),
34 bottom: fdot16::from_f32(src.bottom()),
35 }
36 }
37}
38
39fn alpha_mul(value: AlphaU8, alpha256: i32) -> u8 {
42 let a = (i32::from(value) * alpha256) >> 8;
43 debug_assert!(a >= 0 && a <= 255);
44 a as u8
45}
46
47pub fn fill_rect(rect: &Rect, clip: &ScreenIntRect, blitter: &mut dyn Blitter) {
48 let rect = match rect.intersect(&clip.to_rect()) {
49 Some(v) => v,
50 None => return, };
52
53 let fr = FixedRect::from_rect(&rect);
54 fill_fixed_rect(&fr, blitter);
55}
56
57fn fill_fixed_rect(rect: &FixedRect, blitter: &mut dyn Blitter) {
58 fill_dot8(
59 fdot8::from_fdot16(rect.left),
60 fdot8::from_fdot16(rect.top),
61 fdot8::from_fdot16(rect.right),
62 fdot8::from_fdot16(rect.bottom),
63 true,
64 blitter,
65 )
66}
67
68fn fill_dot8(l: FDot8, t: FDot8, r: FDot8, b: FDot8, fill_inner: bool, blitter: &mut dyn Blitter) {
69 fn to_alpha(a: i32) -> u8 {
70 debug_assert!(a >= 0 && a <= 255);
71 a as u8
72 }
73
74 if l >= r || t >= b {
76 return;
77 }
78
79 let mut top = t >> 8;
80 if top == ((b - 1) >> 8) {
81 do_scanline(l, top, r, to_alpha(b - t - 1), blitter);
83 return;
84 }
85
86 if t & 0xFF != 0 {
87 do_scanline(l, top, r, to_alpha(256 - (t & 0xFF)), blitter);
88 top += 1;
89 }
90
91 let bottom = b >> 8;
92 let height = bottom - top;
93 if let Some(height) = u32::try_from(height).ok().and_then(LengthU32::new) {
94 let mut left = l >> 8;
95 if left == ((r - 1) >> 8) {
96 if let (Ok(left), Ok(top)) = (u32::try_from(left), u32::try_from(top)) {
98 blitter.blit_v(left, top, height, to_alpha(r - l - 1));
99 } else {
100 debug_assert!(false);
101 }
102 } else {
103 if l & 0xFF != 0 {
104 if let (Ok(left), Ok(top)) = (u32::try_from(left), u32::try_from(top)) {
105 blitter.blit_v(left, top, height, to_alpha(256 - (l & 0xFF)));
106 } else {
107 debug_assert!(false);
108 }
109
110 left += 1;
111 }
112
113 let right = r >> 8;
114 let width = right - left;
115 if fill_inner {
116 if let Some(width) = u32::try_from(width).ok().and_then(LengthU32::new) {
117 if let (Ok(left), Ok(top)) = (u32::try_from(left), u32::try_from(top)) {
118 let rect = ScreenIntRect::from_xywh_safe(left, top, width, height);
119 blitter.blit_rect(&rect);
120 } else {
121 debug_assert!(false);
122 }
123 }
124 }
125
126 if r & 0xFF != 0 {
127 if let (Ok(right), Ok(top)) = (u32::try_from(right), u32::try_from(top)) {
128 blitter.blit_v(right, top, height, to_alpha(r & 0xFF));
129 } else {
130 debug_assert!(false);
131 }
132 }
133 }
134 }
135
136 if b & 0xFF != 0 {
137 do_scanline(l, bottom, r, to_alpha(b & 0xFF), blitter);
138 }
139}
140
141fn do_scanline(l: FDot8, top: i32, r: FDot8, alpha: AlphaU8, blitter: &mut dyn Blitter) {
142 debug_assert!(l < r);
143
144 let one_len = LENGTH_U32_ONE;
145 let top = match u32::try_from(top) {
146 Ok(n) => n,
147 _ => return,
148 };
149
150 if (l >> 8) == ((r - 1) >> 8) {
151 if let Ok(left) = u32::try_from(l >> 8) {
153 blitter.blit_v(left, top, one_len, alpha_mul(alpha, r - l));
154 }
155
156 return;
157 }
158
159 let mut left = l >> 8;
160
161 if l & 0xFF != 0 {
162 if let Ok(left) = u32::try_from(l >> 8) {
163 blitter.blit_v(left, top, one_len, alpha_mul(alpha, 256 - (l & 0xFF)));
164 }
165
166 left += 1;
167 }
168
169 let right = r >> 8;
170 let width = right - left;
171 if let Some(width) = u32::try_from(width).ok().and_then(LengthU32::new) {
172 if let Ok(left) = u32::try_from(left) {
173 call_hline_blitter(left, Some(top), width, alpha, blitter);
174 }
175 }
176
177 if r & 0xFF != 0 {
178 if let Ok(right) = u32::try_from(right) {
179 blitter.blit_v(right, top, one_len, alpha_mul(alpha, r & 0xFF));
180 }
181 }
182}
183
184fn call_hline_blitter(
185 mut x: u32,
186 y: Option<u32>,
187 count: LengthU32,
188 alpha: AlphaU8,
189 blitter: &mut dyn Blitter,
190) {
191 const HLINE_STACK_BUFFER: usize = 100;
192
193 let mut runs = [None; HLINE_STACK_BUFFER + 1];
194 let mut aa = [0u8; HLINE_STACK_BUFFER];
195
196 let mut count = count.get();
197 loop {
198 aa[0] = alpha;
204
205 let mut n = count;
206 if n > HLINE_STACK_BUFFER as u32 {
207 n = HLINE_STACK_BUFFER as u32;
208 }
209
210 debug_assert!(n <= u16::MAX as u32);
211 runs[0] = NonZeroU16::new(n as u16);
212 runs[n as usize] = None;
213 if let Some(y) = y {
214 blitter.blit_anti_h(x, y, &mut aa, &mut runs);
215 }
216 x += n;
217
218 if n >= count || count == 0 {
219 break;
220 }
221
222 count -= n;
223 }
224}
225
226pub fn stroke_path(
227 path: &Path,
228 line_cap: LineCap,
229 clip: &ScreenIntRect,
230 blitter: &mut dyn Blitter,
231) {
232 super::hairline::stroke_path_impl(path, line_cap, clip, anti_hair_line_rgn, blitter);
233}
234
235fn anti_hair_line_rgn(points: &[Point], clip: Option<&ScreenIntRect>, blitter: &mut dyn Blitter) {
236 let max = 32767.0;
237 let fixed_bounds = Rect::from_ltrb(-max, -max, max, max).unwrap();
238
239 let clip_bounds = if let Some(clip) = clip {
240 clip.to_rect().outset(1.0, 1.0)
249 } else {
250 None
251 };
252
253 for i in 0..points.len() - 1 {
254 let mut pts = [Point::zero(); 2];
255
256 if !line_clipper::intersect(&[points[i], points[i + 1]], &fixed_bounds, &mut pts) {
258 continue;
259 }
260
261 if let Some(clip_bounds) = clip_bounds {
262 let tmp = pts;
263 if !line_clipper::intersect(&tmp, &clip_bounds, &mut pts) {
264 continue;
265 }
266 }
267
268 let x0 = fdot6::from_f32(pts[0].x);
269 let y0 = fdot6::from_f32(pts[0].y);
270 let x1 = fdot6::from_f32(pts[1].x);
271 let y1 = fdot6::from_f32(pts[1].y);
272
273 if let Some(clip) = clip {
274 let left = x0.min(x1);
275 let top = y0.min(y1);
276 let right = x0.max(x1);
277 let bottom = y0.max(y1);
278
279 let ir = IntRect::from_ltrb(
280 fdot6::floor(left) - 1,
281 fdot6::floor(top) - 1,
282 fdot6::ceil(right) + 1,
283 fdot6::ceil(bottom) + 1,
284 );
285 let ir = match ir {
286 Some(v) => v,
287 None => return,
288 };
289
290 if clip.to_int_rect().intersect(&ir).is_none() {
291 continue;
292 }
293
294 if !clip.to_int_rect().contains(&ir) {
295 let subclip = ir
296 .intersect(&clip.to_int_rect())
297 .and_then(|r| r.to_screen_int_rect());
298
299 if let Some(subclip) = subclip {
300 do_anti_hairline(x0, y0, x1, y1, Some(subclip), blitter);
301 }
302
303 continue;
304 }
305
306 }
308
309 do_anti_hairline(x0, y0, x1, y1, None, blitter);
310 }
311}
312
313#[derive(Copy, Clone, Debug)]
314enum BlitterKind {
315 HLine,
316 Horish,
317 VLine,
318 Vertish,
319}
320
321fn do_anti_hairline(
322 mut x0: FDot6,
323 mut y0: FDot6,
324 mut x1: FDot6,
325 mut y1: FDot6,
326 mut clip_opt: Option<ScreenIntRect>,
327 blitter: &mut dyn Blitter,
328) {
329 if any_bad_ints(x0, y0, x1, y1) != 0 {
333 return;
334 }
335
336 debug_assert!(fdot6::can_convert_to_fdot16(x0));
338 debug_assert!(fdot6::can_convert_to_fdot16(y0));
339 debug_assert!(fdot6::can_convert_to_fdot16(x1));
340 debug_assert!(fdot6::can_convert_to_fdot16(y1));
341
342 if (x1 - x0).abs() > fdot6::from_i32(511) || (y1 - y0).abs() > fdot6::from_i32(511) {
343 let hx = (x0 >> 1) + (x1 >> 1);
349 let hy = (y0 >> 1) + (y1 >> 1);
350 do_anti_hairline(x0, y0, hx, hy, clip_opt, blitter);
351 do_anti_hairline(hx, hy, x1, y1, clip_opt, blitter);
352 return; }
354
355 let mut scale_start;
356 let mut scale_stop;
357 let mut istart;
358 let mut istop;
359 let mut fstart;
360 let slope;
361 let blitter_kind;
362
363 if (x1 - x0).abs() > (y1 - y0).abs() {
364 if x0 > x1 {
367 core::mem::swap(&mut x0, &mut x1);
369 core::mem::swap(&mut y0, &mut y1);
370 }
371
372 istart = fdot6::floor(x0);
373 istop = fdot6::ceil(x1);
374 fstart = fdot6::to_fdot16(y0);
375 if y0 == y1 {
376 slope = 0;
378 blitter_kind = Some(BlitterKind::HLine);
379 } else {
380 slope = fdot16::fast_div(y1 - y0, x1 - x0);
381 debug_assert!(slope >= -fdot16::ONE && slope <= fdot16::ONE);
382 fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
383 blitter_kind = Some(BlitterKind::Horish);
384 }
385
386 debug_assert!(istop > istart);
387 if istop - istart == 1 {
388 scale_start = x1 - x0;
390 debug_assert!(scale_start >= 0 && scale_start <= 64);
391 scale_stop = 0;
392 } else {
393 scale_start = 64 - (x0 & 63);
394 scale_stop = x1 & 63;
395 }
396
397 if let Some(clip) = clip_opt {
398 let clip = clip.to_int_rect();
399
400 if istart >= clip.right() || istop <= clip.left() {
401 return; }
403
404 if istart < clip.left() {
405 fstart += slope * (clip.left() - istart);
406 istart = clip.left();
407 scale_start = 64;
408 if istop - istart == 1 {
409 scale_start = contribution_64(x1);
411 scale_stop = 0;
412 }
413 }
414
415 if istop > clip.right() {
416 istop = clip.right();
417 scale_stop = 0; }
419
420 debug_assert!(istart <= istop);
421 if istart == istop {
422 return; }
424
425 let (mut top, mut bottom) = if slope >= 0 {
427 let top = fdot16::floor_to_i32(fstart - fdot16::HALF);
429 let bottom =
430 fdot16::ceil_to_i32(fstart + (istop - istart - 1) * slope + fdot16::HALF);
431 (top, bottom)
432 } else {
433 let bottom = fdot16::ceil_to_i32(fstart + fdot16::HALF);
435 let top =
436 fdot16::floor_to_i32(fstart + (istop - istart - 1) * slope - fdot16::HALF);
437 (top, bottom)
438 };
439
440 top -= 1;
441 bottom += 1;
442
443 if top >= clip.bottom() || bottom <= clip.top() {
444 return; }
446
447 if clip.top() <= top && clip.bottom() >= bottom {
448 clip_opt = None;
449 }
450 }
451 } else {
452 if y0 > y1 {
455 core::mem::swap(&mut x0, &mut x1);
457 core::mem::swap(&mut y0, &mut y1);
458 }
459
460 istart = fdot6::floor(y0);
461 istop = fdot6::ceil(y1);
462 fstart = fdot6::to_fdot16(x0);
463 if x0 == x1 {
464 if y0 == y1 {
465 return; }
468
469 slope = 0;
470 blitter_kind = Some(BlitterKind::VLine);
471 } else {
472 slope = fdot16::fast_div(x1 - x0, y1 - y0);
473 debug_assert!(slope <= fdot16::ONE && slope >= -fdot16::ONE);
474 fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
475 blitter_kind = Some(BlitterKind::Vertish);
476 }
477
478 debug_assert!(istop > istart);
479 if istop - istart == 1 {
480 scale_start = y1 - y0;
482 debug_assert!(scale_start >= 0 && scale_start <= 64);
483 scale_stop = 0;
484 } else {
485 scale_start = 64 - (y0 & 63);
486 scale_stop = y1 & 63;
487 }
488
489 if let Some(clip) = clip_opt {
490 let clip = clip.to_int_rect();
491
492 if istart >= clip.bottom() || istop <= clip.top() {
493 return; }
495
496 if istart < clip.top() {
497 fstart += slope * (clip.top() - istart);
498 istart = clip.top();
499 scale_start = 64;
500 if istop - istart == 1 {
501 scale_start = contribution_64(y1);
503 scale_stop = 0;
504 }
505 }
506 if istop > clip.bottom() {
507 istop = clip.bottom();
508 scale_stop = 0; }
510
511 debug_assert!(istart <= istop);
512 if istart == istop {
513 return; }
515
516 let (mut left, mut right) = if slope >= 0 {
518 let left = fdot16::floor_to_i32(fstart - fdot16::HALF);
520 let right =
521 fdot16::ceil_to_i32(fstart + (istop - istart - 1) * slope + fdot16::HALF);
522 (left, right)
523 } else {
524 let right = fdot16::ceil_to_i32(fstart + fdot16::HALF);
526 let left =
527 fdot16::floor_to_i32(fstart + (istop - istart - 1) * slope - fdot16::HALF);
528 (left, right)
529 };
530
531 left -= 1;
532 right += 1;
533
534 if left >= clip.right() || right <= clip.left() {
535 return; }
537
538 if clip.left() <= left && clip.right() >= right {
539 clip_opt = None;
540 }
541 }
542 }
543
544 let mut clip_blitter;
545 let blitter = if let Some(clip) = clip_opt {
546 clip_blitter = RectClipBlitter { blitter, clip };
547 &mut clip_blitter
548 } else {
549 blitter
550 };
551
552 let blitter_kind = match blitter_kind {
553 Some(v) => v,
554 None => return,
555 };
556
557 let mut hline_blitter;
559 let mut horish_blitter;
560 let mut vline_blitter;
561 let mut vertish_blitter;
562 let hair_blitter: &mut dyn AntiHairBlitter = match blitter_kind {
563 BlitterKind::HLine => {
564 hline_blitter = HLineAntiHairBlitter(blitter);
565 &mut hline_blitter
566 }
567 BlitterKind::Horish => {
568 horish_blitter = HorishAntiHairBlitter(blitter);
569 &mut horish_blitter
570 }
571 BlitterKind::VLine => {
572 vline_blitter = VLineAntiHairBlitter(blitter);
573 &mut vline_blitter
574 }
575 BlitterKind::Vertish => {
576 vertish_blitter = VertishAntiHairBlitter(blitter);
577 &mut vertish_blitter
578 }
579 };
580
581 debug_assert!(istart >= 0);
582 let mut istart = istart as u32;
583
584 debug_assert!(istop >= 0);
585 let istop = istop as u32;
586
587 fstart = hair_blitter.draw_cap(istart, fstart, slope, scale_start);
588 istart += 1;
589 let full_spans = istop - istart - (scale_stop > 0) as u32;
590 if full_spans > 0 {
591 fstart = hair_blitter.draw_line(istart, istart + full_spans, fstart, slope);
592 }
593
594 if scale_stop > 0 {
595 hair_blitter.draw_cap(istop - 1, fstart, slope, scale_stop);
596 }
597}
598
599fn bad_int(x: i32) -> i32 {
601 x & -x
602}
603
604fn any_bad_ints(a: i32, b: i32, c: i32, d: i32) -> i32 {
605 (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> ((core::mem::size_of::<i32>() << 3) - 1)
606}
607
608fn contribution_64(ordinate: FDot6) -> i32 {
613 let result = ((ordinate - 1) & 63) + 1;
614 debug_assert!(result > 0 && result <= 64);
615 result
616}
617
618trait AntiHairBlitter {
619 fn draw_cap(&mut self, x: u32, fy: FDot16, slope: FDot16, mod64: i32) -> FDot16;
620 fn draw_line(&mut self, x: u32, stopx: u32, fy: FDot16, slope: FDot16) -> FDot16;
621}
622
623struct HLineAntiHairBlitter<'a>(&'a mut dyn Blitter);
624
625impl AntiHairBlitter for HLineAntiHairBlitter<'_> {
626 fn draw_cap(&mut self, x: u32, mut fy: FDot16, _: FDot16, mod64: i32) -> FDot16 {
627 fy += fdot16::ONE / 2;
628 fy = fy.max(0);
629
630 let y = (fy >> 16) as u32;
631 let a = i32_to_alpha(fy >> 8);
632
633 let mut ma = fdot6::small_scale(a, mod64);
635 if ma != 0 {
636 call_hline_blitter(x, Some(y), LENGTH_U32_ONE, ma, self.0);
637 }
638
639 ma = fdot6::small_scale(255 - a, mod64);
641 if ma != 0 {
642 call_hline_blitter(x, y.checked_sub(1), LENGTH_U32_ONE, ma, self.0);
643 }
644
645 fy - fdot16::ONE / 2
646 }
647
648 fn draw_line(&mut self, x: u32, stop_x: u32, mut fy: FDot16, _: FDot16) -> FDot16 {
649 let count = match LengthU32::new(stop_x - x) {
650 Some(n) => n,
651 None => return fy,
652 };
653
654 fy += fdot16::ONE / 2;
655 fy = fy.max(0);
656
657 let y = (fy >> 16) as u32;
658 let mut a = i32_to_alpha(fy >> 8);
659
660 if a != 0 {
662 call_hline_blitter(x, Some(y), count, a, self.0);
663 }
664
665 a = 255 - a;
667 if a != 0 {
668 call_hline_blitter(x, y.checked_sub(1), count, a, self.0);
669 }
670
671 fy - fdot16::ONE / 2
672 }
673}
674
675struct HorishAntiHairBlitter<'a>(&'a mut dyn Blitter);
676
677impl AntiHairBlitter for HorishAntiHairBlitter<'_> {
678 fn draw_cap(&mut self, x: u32, mut fy: FDot16, dy: FDot16, mod64: i32) -> FDot16 {
679 fy += fdot16::ONE / 2;
680 fy = fy.max(0);
681
682 let lower_y = (fy >> 16) as u32;
683 let a = i32_to_alpha(fy >> 8);
684 let a0 = fdot6::small_scale(255 - a, mod64);
685 let a1 = fdot6::small_scale(a, mod64);
686 self.0.blit_anti_v2(x, lower_y.max(1) - 1, a0, a1);
687
688 fy + dy - fdot16::ONE / 2
689 }
690
691 fn draw_line(&mut self, mut x: u32, stop_x: u32, mut fy: FDot16, dy: FDot16) -> FDot16 {
692 debug_assert!(x < stop_x);
693
694 fy += fdot16::ONE / 2;
695 loop {
696 fy = fy.max(0);
697 let lower_y = (fy >> 16) as u32;
698 let a = i32_to_alpha(fy >> 8);
699 self.0.blit_anti_v2(x, lower_y.max(1) - 1, 255 - a, a);
700 fy += dy;
701
702 x += 1;
703 if x >= stop_x {
704 break;
705 }
706 }
707
708 fy - fdot16::ONE / 2
709 }
710}
711
712struct VLineAntiHairBlitter<'a>(&'a mut dyn Blitter);
713
714impl AntiHairBlitter for VLineAntiHairBlitter<'_> {
715 fn draw_cap(&mut self, y: u32, mut fx: FDot16, dx: FDot16, mod64: i32) -> FDot16 {
716 debug_assert!(dx == 0);
717 fx += fdot16::ONE / 2;
718 fx = fx.max(0);
719
720 let x = (fx >> 16) as u32;
721 let a = i32_to_alpha(fx >> 8);
722
723 let mut ma = fdot6::small_scale(a, mod64);
724 if ma != 0 {
725 self.0.blit_v(x, y, LENGTH_U32_ONE, ma);
726 }
727
728 ma = fdot6::small_scale(255 - a, mod64);
729 if ma != 0 {
730 self.0.blit_v(x.max(1) - 1, y, LENGTH_U32_ONE, ma);
731 }
732
733 fx - fdot16::ONE / 2
734 }
735
736 fn draw_line(&mut self, y: u32, stop_y: u32, mut fx: FDot16, dx: FDot16) -> FDot16 {
737 debug_assert!(dx == 0);
738 let height = match LengthU32::new(stop_y - y) {
739 Some(n) => n,
740 None => return fx,
741 };
742
743 fx += fdot16::ONE / 2;
744 fx = fx.max(0);
745
746 let x = (fx >> 16) as u32;
747 let mut a = i32_to_alpha(fx >> 8);
748
749 if a != 0 {
750 self.0.blit_v(x, y, height, a);
751 }
752
753 a = 255 - a;
754 if a != 0 {
755 self.0.blit_v(x.max(1) - 1, y, height, a);
756 }
757
758 fx - fdot16::ONE / 2
759 }
760}
761
762struct VertishAntiHairBlitter<'a>(&'a mut dyn Blitter);
763
764impl AntiHairBlitter for VertishAntiHairBlitter<'_> {
765 fn draw_cap(&mut self, y: u32, mut fx: FDot16, dx: FDot16, mod64: i32) -> FDot16 {
766 fx += fdot16::ONE / 2;
767 fx = fx.max(0);
768
769 let x = (fx >> 16) as u32;
770 let a = i32_to_alpha(fx >> 8);
771 self.0.blit_anti_h2(
772 x.max(1) - 1,
773 y,
774 fdot6::small_scale(255 - a, mod64),
775 fdot6::small_scale(a, mod64),
776 );
777
778 fx + dx - fdot16::ONE / 2
779 }
780
781 fn draw_line(&mut self, mut y: u32, stop_y: u32, mut fx: FDot16, dx: FDot16) -> FDot16 {
782 debug_assert!(y < stop_y);
783
784 fx += fdot16::ONE / 2;
785 loop {
786 fx = fx.max(0);
787 let x = (fx >> 16) as u32;
788 let a = i32_to_alpha(fx >> 8);
789 self.0.blit_anti_h2(x.max(1) - 1, y, 255 - a, a);
790 fx += dx;
791
792 y += 1;
793 if y >= stop_y {
794 break;
795 }
796 }
797
798 fx - fdot16::ONE / 2
799 }
800}
801
802fn i32_to_alpha(a: i32) -> u8 {
803 (a & 0xFF) as u8
804}
805
806struct RectClipBlitter<'a> {
807 blitter: &'a mut dyn Blitter,
808 clip: ScreenIntRect,
809}
810
811impl Blitter for RectClipBlitter<'_> {
812 fn blit_anti_h(
813 &mut self,
814 x: u32,
815 y: u32,
816 mut antialias: &mut [AlphaU8],
817 mut runs: &mut [AlphaRun],
818 ) {
819 fn y_in_rect(y: u32, rect: ScreenIntRect) -> bool {
820 (y - rect.top()) < rect.height()
821 }
822
823 if !y_in_rect(y, self.clip) || x >= self.clip.right() {
824 return;
825 }
826
827 let mut x0 = x;
828 let mut x1 = x + compute_anti_width(runs);
829
830 if x1 <= self.clip.left() {
831 return;
832 }
833
834 debug_assert!(x0 < x1);
835 if x0 < self.clip.left() {
836 let dx = self.clip.left() - x0;
837 AlphaRuns::break_at(antialias, runs, dx as i32);
838 antialias = &mut antialias[dx as usize..];
839 runs = &mut runs[dx as usize..];
840 x0 = self.clip.left();
841 }
842
843 debug_assert!(x0 < x1 && runs[(x1 - x0) as usize].is_none());
844 if x1 > self.clip.right() {
845 x1 = self.clip.right();
846 AlphaRuns::break_at(antialias, runs, (x1 - x0) as i32);
847 runs[(x1 - x0) as usize] = None;
848 }
849
850 debug_assert!(x0 < x1 && runs[(x1 - x0) as usize].is_none());
851 debug_assert!(compute_anti_width(runs) == x1 - x0);
852
853 self.blitter.blit_anti_h(x0, y, antialias, runs);
854 }
855
856 fn blit_v(&mut self, x: u32, y: u32, height: LengthU32, alpha: AlphaU8) {
857 fn x_in_rect(x: u32, rect: ScreenIntRect) -> bool {
858 (x - rect.left()) < rect.width()
859 }
860
861 if !x_in_rect(x, self.clip) {
862 return;
863 }
864
865 let mut y0 = y;
866 let mut y1 = y + height.get();
867
868 if y0 < self.clip.top() {
869 y0 = self.clip.top();
870 }
871
872 if y1 > self.clip.bottom() {
873 y1 = self.clip.bottom();
874 }
875
876 if y0 < y1 {
877 if let Some(h) = LengthU32::new(y1 - y0) {
878 self.blitter.blit_v(x, y0, h, alpha);
879 }
880 }
881 }
882
883 fn blit_anti_h2(&mut self, x: u32, y: u32, alpha0: AlphaU8, alpha1: AlphaU8) {
884 self.blit_anti_h(
885 x,
886 y,
887 &mut [alpha0, alpha1],
888 &mut [NonZeroU16::new(1), NonZeroU16::new(1), None],
889 );
890 }
891
892 fn blit_anti_v2(&mut self, x: u32, y: u32, alpha0: AlphaU8, alpha1: AlphaU8) {
893 self.blit_anti_h(x, y, &mut [alpha0], &mut [NonZeroU16::new(1), None]);
894
895 self.blit_anti_h(x, y + 1, &mut [alpha1], &mut [NonZeroU16::new(1), None]);
896 }
897}
898
899fn compute_anti_width(runs: &[AlphaRun]) -> u32 {
900 let mut i = 0;
901 let mut width = 0;
902 while let Some(count) = runs[i] {
903 width += u32::from(count.get());
904 i += usize::from(count.get());
905 }
906
907 width
908}