1use crate::rendering_buffer::RowAccessor;
7
8pub trait MaskFunction {
16 fn calculate(&self, p: &[u8]) -> u8;
17}
18
19#[derive(Clone, Copy, Default)]
23pub struct OneComponentMask;
24
25impl MaskFunction for OneComponentMask {
26 #[inline]
27 fn calculate(&self, p: &[u8]) -> u8 {
28 p[0]
29 }
30}
31
32#[derive(Clone, Copy)]
37pub struct RgbToGrayMask {
38 pub r_offset: usize,
39 pub g_offset: usize,
40 pub b_offset: usize,
41}
42
43impl RgbToGrayMask {
44 pub const fn new(r: usize, g: usize, b: usize) -> Self {
45 Self {
46 r_offset: r,
47 g_offset: g,
48 b_offset: b,
49 }
50 }
51}
52
53impl MaskFunction for RgbToGrayMask {
54 #[inline]
55 fn calculate(&self, p: &[u8]) -> u8 {
56 ((p[self.r_offset] as u32 * 77
57 + p[self.g_offset] as u32 * 150
58 + p[self.b_offset] as u32 * 29)
59 >> 8) as u8
60 }
61}
62
63pub trait AlphaMask {
69 fn pixel(&self, x: i32, y: i32) -> u8;
70 fn combine_pixel(&self, x: i32, y: i32, val: u8) -> u8;
71 fn fill_hspan(&self, x: i32, y: i32, dst: &mut [u8]);
72 fn combine_hspan(&self, x: i32, y: i32, dst: &mut [u8]);
73 fn fill_vspan(&self, x: i32, y: i32, dst: &mut [u8]);
74 fn combine_vspan(&self, x: i32, y: i32, dst: &mut [u8]);
75}
76
77const COVER_SHIFT: u32 = 8;
82const COVER_FULL: u32 = 255;
83
84pub struct AlphaMaskU8<'a, const STEP: usize, const OFFSET: usize, MF: MaskFunction> {
91 rbuf: &'a RowAccessor,
92 mask_function: MF,
93}
94
95impl<'a, const STEP: usize, const OFFSET: usize, MF: MaskFunction>
96 AlphaMaskU8<'a, STEP, OFFSET, MF>
97{
98 pub fn new(rbuf: &'a RowAccessor, mask_function: MF) -> Self {
99 Self {
100 rbuf,
101 mask_function,
102 }
103 }
104
105 pub fn mask_function(&self) -> &MF {
106 &self.mask_function
107 }
108}
109
110impl<const STEP: usize, const OFFSET: usize, MF: MaskFunction> AlphaMask
111 for AlphaMaskU8<'_, STEP, OFFSET, MF>
112{
113 fn pixel(&self, x: i32, y: i32) -> u8 {
114 if x >= 0 && y >= 0 && x < self.rbuf.width() as i32 && y < self.rbuf.height() as i32 {
115 let row = self.rbuf.row_slice(y as u32);
116 let off = x as usize * STEP + OFFSET;
117 self.mask_function.calculate(&row[off..])
118 } else {
119 0
120 }
121 }
122
123 fn combine_pixel(&self, x: i32, y: i32, val: u8) -> u8 {
124 if x >= 0 && y >= 0 && x < self.rbuf.width() as i32 && y < self.rbuf.height() as i32 {
125 let row = self.rbuf.row_slice(y as u32);
126 let off = x as usize * STEP + OFFSET;
127 ((COVER_FULL + val as u32 * self.mask_function.calculate(&row[off..]) as u32)
128 >> COVER_SHIFT) as u8
129 } else {
130 0
131 }
132 }
133
134 fn fill_hspan(&self, x: i32, y: i32, dst: &mut [u8]) {
135 let num_pix = dst.len() as i32;
136 let xmax = self.rbuf.width() as i32 - 1;
137 let ymax = self.rbuf.height() as i32 - 1;
138
139 let mut count = num_pix;
140 let mut covers_off: usize = 0;
141 let mut x = x;
142
143 if y < 0 || y > ymax {
144 dst.iter_mut().for_each(|d| *d = 0);
145 return;
146 }
147
148 if x < 0 {
149 count += x;
150 if count <= 0 {
151 dst.iter_mut().for_each(|d| *d = 0);
152 return;
153 }
154 dst[..(-x) as usize].iter_mut().for_each(|d| *d = 0);
155 covers_off = (-x) as usize;
156 x = 0;
157 }
158
159 if x + count > xmax + 1 {
160 let rest = x + count - xmax - 1;
161 count -= rest;
162 if count <= 0 {
163 dst.iter_mut().for_each(|d| *d = 0);
164 return;
165 }
166 dst[(covers_off + count as usize)..]
167 .iter_mut()
168 .for_each(|d| *d = 0);
169 }
170
171 let row = self.rbuf.row_slice(y as u32);
172 let mut mask_off = x as usize * STEP + OFFSET;
173 for i in 0..count as usize {
174 dst[covers_off + i] = self.mask_function.calculate(&row[mask_off..]);
175 mask_off += STEP;
176 }
177 }
178
179 fn combine_hspan(&self, x: i32, y: i32, dst: &mut [u8]) {
180 let num_pix = dst.len() as i32;
181 let xmax = self.rbuf.width() as i32 - 1;
182 let ymax = self.rbuf.height() as i32 - 1;
183
184 let mut count = num_pix;
185 let mut covers_off: usize = 0;
186 let mut x = x;
187
188 if y < 0 || y > ymax {
189 dst.iter_mut().for_each(|d| *d = 0);
190 return;
191 }
192
193 if x < 0 {
194 count += x;
195 if count <= 0 {
196 dst.iter_mut().for_each(|d| *d = 0);
197 return;
198 }
199 dst[..(-x) as usize].iter_mut().for_each(|d| *d = 0);
200 covers_off = (-x) as usize;
201 x = 0;
202 }
203
204 if x + count > xmax + 1 {
205 let rest = x + count - xmax - 1;
206 count -= rest;
207 if count <= 0 {
208 dst.iter_mut().for_each(|d| *d = 0);
209 return;
210 }
211 dst[(covers_off + count as usize)..]
212 .iter_mut()
213 .for_each(|d| *d = 0);
214 }
215
216 let row = self.rbuf.row_slice(y as u32);
217 let mut mask_off = x as usize * STEP + OFFSET;
218 for i in 0..count as usize {
219 let idx = covers_off + i;
220 dst[idx] = ((COVER_FULL
221 + dst[idx] as u32 * self.mask_function.calculate(&row[mask_off..]) as u32)
222 >> COVER_SHIFT) as u8;
223 mask_off += STEP;
224 }
225 }
226
227 fn fill_vspan(&self, x: i32, y: i32, dst: &mut [u8]) {
228 let num_pix = dst.len() as i32;
229 let xmax = self.rbuf.width() as i32 - 1;
230 let ymax = self.rbuf.height() as i32 - 1;
231
232 let mut count = num_pix;
233 let mut covers_off: usize = 0;
234 let mut y = y;
235
236 if x < 0 || x > xmax {
237 dst.iter_mut().for_each(|d| *d = 0);
238 return;
239 }
240
241 if y < 0 {
242 count += y;
243 if count <= 0 {
244 dst.iter_mut().for_each(|d| *d = 0);
245 return;
246 }
247 dst[..(-y) as usize].iter_mut().for_each(|d| *d = 0);
248 covers_off = (-y) as usize;
249 y = 0;
250 }
251
252 if y + count > ymax + 1 {
253 let rest = y + count - ymax - 1;
254 count -= rest;
255 if count <= 0 {
256 dst.iter_mut().for_each(|d| *d = 0);
257 return;
258 }
259 dst[(covers_off + count as usize)..]
260 .iter_mut()
261 .for_each(|d| *d = 0);
262 }
263
264 let col = x as usize * STEP + OFFSET;
265 for i in 0..count as usize {
266 let row = self.rbuf.row_slice((y + i as i32) as u32);
267 dst[covers_off + i] = self.mask_function.calculate(&row[col..]);
268 }
269 }
270
271 fn combine_vspan(&self, x: i32, y: i32, dst: &mut [u8]) {
272 let num_pix = dst.len() as i32;
273 let xmax = self.rbuf.width() as i32 - 1;
274 let ymax = self.rbuf.height() as i32 - 1;
275
276 let mut count = num_pix;
277 let mut covers_off: usize = 0;
278 let mut y = y;
279
280 if x < 0 || x > xmax {
281 dst.iter_mut().for_each(|d| *d = 0);
282 return;
283 }
284
285 if y < 0 {
286 count += y;
287 if count <= 0 {
288 dst.iter_mut().for_each(|d| *d = 0);
289 return;
290 }
291 dst[..(-y) as usize].iter_mut().for_each(|d| *d = 0);
292 covers_off = (-y) as usize;
293 y = 0;
294 }
295
296 if y + count > ymax + 1 {
297 let rest = y + count - ymax - 1;
298 count -= rest;
299 if count <= 0 {
300 dst.iter_mut().for_each(|d| *d = 0);
301 return;
302 }
303 dst[(covers_off + count as usize)..]
304 .iter_mut()
305 .for_each(|d| *d = 0);
306 }
307
308 let col = x as usize * STEP + OFFSET;
309 for i in 0..count as usize {
310 let row = self.rbuf.row_slice((y + i as i32) as u32);
311 let idx = covers_off + i;
312 dst[idx] = ((COVER_FULL
313 + dst[idx] as u32 * self.mask_function.calculate(&row[col..]) as u32)
314 >> COVER_SHIFT) as u8;
315 }
316 }
317}
318
319pub struct AmaskNoClipU8<'a, const STEP: usize, const OFFSET: usize, MF: MaskFunction> {
327 rbuf: &'a RowAccessor,
328 mask_function: MF,
329}
330
331impl<'a, const STEP: usize, const OFFSET: usize, MF: MaskFunction>
332 AmaskNoClipU8<'a, STEP, OFFSET, MF>
333{
334 pub fn new(rbuf: &'a RowAccessor, mask_function: MF) -> Self {
335 Self {
336 rbuf,
337 mask_function,
338 }
339 }
340
341 pub fn mask_function(&self) -> &MF {
342 &self.mask_function
343 }
344}
345
346impl<const STEP: usize, const OFFSET: usize, MF: MaskFunction> AlphaMask
347 for AmaskNoClipU8<'_, STEP, OFFSET, MF>
348{
349 fn pixel(&self, x: i32, y: i32) -> u8 {
350 let row = self.rbuf.row_slice(y as u32);
351 let off = x as usize * STEP + OFFSET;
352 self.mask_function.calculate(&row[off..])
353 }
354
355 fn combine_pixel(&self, x: i32, y: i32, val: u8) -> u8 {
356 let row = self.rbuf.row_slice(y as u32);
357 let off = x as usize * STEP + OFFSET;
358 ((COVER_FULL + val as u32 * self.mask_function.calculate(&row[off..]) as u32)
359 >> COVER_SHIFT) as u8
360 }
361
362 fn fill_hspan(&self, x: i32, y: i32, dst: &mut [u8]) {
363 let row = self.rbuf.row_slice(y as u32);
364 let mut mask_off = x as usize * STEP + OFFSET;
365 for d in dst.iter_mut() {
366 *d = self.mask_function.calculate(&row[mask_off..]);
367 mask_off += STEP;
368 }
369 }
370
371 fn combine_hspan(&self, x: i32, y: i32, dst: &mut [u8]) {
372 let row = self.rbuf.row_slice(y as u32);
373 let mut mask_off = x as usize * STEP + OFFSET;
374 for d in dst.iter_mut() {
375 *d = ((COVER_FULL + *d as u32 * self.mask_function.calculate(&row[mask_off..]) as u32)
376 >> COVER_SHIFT) as u8;
377 mask_off += STEP;
378 }
379 }
380
381 fn fill_vspan(&self, x: i32, y: i32, dst: &mut [u8]) {
382 let col = x as usize * STEP + OFFSET;
383 for (i, d) in dst.iter_mut().enumerate() {
384 let row = self.rbuf.row_slice((y + i as i32) as u32);
385 *d = self.mask_function.calculate(&row[col..]);
386 }
387 }
388
389 fn combine_vspan(&self, x: i32, y: i32, dst: &mut [u8]) {
390 let col = x as usize * STEP + OFFSET;
391 for (i, d) in dst.iter_mut().enumerate() {
392 let row = self.rbuf.row_slice((y + i as i32) as u32);
393 *d = ((COVER_FULL + *d as u32 * self.mask_function.calculate(&row[col..]) as u32)
394 >> COVER_SHIFT) as u8;
395 }
396 }
397}
398
399pub type AlphaMaskGray8<'a> = AlphaMaskU8<'a, 1, 0, OneComponentMask>;
405
406pub type AlphaMaskRgba32r<'a> = AlphaMaskU8<'a, 4, 0, OneComponentMask>;
408pub type AlphaMaskRgba32g<'a> = AlphaMaskU8<'a, 4, 1, OneComponentMask>;
410pub type AlphaMaskRgba32b<'a> = AlphaMaskU8<'a, 4, 2, OneComponentMask>;
412pub type AlphaMaskRgba32a<'a> = AlphaMaskU8<'a, 4, 3, OneComponentMask>;
414
415pub type AlphaMaskRgb24r<'a> = AlphaMaskU8<'a, 3, 0, OneComponentMask>;
417pub type AlphaMaskRgb24g<'a> = AlphaMaskU8<'a, 3, 1, OneComponentMask>;
419pub type AlphaMaskRgb24b<'a> = AlphaMaskU8<'a, 3, 2, OneComponentMask>;
421
422pub type AmaskNoClipGray8<'a> = AmaskNoClipU8<'a, 1, 0, OneComponentMask>;
425pub type AmaskNoClipRgba32a<'a> = AmaskNoClipU8<'a, 4, 3, OneComponentMask>;
427
428#[cfg(test)]
433mod tests {
434 use super::*;
435
436 fn make_gray_buffer(width: u32, height: u32, data: &mut Vec<u8>) -> RowAccessor {
437 data.resize((width * height) as usize, 0);
438 unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), width, height, width as i32) }
439 }
440
441 fn make_rgba_buffer(width: u32, height: u32, data: &mut Vec<u8>) -> RowAccessor {
442 let stride = width * 4;
443 data.resize((stride * height) as usize, 0);
444 unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), width, height, stride as i32) }
445 }
446
447 #[test]
448 fn test_one_component_mask() {
449 let m = OneComponentMask;
450 assert_eq!(m.calculate(&[128, 0, 0, 0]), 128);
451 assert_eq!(m.calculate(&[255]), 255);
452 assert_eq!(m.calculate(&[0, 99]), 0);
453 }
454
455 #[test]
456 fn test_rgb_to_gray_mask() {
457 let m = RgbToGrayMask::new(0, 1, 2);
458 let val = m.calculate(&[255, 0, 0]);
460 assert_eq!(val, ((255u32 * 77) >> 8) as u8);
461
462 let val = m.calculate(&[0, 255, 0]);
464 assert_eq!(val, ((255u32 * 150) >> 8) as u8);
465
466 let val = m.calculate(&[0, 0, 255]);
468 assert_eq!(val, ((255u32 * 29) >> 8) as u8);
469
470 let val = m.calculate(&[255, 255, 255]);
472 assert_eq!(val, 255);
473 }
474
475 #[test]
476 fn test_pixel_in_bounds() {
477 let mut data = Vec::new();
478 let rbuf = make_gray_buffer(4, 4, &mut data);
479 data[1 * 4 + 2] = 200;
481 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
482 assert_eq!(mask.pixel(2, 1), 200);
483 }
484
485 #[test]
486 fn test_pixel_out_of_bounds() {
487 let mut data = Vec::new();
488 let rbuf = make_gray_buffer(4, 4, &mut data);
489 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
490 assert_eq!(mask.pixel(-1, 0), 0);
491 assert_eq!(mask.pixel(0, -1), 0);
492 assert_eq!(mask.pixel(4, 0), 0);
493 assert_eq!(mask.pixel(0, 4), 0);
494 }
495
496 #[test]
497 fn test_combine_pixel() {
498 let mut data = Vec::new();
499 let rbuf = make_gray_buffer(4, 4, &mut data);
500 data[0] = 128;
501 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
502 let result = mask.combine_pixel(0, 0, 200);
504 assert_eq!(result, ((255 + 200u32 * 128) >> 8) as u8);
505 }
506
507 #[test]
508 fn test_combine_pixel_out_of_bounds() {
509 let mut data = Vec::new();
510 let rbuf = make_gray_buffer(4, 4, &mut data);
511 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
512 assert_eq!(mask.combine_pixel(-1, 0, 200), 0);
513 }
514
515 #[test]
516 fn test_fill_hspan_in_bounds() {
517 let mut data = vec![0u8; 16];
518 for i in 0..4 {
519 data[i] = (i as u8 + 1) * 50;
520 }
521 let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
522 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
523
524 let mut dst = vec![0u8; 4];
525 mask.fill_hspan(0, 0, &mut dst);
526 assert_eq!(dst, vec![50, 100, 150, 200]);
527 }
528
529 #[test]
530 fn test_fill_hspan_y_out_of_range() {
531 let mut data = Vec::new();
532 let rbuf = make_gray_buffer(4, 4, &mut data);
533 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
534
535 let mut dst = vec![99u8; 4];
536 mask.fill_hspan(0, -1, &mut dst);
537 assert_eq!(dst, vec![0, 0, 0, 0]);
538
539 let mut dst = vec![99u8; 4];
540 mask.fill_hspan(0, 4, &mut dst);
541 assert_eq!(dst, vec![0, 0, 0, 0]);
542 }
543
544 #[test]
545 fn test_fill_hspan_left_clip() {
546 let mut data = vec![0u8; 16];
547 for i in 0..4 {
548 data[i] = (i as u8 + 1) * 50;
549 }
550 let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
551 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
552
553 let mut dst = vec![99u8; 3];
554 mask.fill_hspan(-1, 0, &mut dst);
555 assert_eq!(dst[0], 0);
557 assert_eq!(dst[1], 50); assert_eq!(dst[2], 100); }
560
561 #[test]
562 fn test_fill_hspan_right_clip() {
563 let mut data = vec![0u8; 16];
564 for i in 0..4 {
565 data[i] = (i as u8 + 1) * 50;
566 }
567 let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
568 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
569
570 let mut dst = vec![99u8; 3];
571 mask.fill_hspan(2, 0, &mut dst);
572 assert_eq!(dst[0], 150); assert_eq!(dst[1], 200); assert_eq!(dst[2], 0); }
577
578 #[test]
579 fn test_combine_hspan() {
580 let mut data = vec![0u8; 16];
581 data[0] = 128;
582 data[1] = 255;
583 let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
584 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
585
586 let mut dst = vec![200u8, 100u8];
587 mask.combine_hspan(0, 0, &mut dst);
588 assert_eq!(dst[0], ((255 + 200u32 * 128) >> 8) as u8);
589 assert_eq!(dst[1], ((255 + 100u32 * 255) >> 8) as u8);
590 }
591
592 #[test]
593 fn test_fill_vspan() {
594 let mut data = vec![0u8; 16];
595 data[1] = 10;
597 data[4 + 1] = 20;
598 data[8 + 1] = 30;
599 data[12 + 1] = 40;
600 let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
601 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
602
603 let mut dst = vec![0u8; 4];
604 mask.fill_vspan(1, 0, &mut dst);
605 assert_eq!(dst, vec![10, 20, 30, 40]);
606 }
607
608 #[test]
609 fn test_fill_vspan_x_out_of_range() {
610 let mut data = Vec::new();
611 let rbuf = make_gray_buffer(4, 4, &mut data);
612 let mask = AlphaMaskGray8::new(&rbuf, OneComponentMask);
613
614 let mut dst = vec![99u8; 4];
615 mask.fill_vspan(-1, 0, &mut dst);
616 assert_eq!(dst, vec![0, 0, 0, 0]);
617 }
618
619 #[test]
620 fn test_rgba_mask() {
621 let mut data = Vec::new();
622 let rbuf = make_rgba_buffer(4, 4, &mut data);
623 data[0] = 100;
625 data[1] = 150;
626 data[2] = 200;
627 data[3] = 255;
628
629 let mask = AlphaMaskRgba32a::new(&rbuf, OneComponentMask);
631 assert_eq!(mask.pixel(0, 0), 255);
632
633 let rmask = AlphaMaskRgba32r::new(&rbuf, OneComponentMask);
635 assert_eq!(rmask.pixel(0, 0), 100);
636 }
637
638 #[test]
639 fn test_no_clip_pixel() {
640 let mut data = vec![0u8; 16];
641 data[5] = 42; let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
643 let mask = AmaskNoClipGray8::new(&rbuf, OneComponentMask);
644 assert_eq!(mask.pixel(1, 1), 42);
645 }
646
647 #[test]
648 fn test_no_clip_fill_hspan() {
649 let mut data = vec![0u8; 16];
650 data[0] = 10;
651 data[1] = 20;
652 data[2] = 30;
653 let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
654 let mask = AmaskNoClipGray8::new(&rbuf, OneComponentMask);
655
656 let mut dst = vec![0u8; 3];
657 mask.fill_hspan(0, 0, &mut dst);
658 assert_eq!(dst, vec![10, 20, 30]);
659 }
660
661 #[test]
662 fn test_no_clip_combine_pixel() {
663 let mut data = vec![0u8; 16];
664 data[0] = 128;
665 let rbuf = unsafe { RowAccessor::new_with_buf(data.as_mut_ptr(), 4, 4, 4) };
666 let mask = AmaskNoClipGray8::new(&rbuf, OneComponentMask);
667 let result = mask.combine_pixel(0, 0, 200);
668 assert_eq!(result, ((255 + 200u32 * 128) >> 8) as u8);
669 }
670}