diff --git a/core/embed/rust/src/ui/shape/canvas/rgba8888.rs b/core/embed/rust/src/ui/shape/canvas/rgba8888.rs index 88eade7667..2b7248e3e5 100644 --- a/core/embed/rust/src/ui/shape/canvas/rgba8888.rs +++ b/core/embed/rust/src/ui/shape/canvas/rgba8888.rs @@ -135,7 +135,31 @@ impl<'a> Canvas for Rgba8888Canvas<'a> { } #[cfg(feature = "ui_blurring")] - fn blur_rect(&mut self, _r: Rect, _radius: usize, _cache: &DrawingCache) { - // TODO + fn blur_rect(&mut self, r: Rect, radius: usize, cache: &DrawingCache) { + let clip = r.translate(self.viewport.origin).clamp(self.viewport.clip); + + let ofs = radius as i16; + + if clip.width() > 2 * ofs - 1 && clip.height() > 2 * ofs - 1 { + let mut blur_cache = cache.blur(); + let (blur, _) = unwrap!( + blur_cache.get(clip.size(), radius, None), + "Too small blur buffer" + ); + + loop { + if let Some(y) = blur.push_ready() { + let row = unwrap!(self.row_mut(y + clip.y0)); // can't panic + blur.push(&row[clip.x0 as usize..clip.x1 as usize]); + } + if let Some(y) = blur.pop_ready() { + let row = unwrap!(self.row_mut(y + clip.y0)); // can't panic + blur.pop(&mut row[clip.x0 as usize..clip.x1 as usize], None); + if y + 1 >= clip.height() { + break; + } + } + } + } } } diff --git a/core/embed/rust/src/ui/shape/jpeg.rs b/core/embed/rust/src/ui/shape/jpeg.rs index f72d645800..2fa5f27e71 100644 --- a/core/embed/rust/src/ui/shape/jpeg.rs +++ b/core/embed/rust/src/ui/shape/jpeg.rs @@ -197,14 +197,14 @@ impl<'a> Shape<'a> for JpegImage<'a> { if let Some(y) = blur.push_ready() { if y < row_r.y1 { // should never fail - blur.push(unwrap!(jpeg_slice.row(y - row_r.y0))); + blur.push(unwrap!(jpeg_slice.row::(y - row_r.y0))); } else { return true; // need more data } } if let Some(y) = blur.pop_ready() { - blur.pop(unwrap!(slice.row_mut(0)), Some(self.dim)); // should never fail + blur.pop(unwrap!(slice.row_mut::(0)), Some(self.dim)); // should never fail let dst_r = Rect::from_top_left_and_size(bounds.top_left(), jpeg_size) .translate(Offset::new(0, y)); canvas.draw_bitmap(dst_r, slice.view()); diff --git a/core/embed/rust/src/ui/shape/utils/blur.rs b/core/embed/rust/src/ui/shape/utils/blur.rs index 0cadb9c43c..4b03bed816 100644 --- a/core/embed/rust/src/ui/shape/utils/blur.rs +++ b/core/embed/rust/src/ui/shape/utils/blur.rs @@ -46,10 +46,8 @@ const MAX_WIDTH: usize = display::DISPLAY_RESX as usize; pub type BlurBuff = [u8; MAX_WIDTH * (MAX_SIDE * 3 + size_of::() * 3) + 8]; -type PixelColor = u16; - #[derive(Default, Copy, Clone)] -struct Rgb { +pub struct Rgb { pub r: T, pub g: T, pub b: T, @@ -77,6 +75,17 @@ impl From for Rgb { } } +impl From for Rgb { + #[inline(always)] + fn from(value: u32) -> Self { + Self { + r: ((value >> 16) & 0xFF) as u16, + g: ((value >> 8) & 0xFF) as u16, + b: (value & 0xFF) as u16, + } + } +} + impl core::ops::AddAssign for Rgb { #[inline(always)] fn add_assign(&mut self, rhs: u16) { @@ -85,6 +94,14 @@ impl core::ops::AddAssign for Rgb { } } +impl core::ops::AddAssign for Rgb { + #[inline(always)] + fn add_assign(&mut self, rhs: u32) { + let rgb: Self = rhs.into(); + *self += rgb; + } +} + impl core::ops::SubAssign for Rgb { #[inline(always)] fn sub_assign(&mut self, rhs: u16) { @@ -93,6 +110,14 @@ impl core::ops::SubAssign for Rgb { } } +impl core::ops::SubAssign for Rgb { + #[inline(always)] + fn sub_assign(&mut self, rhs: u32) { + let rgb: Self = rhs.into(); + *self -= rgb; + } +} + impl core::ops::AddAssign for Rgb { #[inline(always)] fn add_assign(&mut self, rhs: Self) { @@ -121,6 +146,17 @@ impl From> for u16 { } } +impl From> for u32 { + #[inline(always)] + fn from(value: Rgb) -> u32 { + let r = (value.r as u32) << 16; + let g = (value.g as u32) << 8; + let b = value.b as u32; + let alpha = 0xFF000000; + alpha | r | g | b + } +} + impl From> for Rgb { #[inline(always)] fn from(value: Rgb) -> Self { @@ -209,7 +245,10 @@ impl<'a> BlurAlgorithm<'a> { /// as the floating average of n subsequent elements where n = 2 * radius + /// 1. Finally, it stores it into the specifed row in the sliding /// window. - fn average_to_row(&mut self, inp: &[PixelColor], row: usize) { + fn average_to_row(&mut self, inp: &[T], row: usize) + where + T: Copy + Into>, + { let radius = self.radius; let offset = self.size.x as usize * row; let row = &mut self.window[offset..offset + self.size.x as usize]; @@ -222,29 +261,29 @@ impl<'a> BlurAlgorithm<'a> { // Prepare before averaging for i in 0..radius { - sum += inp[0]; // Duplicate pixels on the left - sum += inp[i]; // Add first radius pixels + sum += inp[0].into(); // Duplicate pixels on the left + sum += inp[i].into(); // Add first radius pixels } // Process the first few pixels of the row for i in 0..radius { - sum += inp[i + radius]; + sum += inp[i + radius].into(); row[i] = sum.mulshift(multiplier, shift); - sum -= inp[0]; + sum -= inp[0].into(); } // Process the inner part of the row for i in radius..row.len() - radius { - sum += inp[i + radius]; + sum += inp[i + radius].into(); row[i] = sum.mulshift(multiplier, shift); - sum -= inp[i - radius]; + sum -= inp[i - radius].into(); } // Process the last few pixels of the row for i in (row.len() - radius)..row.len() { - sum += inp[inp.len() - 1]; + sum += inp[inp.len() - 1].into(); row[i] = sum.mulshift(multiplier, shift); - sum -= inp[i - radius]; // Duplicate pixels on the right + sum -= inp[i - radius].into(); // Duplicate pixels on the right } } @@ -305,7 +344,10 @@ impl<'a> BlurAlgorithm<'a> { } /// Takes the source row and pushes it into the sliding window. - pub fn push(&mut self, input: &[PixelColor]) { + pub fn push(&mut self, input: &[T]) + where + T: Copy + Into>, + { let row = self.row; self.subtract_row(row); @@ -331,7 +373,10 @@ impl<'a> BlurAlgorithm<'a> { } /// Copies the current content of `totals[]` to the output buffer. - pub fn pop(&mut self, output: &mut [PixelColor], dim: Option) { + pub fn pop(&mut self, output: &mut [T], dim: Option) + where + T: Copy + Into> + From>, + { let divisor = match dim { Some(dim) => { if dim > 0 {