From 3109001fa08593930c8e5bb2933316761eb16030 Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Wed, 8 May 2024 15:20:00 +0200 Subject: [PATCH] refactor(core): remove old homescreen rendering from mercury UI [no changelog] --- .../model_mercury/component/homescreen/mod.rs | 191 +---- .../component/homescreen/render.rs | 768 ------------------ 2 files changed, 16 insertions(+), 943 deletions(-) delete mode 100644 core/embed/rust/src/ui/model_mercury/component/homescreen/render.rs diff --git a/core/embed/rust/src/ui/model_mercury/component/homescreen/mod.rs b/core/embed/rust/src/ui/model_mercury/component/homescreen/mod.rs index fe6bb95e3f..33d8e79cf3 100644 --- a/core/embed/rust/src/ui/model_mercury/component/homescreen/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/component/homescreen/mod.rs @@ -1,5 +1,3 @@ -mod render; - use crate::{ micropython::gc::Gc, strutil::TString, @@ -17,26 +15,12 @@ use crate::{ }, }; -use crate::{ - trezorhal::{buffers::BufferJpegWork, uzlib::UZLIB_WINDOW_SIZE}, - ui::{ - constant::{screen, HEIGHT}, - display::{ - tjpgd::BufferInput, - toif::{Toif, ToifFormat}, - }, - model_mercury::{ - component::homescreen::render::{HomescreenJpeg, HomescreenToif, HOMESCREEN_TOIF_SIZE}, - theme::{ - GREEN_LIGHT, GREY_LIGHT, ICON_CENTRAL_CIRCLE, ICON_KEY, ICON_LOCKSCREEN_FILTER, - }, - }, +use crate::ui::{ + constant::{screen, HEIGHT, WIDTH}, + model_mercury::theme::{ + GREEN_LIGHT, GREY_LIGHT, ICON_CENTRAL_CIRCLE, ICON_KEY, ICON_LOCKSCREEN_FILTER, }, }; -use render::{ - homescreen, homescreen_blurred, HomescreenNotification, HomescreenText, - HOMESCREEN_IMAGE_HEIGHT, HOMESCREEN_IMAGE_WIDTH, -}; use super::{theme, Loader, LoaderMsg}; @@ -51,6 +35,16 @@ const LOADER_OFFSET: Offset = Offset::y(-10); const LOADER_DELAY: Duration = Duration::from_millis(500); const LOADER_DURATION: Duration = Duration::from_millis(2000); +pub const HOMESCREEN_IMAGE_WIDTH: i16 = WIDTH; +pub const HOMESCREEN_IMAGE_HEIGHT: i16 = HEIGHT; + +#[derive(Clone, Copy)] +pub struct HomescreenNotification { + pub text: TString<'static>, + pub icon: Icon, + pub color: Color, +} + pub struct Homescreen { label: TString<'static>, notification: Option<(TString<'static>, u8)>, @@ -109,19 +103,6 @@ impl Homescreen { } } - fn paint_loader(&mut self) { - TR::progress__locking_device.map_translated(|t| { - display::text_center( - TOP_CENTER + Offset::y(HOLD_Y), - t, - Font::NORMAL, - theme::FG, - theme::BG, - ) - }); - self.loader.paint() - } - fn render_loader<'s>(&'s self, target: &mut impl Renderer<'s>) { TR::progress__locking_device.map_translated(|t| { shape::Text::new(TOP_CENTER + Offset::y(HOLD_Y), t) @@ -197,63 +178,7 @@ impl Component for Homescreen { } fn paint(&mut self) { - self.pad.paint(); - if self.loader.is_animating() || self.loader.is_completely_grown(Instant::now()) { - self.paint_loader(); - } else { - let mut label_style = theme::TEXT_DEMIBOLD; - label_style.text_color = theme::FG; - - let text = HomescreenText { - text: self.label, - style: label_style, - offset: Offset::y(LABEL_Y), - icon: None, - }; - - let notification = self.get_notification(); - - let mut show_default = true; - - if let Some(ref data) = self.custom_image { - if is_image_jpeg(data.as_ref()) { - let input = BufferInput(data.as_ref()); - let mut pool = BufferJpegWork::get_cleared(); - let mut hs_img = HomescreenJpeg::new(input, pool.buffer.as_mut_slice()); - homescreen( - &mut hs_img, - &[text], - notification, - self.paint_notification_only, - ); - show_default = false; - } else if is_image_toif(data.as_ref()) { - let input = unwrap!(Toif::new(data.as_ref())); - let mut window = [0; UZLIB_WINDOW_SIZE]; - let mut hs_img = - HomescreenToif::new(input.decompression_context(Some(&mut window))); - homescreen( - &mut hs_img, - &[text], - notification, - self.paint_notification_only, - ); - show_default = false; - } - } - - if show_default { - let input = BufferInput(IMAGE_HOMESCREEN); - let mut pool = BufferJpegWork::get_cleared(); - let mut hs_img = HomescreenJpeg::new(input, pool.buffer.as_mut_slice()); - homescreen( - &mut hs_img, - &[text], - notification, - self.paint_notification_only, - ); - } - } + todo!() } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { @@ -269,10 +194,6 @@ impl Component for Homescreen { shape::JpegImage::new(AREA.center(), img_data) .with_align(Alignment2D::CENTER) .render(target); - } else if is_image_toif(img_data) { - shape::ToifImage::new(self.pad.area.center(), unwrap!(Toif::new(img_data))) - .with_align(Alignment2D::CENTER) - .render(target); } self.label.map(|t| { @@ -381,74 +302,7 @@ impl Component for Lockscreen<'_> { } fn paint(&mut self) { - let (locked, tap) = if self.bootscreen { - ( - TR::lockscreen__title_not_connected, - TR::lockscreen__tap_to_connect, - ) - } else { - (TR::lockscreen__title_locked, TR::lockscreen__tap_to_unlock) - }; - - let mut label_style = theme::TEXT_DEMIBOLD; - label_style.text_color = theme::GREY_LIGHT; - - let mut texts: &[HomescreenText] = &[ - HomescreenText { - text: "".into(), - style: theme::TEXT_NORMAL, - offset: Offset::new(2, COINJOIN_Y), - icon: Some(theme::ICON_COINJOIN), - }, - HomescreenText { - text: locked.into(), - style: theme::TEXT_BOLD, - offset: Offset::y(LOCKED_Y), - icon: Some(theme::ICON_LOCK), - }, - HomescreenText { - text: tap.into(), - style: theme::TEXT_NORMAL, - offset: Offset::y(TAP_Y), - icon: None, - }, - HomescreenText { - text: self.label, - style: label_style, - offset: Offset::y(LABEL_Y), - icon: None, - }, - ]; - - if !self.coinjoin_authorized { - texts = &texts[1..]; - } - - let mut show_default = true; - - if let Some(ref data) = self.custom_image { - if is_image_jpeg(data.as_ref()) { - let input = BufferInput(data.as_ref()); - let mut pool = BufferJpegWork::get_cleared(); - let mut hs_img = HomescreenJpeg::new(input, pool.buffer.as_mut_slice()); - homescreen_blurred(&mut hs_img, texts); - show_default = false; - } else if is_image_toif(data.as_ref()) { - let input = unwrap!(Toif::new(data.as_ref())); - let mut window = [0; UZLIB_WINDOW_SIZE]; - let mut hs_img = - HomescreenToif::new(input.decompression_context(Some(&mut window))); - homescreen_blurred(&mut hs_img, texts); - show_default = false; - } - } - - if show_default { - let input = BufferInput(IMAGE_HOMESCREEN); - let mut pool = BufferJpegWork::get_cleared(); - let mut hs_img = HomescreenJpeg::new(input, pool.buffer.as_mut_slice()); - homescreen_blurred(&mut hs_img, texts); - } + todo!() } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { @@ -560,19 +414,6 @@ fn is_image_jpeg(buffer: &[u8]) -> bool { false } -fn is_image_toif(buffer: &[u8]) -> bool { - let toif = Toif::new(buffer); - if let Ok(toif) = toif { - if toif.size().x == HOMESCREEN_TOIF_SIZE - && toif.size().y == HOMESCREEN_TOIF_SIZE - && toif.format() == ToifFormat::FullColorBE - { - return true; - } - } - false -} - #[cfg(feature = "ui_debug")] impl crate::trace::Trace for Lockscreen<'_> { fn trace(&self, t: &mut dyn crate::trace::Tracer) { diff --git a/core/embed/rust/src/ui/model_mercury/component/homescreen/render.rs b/core/embed/rust/src/ui/model_mercury/component/homescreen/render.rs deleted file mode 100644 index 897c9cd9e4..0000000000 --- a/core/embed/rust/src/ui/model_mercury/component/homescreen/render.rs +++ /dev/null @@ -1,768 +0,0 @@ -use crate::{ - strutil::TString, - trezorhal::{ - buffers::{ - BufferBlurring, BufferBlurringTotals, BufferJpeg, BufferLine16bpp, BufferLine4bpp, - BufferText, - }, - display, - dma2d::{dma2d_setup_4bpp_over_16bpp, dma2d_start_blend, dma2d_wait_for_transfer}, - uzlib::UzlibContext, - }, - ui::{ - component::text::TextStyle, - constant::{screen, HEIGHT, WIDTH}, - display::{ - position_buffer, rect_fill_rounded_buffer, set_window, - tjpgd::{BufferInput, BufferOutput, JDEC}, - Color, Icon, - }, - geometry::{Offset, Point, Rect}, - model_mercury::theme, - util::icon_text_center, - }, -}; - -#[derive(Clone, Copy)] -pub struct HomescreenText<'a> { - pub text: TString<'a>, - pub style: TextStyle, - pub offset: Offset, - pub icon: Option, -} - -#[derive(Clone, Copy)] -pub struct HomescreenNotification { - pub text: TString<'static>, - pub icon: Icon, - pub color: Color, -} - -#[derive(Clone, Copy)] -struct HomescreenTextInfo { - pub text_area: Rect, - pub text_width: i16, - pub text_color: Color, - pub icon_area: Option, -} - -pub const HOMESCREEN_IMAGE_WIDTH: i16 = WIDTH; -pub const HOMESCREEN_IMAGE_HEIGHT: i16 = HEIGHT; -pub const HOMESCREEN_TOIF_SIZE: i16 = 144; -pub const HOMESCREEN_TOIF_Y_OFFSET: i16 = 27; -pub const HOMESCREEN_TOIF_X_OFFSET: usize = - ((WIDTH.saturating_sub(HOMESCREEN_TOIF_SIZE)) / 2) as usize; - -const HOMESCREEN_MAX_ICON_SIZE: i16 = 20; -const NOTIFICATION_HEIGHT: i16 = 36; -const NOTIFICATION_BORDER: i16 = 6; -const TEXT_ICON_SPACE: i16 = 2; - -const HOMESCREEN_DIM_HEIGHT: i16 = 35; -const HOMESCREEN_DIM_START: i16 = HOMESCREEN_IMAGE_HEIGHT - 42; -const HOMESCREEN_DIM: f32 = 0.65; -const HOMESCREEN_DIM_BORDER: i16 = theme::BUTTON_SPACING; - -const LOCKSCREEN_DIM: f32 = 0.55; -const LOCKSCREEN_DIM_BG: f32 = 0.0; -const LOCKSCREEN_DIM_ALL: bool = true; - -const BLUR_SIZE: usize = 9; -const BLUR_DIV: u32 = - ((65536_f32 * (1_f32 - LOCKSCREEN_DIM_BG)) as u32) / ((BLUR_SIZE * BLUR_SIZE) as u32); -const DECOMP_LINES: usize = BLUR_SIZE + 1; -const BLUR_RADIUS: i16 = (BLUR_SIZE / 2) as i16; - -const COLORS: usize = 3; -const RED_IDX: usize = 0; -const GREEN_IDX: usize = 1; -const BLUE_IDX: usize = 2; - -pub trait HomescreenDecompressor { - fn get_height(&self) -> i16; - fn decompress(&mut self); - fn get_data(&mut self) -> &mut BufferJpeg; -} - -pub struct HomescreenJpeg<'i> { - pub output: BufferOutput, - pub input: BufferInput<'i>, - pub jdec: Option>, -} - -impl<'i> HomescreenJpeg<'i> { - pub fn new(mut input: BufferInput<'i>, pool: &'i mut [u8]) -> Self { - Self { - output: BufferOutput::new(WIDTH, 16), - jdec: JDEC::new(&mut input, pool).ok(), - input, - } - } -} - -impl<'i> HomescreenDecompressor for HomescreenJpeg<'i> { - fn get_height(&self) -> i16 { - if let Some(dec) = self.jdec.as_ref() { - return dec.mcu_height(); - } - 1 - } - - fn decompress(&mut self) { - self.jdec - .as_mut() - .map(|dec| dec.decomp(&mut self.input, &mut self.output)); - } - - fn get_data(&mut self) -> &mut BufferJpeg { - self.output.buffer() - } -} - -pub struct HomescreenToif<'i> { - pub output: BufferOutput, - pub decomp_context: UzlibContext<'i>, - line: i16, -} - -impl<'i> HomescreenToif<'i> { - pub fn new(context: UzlibContext<'i>) -> Self { - Self { - output: BufferOutput::new(WIDTH, 16), - decomp_context: context, - line: 0, - } - } -} - -impl<'i> HomescreenDecompressor for HomescreenToif<'i> { - fn get_height(&self) -> i16 { - 1 - } - - fn decompress(&mut self) { - // SAFETY: Aligning to u8 slice is safe, because the original slice is aligned - // to 16 bits, therefore there are also no residuals (prefix/suffix). - // The data in the slices are integers, so these are valid for both u16 - // and u8. - if self.line >= HOMESCREEN_TOIF_Y_OFFSET - && self.line < HOMESCREEN_TOIF_Y_OFFSET + HOMESCREEN_TOIF_SIZE - { - let (_, workbuf, _) = unsafe { self.output.buffer().buffer.align_to_mut::() }; - let result = self.decomp_context.uncompress( - &mut workbuf[2 * HOMESCREEN_TOIF_X_OFFSET - ..2 * HOMESCREEN_TOIF_X_OFFSET + 2 * HOMESCREEN_TOIF_SIZE as usize], - ); - - if result.is_err() { - self.output.buffer().buffer.fill(0); - } else { - for i in 0..HOMESCREEN_TOIF_SIZE as usize { - workbuf.swap( - 2 * HOMESCREEN_TOIF_X_OFFSET + 2 * i, - 2 * HOMESCREEN_TOIF_X_OFFSET + 2 * i + 1, - ); - } - } - } else { - self.output.buffer().buffer.fill(0); - } - self.line += 1; - } - - fn get_data(&mut self) -> &mut BufferJpeg { - self.output.buffer() - } -} - -fn homescreen_get_fg_text( - y_tmp: i16, - text_info: HomescreenTextInfo, - text_buffer: &BufferText, - fg_buffer: &mut BufferLine4bpp, -) -> bool { - if y_tmp >= text_info.text_area.y0 && y_tmp < text_info.text_area.y1 { - let y_pos = y_tmp - text_info.text_area.y0; - position_buffer( - &mut fg_buffer.buffer, - &text_buffer.buffer[(y_pos * WIDTH / 2) as usize..((y_pos + 1) * WIDTH / 2) as usize], - 4, - text_info.text_area.x0, - text_info.text_width, - ); - } - - y_tmp == (text_info.text_area.y1 - 1) -} - -fn homescreen_get_fg_icon( - y_tmp: i16, - text_info: HomescreenTextInfo, - icon_data: &[u8], - fg_buffer: &mut BufferLine4bpp, -) { - if let Some(icon_area) = text_info.icon_area { - let icon_size = icon_area.size(); - if y_tmp >= icon_area.y0 && y_tmp < icon_area.y1 { - let y_pos = y_tmp - icon_area.y0; - position_buffer( - &mut fg_buffer.buffer, - &icon_data - [(y_pos * icon_size.x / 2) as usize..((y_pos + 1) * icon_size.x / 2) as usize], - 4, - icon_area.x0, - icon_size.x, - ); - } - } -} - -fn homescreen_position_text( - text: &HomescreenText, - buffer: &mut BufferText, - icon_buffer: &mut [u8], -) -> HomescreenTextInfo { - let text_width = text - .text - .map(|t| display::text_width(t, text.style.text_font.into())); - let font_max_height = display::text_max_height(text.style.text_font.into()); - let font_baseline = display::text_baseline(text.style.text_font.into()); - let text_width_clamped = text_width.clamp(0, screen().width()); - - let icon_size = if let Some(icon) = text.icon { - let size = icon.toif.size(); - assert!(size.x <= HOMESCREEN_MAX_ICON_SIZE); - assert!(size.y <= HOMESCREEN_MAX_ICON_SIZE); - icon.toif.uncompress(icon_buffer); - size - } else { - Offset::zero() - }; - - let text_top = screen().y0 + text.offset.y - font_max_height + font_baseline; - let text_bottom = screen().y0 + text.offset.y + font_baseline; - - let total_width = text_width_clamped + icon_size.x + TEXT_ICON_SPACE; - let icon_left = screen().center().x + text.offset.x - total_width / 2; - let text_left = icon_left + icon_size.x + TEXT_ICON_SPACE; - let text_right = screen().center().x + text.offset.x + total_width / 2; - - let text_area = Rect::new( - Point::new(text_left, text_top), - Point::new(text_right, text_bottom), - ); - - let icon_area = if text.icon.is_some() { - Some(Rect::from_top_left_and_size( - Point::new(icon_left, text_bottom - icon_size.y - font_baseline), - icon_size, - )) - } else { - None - }; - - text.text - .map(|t| display::text_into_buffer(t, text.style.text_font.into(), buffer, 0)); - - HomescreenTextInfo { - text_area, - text_width, - text_color: text.style.text_color, - icon_area, - } -} - -#[inline(always)] -fn homescreen_dim_area(x: i16, y: i16) -> bool { - y >= HOMESCREEN_DIM_START - && (y > HOMESCREEN_DIM_START + 1 - && y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT - 1) - && x > HOMESCREEN_DIM_BORDER - && x < WIDTH - HOMESCREEN_DIM_BORDER) - || (y > HOMESCREEN_DIM_START - && y < (HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT) - && x > HOMESCREEN_DIM_BORDER + 1 - && x < WIDTH - (HOMESCREEN_DIM_BORDER + 1)) - || ((HOMESCREEN_DIM_START..=(HOMESCREEN_DIM_START + HOMESCREEN_DIM_HEIGHT)).contains(&y) - && x > HOMESCREEN_DIM_BORDER + 2 - && x < WIDTH - (HOMESCREEN_DIM_BORDER + 2)) -} - -fn homescreen_line_blurred( - icon_data: &[u8], - text_buffer: &mut BufferText, - fg_buffer: &mut BufferLine4bpp, - img_buffer: &mut BufferLine16bpp, - text_info: HomescreenTextInfo, - blurring: &BlurringContext, - y: i16, -) -> bool { - fg_buffer.buffer.fill(0); - for x in 0..HOMESCREEN_IMAGE_WIDTH { - let c = if LOCKSCREEN_DIM_ALL { - let x = x as usize; - - let coef = (65536_f32 * LOCKSCREEN_DIM) as u32; - - let r = (blurring.totals.buffer[RED_IDX][x] as u32 * BLUR_DIV) >> 16; - let g = (blurring.totals.buffer[GREEN_IDX][x] as u32 * BLUR_DIV) >> 16; - let b = (blurring.totals.buffer[BLUE_IDX][x] as u32 * BLUR_DIV) >> 16; - - let r = (((coef * r) >> 8) & 0xF800) as u16; - let g = (((coef * g) >> 13) & 0x07E0) as u16; - let b = (((coef * b) >> 19) & 0x001F) as u16; - - r | g | b - } else { - let x = x as usize; - - let r = (((blurring.totals.buffer[RED_IDX][x] as u32 * BLUR_DIV) >> 8) & 0xF800) as u16; - let g = - (((blurring.totals.buffer[GREEN_IDX][x] as u32 * BLUR_DIV) >> 13) & 0x07E0) as u16; - let b = - (((blurring.totals.buffer[BLUE_IDX][x] as u32 * BLUR_DIV) >> 19) & 0x001F) as u16; - r | g | b - }; - - let j = (2 * x) as usize; - img_buffer.buffer[j + 1] = (c >> 8) as u8; - img_buffer.buffer[j] = (c & 0xFF) as u8; - } - - let done = homescreen_get_fg_text(y, text_info, text_buffer, fg_buffer); - homescreen_get_fg_icon(y, text_info, icon_data, fg_buffer); - - dma2d_wait_for_transfer(); - dma2d_setup_4bpp_over_16bpp(text_info.text_color.into()); - unsafe { - dma2d_start_blend(&fg_buffer.buffer, &img_buffer.buffer, WIDTH); - } - - done -} - -#[allow(clippy::too_many_arguments)] -fn homescreen_line( - icon_data: &[u8], - text_buffer: &mut BufferText, - text_info: HomescreenTextInfo, - data_buffer: &mut BufferJpeg, - fg_buffer: &mut BufferLine4bpp, - img_buffer: &mut BufferLine16bpp, - mcu_height: i16, - y: i16, -) -> bool { - let image_data = get_data(data_buffer, y, mcu_height); - fg_buffer.buffer.fill(0); - - for x in 0..HOMESCREEN_IMAGE_WIDTH { - let d = image_data[x as usize]; - - let c = if homescreen_dim_area(x, y) { - let coef = (65536_f32 * HOMESCREEN_DIM) as u32; - - let r = (d & 0xF800) >> 8; - let g = (d & 0x07E0) >> 3; - let b = (d & 0x001F) << 3; - - let r = (((coef * r as u32) >> 8) & 0xF800) as u16; - let g = (((coef * g as u32) >> 13) & 0x07E0) as u16; - let b = (((coef * b as u32) >> 19) & 0x001F) as u16; - r | g | b - } else { - d - }; - - let j = 2 * x as usize; - img_buffer.buffer[j + 1] = (c >> 8) as u8; - img_buffer.buffer[j] = (c & 0xFF) as u8; - } - - let done = homescreen_get_fg_text(y, text_info, text_buffer, fg_buffer); - homescreen_get_fg_icon(y, text_info, icon_data, fg_buffer); - - dma2d_wait_for_transfer(); - dma2d_setup_4bpp_over_16bpp(text_info.text_color.into()); - unsafe { - dma2d_start_blend(&fg_buffer.buffer, &img_buffer.buffer, WIDTH); - } - - done -} - -fn homescreen_next_text( - texts: &[HomescreenText], - text_buffer: &mut BufferText, - icon_data: &mut [u8], - text_info: HomescreenTextInfo, - text_idx: usize, -) -> (HomescreenTextInfo, usize) { - let mut next_text_idx = text_idx; - let mut next_text_info = text_info; - - if next_text_idx < texts.len() { - if let Some(txt) = texts.get(next_text_idx) { - text_buffer.buffer.fill(0); - next_text_info = homescreen_position_text(txt, text_buffer, icon_data); - next_text_idx += 1; - } - } - - (next_text_info, next_text_idx) -} - -#[inline(always)] -fn update_accs_add(data: &[u16], idx: usize, acc_r: &mut u16, acc_g: &mut u16, acc_b: &mut u16) { - let d = data[idx]; - let r = (d & 0xF800) >> 8; - let g = (d & 0x07E0) >> 3; - let b = (d & 0x001F) << 3; - *acc_r += r; - *acc_g += g; - *acc_b += b; -} - -#[inline(always)] -fn update_accs_sub(data: &[u16], idx: usize, acc_r: &mut u16, acc_g: &mut u16, acc_b: &mut u16) { - let d = data[idx]; - let r = (d & 0xF800) >> 8; - let g = (d & 0x07E0) >> 3; - let b = (d & 0x001F) << 3; - *acc_r -= r; - *acc_g -= g; - *acc_b -= b; -} - -struct BlurringContext { - mem: BufferBlurring, - pub totals: BufferBlurringTotals, - line_num: i16, - add_idx: usize, - rem_idx: usize, -} - -impl BlurringContext { - pub fn new() -> Self { - Self { - mem: BufferBlurring::get_cleared(), - totals: BufferBlurringTotals::get_cleared(), - line_num: 0, - add_idx: 0, - rem_idx: 0, - } - } - - fn clear(&mut self) { - let lines = &mut self.mem.buffer[0..DECOMP_LINES]; - for (i, total) in self.totals.buffer.iter_mut().enumerate() { - for line in lines.iter_mut() { - line[i].fill(0); - } - total.fill(0); - } - } - - // computes color averages for one line of image data - fn compute_line_avgs(&mut self, buffer: &mut BufferJpeg, mcu_height: i16) { - let lines = &mut self.mem.buffer[0..DECOMP_LINES]; - let mut acc_r = 0; - let mut acc_g = 0; - let mut acc_b = 0; - let data = get_data(buffer, self.line_num, mcu_height); - - for i in -BLUR_RADIUS..=BLUR_RADIUS { - let ic = i.clamp(0, HOMESCREEN_IMAGE_WIDTH - 1) as usize; - update_accs_add(data, ic, &mut acc_r, &mut acc_g, &mut acc_b); - } - - for i in 0..HOMESCREEN_IMAGE_WIDTH { - lines[self.add_idx][RED_IDX][i as usize] = acc_r; - lines[self.add_idx][GREEN_IDX][i as usize] = acc_g; - lines[self.add_idx][BLUE_IDX][i as usize] = acc_b; - - // clamping handles left and right edges - let ic = (i - BLUR_RADIUS).clamp(0, HOMESCREEN_IMAGE_WIDTH - 1) as usize; - let ic2 = - (i + BLUR_SIZE as i16 - BLUR_RADIUS).clamp(0, HOMESCREEN_IMAGE_WIDTH - 1) as usize; - update_accs_add(data, ic2, &mut acc_r, &mut acc_g, &mut acc_b); - update_accs_sub(data, ic, &mut acc_r, &mut acc_g, &mut acc_b); - } - self.line_num += 1; - } - - // adds one line of averages to sliding total averages - fn vertical_avg_add(&mut self) { - let lines = &mut self.mem.buffer[0..DECOMP_LINES]; - for i in 0..HOMESCREEN_IMAGE_WIDTH as usize { - self.totals.buffer[RED_IDX][i] += lines[self.add_idx][RED_IDX][i]; - self.totals.buffer[GREEN_IDX][i] += lines[self.add_idx][GREEN_IDX][i]; - self.totals.buffer[BLUE_IDX][i] += lines[self.add_idx][BLUE_IDX][i]; - } - } - - // adds one line and removes one line of averages to/from sliding total averages - fn vertical_avg(&mut self) { - let lines = &mut self.mem.buffer[0..DECOMP_LINES]; - for i in 0..HOMESCREEN_IMAGE_WIDTH as usize { - self.totals.buffer[RED_IDX][i] += lines[self.add_idx][RED_IDX][i]; - self.totals.buffer[GREEN_IDX][i] += lines[self.add_idx][GREEN_IDX][i]; - self.totals.buffer[BLUE_IDX][i] += lines[self.add_idx][BLUE_IDX][i]; - self.totals.buffer[RED_IDX][i] -= lines[self.rem_idx][RED_IDX][i]; - self.totals.buffer[GREEN_IDX][i] -= lines[self.rem_idx][GREEN_IDX][i]; - self.totals.buffer[BLUE_IDX][i] -= lines[self.rem_idx][BLUE_IDX][i]; - } - } - - fn inc_add(&mut self) { - self.add_idx += 1; - if self.add_idx >= DECOMP_LINES { - self.add_idx = 0; - } - } - - fn inc_rem(&mut self) { - self.rem_idx += 1; - if self.rem_idx >= DECOMP_LINES { - self.rem_idx = 0; - } - } - - fn get_line_num(&self) -> i16 { - self.line_num - } -} - -#[inline(always)] -fn get_data(buffer: &mut BufferJpeg, line_num: i16, mcu_height: i16) -> &mut [u16] { - let data_start = ((line_num % mcu_height) * WIDTH) as usize; - let data_end = (((line_num % mcu_height) + 1) * WIDTH) as usize; - &mut buffer.buffer[data_start..data_end] -} - -pub fn homescreen_blurred(data: &mut dyn HomescreenDecompressor, texts: &[HomescreenText]) { - let mut icon_data = [0_u8; (HOMESCREEN_MAX_ICON_SIZE * HOMESCREEN_MAX_ICON_SIZE / 2) as usize]; - - let mut text_buffer = BufferText::get_cleared(); - let mut fg_buffer_0 = BufferLine4bpp::get_cleared(); - let mut img_buffer_0 = BufferLine16bpp::get_cleared(); - let mut fg_buffer_1 = BufferLine4bpp::get_cleared(); - let mut img_buffer_1 = BufferLine16bpp::get_cleared(); - - let mut next_text_idx = 1; - let mut text_info = - homescreen_position_text(unwrap!(texts.first()), &mut text_buffer, &mut icon_data); - - let mcu_height = data.get_height(); - data.decompress(); - - set_window(screen()); - - let mut blurring = BlurringContext::new(); - - // handling top edge case: preload the edge value N+1 times - blurring.compute_line_avgs(data.get_data(), mcu_height); - - for _ in 0..=BLUR_RADIUS { - blurring.vertical_avg_add(); - } - blurring.inc_add(); - - // load enough values to be able to compute first line averages - for _ in 0..BLUR_RADIUS { - blurring.compute_line_avgs(data.get_data(), mcu_height); - blurring.vertical_avg_add(); - blurring.inc_add(); - - if (blurring.get_line_num() % mcu_height) == 0 { - data.decompress(); - } - } - - for y in 0..HEIGHT { - // several lines have been already decompressed before this loop, adjust for - // that - if y < HOMESCREEN_IMAGE_HEIGHT - (BLUR_RADIUS + 1) { - blurring.compute_line_avgs(data.get_data(), mcu_height); - } - - let done = if y % 2 == 0 { - homescreen_line_blurred( - &icon_data, - &mut text_buffer, - &mut fg_buffer_0, - &mut img_buffer_0, - text_info, - &blurring, - y, - ) - } else { - homescreen_line_blurred( - &icon_data, - &mut text_buffer, - &mut fg_buffer_1, - &mut img_buffer_1, - text_info, - &blurring, - y, - ) - }; - - if done { - (text_info, next_text_idx) = homescreen_next_text( - texts, - &mut text_buffer, - &mut icon_data, - text_info, - next_text_idx, - ); - } - - blurring.vertical_avg(); - - // handling bottom edge case: stop incrementing counter, adding the edge value - // for the rest of image - // the extra -1 is to indicate that this was the last decompressed line, - // in the next pass the docompression and compute_line_avgs won't happen - if y < HOMESCREEN_IMAGE_HEIGHT - (BLUR_RADIUS + 1) - 1 { - blurring.inc_add(); - } - - if y == HOMESCREEN_IMAGE_HEIGHT { - // reached end of image, clear avgs (display black) - blurring.clear(); - } - - // only start incrementing remove index when enough lines have been loaded - if y >= (BLUR_RADIUS) { - blurring.inc_rem(); - } - - if (blurring.get_line_num() % mcu_height) == 0 && (blurring.get_line_num() < HEIGHT) { - data.decompress(); - } - } - dma2d_wait_for_transfer(); -} - -pub fn homescreen( - data: &mut dyn HomescreenDecompressor, - texts: &[HomescreenText], - notification: Option, - notification_only: bool, -) { - let mut icon_data = [0_u8; (HOMESCREEN_MAX_ICON_SIZE * HOMESCREEN_MAX_ICON_SIZE / 2) as usize]; - - let mut text_buffer = BufferText::get_cleared(); - let mut fg_buffer_0 = BufferLine4bpp::get_cleared(); - let mut img_buffer_0 = BufferLine16bpp::get_cleared(); - let mut fg_buffer_1 = BufferLine4bpp::get_cleared(); - let mut img_buffer_1 = BufferLine16bpp::get_cleared(); - - let mut next_text_idx = 0; - let mut text_info = if let Some(notification) = notification { - rect_fill_rounded_buffer( - Rect::from_top_left_and_size( - Point::new(NOTIFICATION_BORDER, 0), - Offset::new(WIDTH - NOTIFICATION_BORDER * 2, NOTIFICATION_HEIGHT), - ), - 2, - &mut text_buffer, - ); - let area = Rect::new( - Point::new(0, NOTIFICATION_BORDER), - Point::new(WIDTH, NOTIFICATION_HEIGHT + NOTIFICATION_BORDER), - ); - HomescreenTextInfo { - text_area: area, - text_width: WIDTH, - text_color: notification.color, - icon_area: None, - } - } else { - next_text_idx += 1; - homescreen_position_text(unwrap!(texts.first()), &mut text_buffer, &mut icon_data) - }; - - set_window(screen()); - - let mcu_height = data.get_height(); - - for y in 0..HEIGHT { - if (y % mcu_height) == 0 { - data.decompress(); - } - - let done = if y % 2 == 0 { - homescreen_line( - &icon_data, - &mut text_buffer, - text_info, - data.get_data(), - &mut fg_buffer_0, - &mut img_buffer_0, - mcu_height, - y, - ) - } else { - homescreen_line( - &icon_data, - &mut text_buffer, - text_info, - data.get_data(), - &mut fg_buffer_1, - &mut img_buffer_1, - mcu_height, - y, - ) - }; - - if done { - if notification.is_some() && next_text_idx == 0 { - //finished notification area, let interrupt and draw the text - let notification = unwrap!(notification); - - let style = TextStyle { - background_color: notification.color, - ..theme::TEXT_BOLD - }; - - dma2d_wait_for_transfer(); - - drop(fg_buffer_0); - drop(fg_buffer_1); - - icon_text_center( - text_info.text_area.center(), - notification.icon, - 8, - notification.text, - style, - Offset::new(1, -2), - ); - - fg_buffer_0 = BufferLine4bpp::get_cleared(); - fg_buffer_1 = BufferLine4bpp::get_cleared(); - - set_window( - screen() - .split_top(NOTIFICATION_HEIGHT + NOTIFICATION_BORDER) - .1, - ); - } - - if notification_only && next_text_idx == 0 { - dma2d_wait_for_transfer(); - return; - } - - (text_info, next_text_idx) = homescreen_next_text( - texts, - &mut text_buffer, - &mut icon_data, - text_info, - next_text_idx, - ); - } - } - dma2d_wait_for_transfer(); -}