diff --git a/core/embed/rust/src/trezorhal/bitblt.rs b/core/embed/rust/src/trezorhal/bitblt.rs index 4803a76593..8935c3f5c1 100644 --- a/core/embed/rust/src/trezorhal/bitblt.rs +++ b/core/embed/rust/src/trezorhal/bitblt.rs @@ -66,8 +66,8 @@ impl ffi::gfx_bitblt_t { /// # SAFETY /// 1) Ensure that the rectangle is completely inside the destination /// bitmap. - /// 2) If the copy or blend operation is used, ensure that the rectangle - /// is completely filled with source bitmap or its part. + /// 2) If the copy or blend operation is used, ensure that the rectangle is + /// completely filled with source bitmap or its part. unsafe fn with_rect(self, r: Rect) -> Self { Self { width: r.width() as u16, 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 33d8e79cf3..69737881ea 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,12 +1,18 @@ use crate::{ - micropython::gc::Gc, + io::BinaryData, strutil::TString, time::{Duration, Instant}, translations::TR, trezorhal::usb::usb_configured, ui::{ component::{Component, Event, EventCtx, TimerToken}, - display::{tjpgd::jpeg_info, toif::Icon, Color, Font}, + display::{ + self, + image::{ImageInfo, ToifFormat}, + tjpgd::jpeg_info, + toif::{Icon, Toif}, + Color, Font, + }, event::{TouchEvent, USBEvent}, geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect}, layout::util::get_user_custom_image, @@ -37,6 +43,7 @@ const LOADER_DURATION: Duration = Duration::from_millis(2000); pub const HOMESCREEN_IMAGE_WIDTH: i16 = WIDTH; pub const HOMESCREEN_IMAGE_HEIGHT: i16 = HEIGHT; +pub const HOMESCREEN_TOIF_SIZE: i16 = 144; #[derive(Clone, Copy)] pub struct HomescreenNotification { @@ -48,7 +55,7 @@ pub struct HomescreenNotification { pub struct Homescreen { label: TString<'static>, notification: Option<(TString<'static>, u8)>, - custom_image: Option>, + image: BinaryData<'static>, hold_to_lock: bool, loader: Loader, delay: Option, @@ -67,7 +74,7 @@ impl Homescreen { Self { label, notification, - custom_image: get_user_custom_image().ok(), + image: get_homescreen_image(), hold_to_lock, loader: Loader::with_lock_icon().with_durations(LOADER_DURATION, LOADER_DURATION / 3), delay: None, @@ -185,15 +192,14 @@ impl Component for Homescreen { if self.loader.is_animating() || self.loader.is_completely_grown(Instant::now()) { self.render_loader(target); } else { - let img_data = match self.custom_image { - Some(ref img) => img.as_ref(), - None => IMAGE_HOMESCREEN, - }; - - if is_image_jpeg(img_data) { - shape::JpegImage::new(AREA.center(), img_data) + match ImageInfo::parse(self.image) { + ImageInfo::Jpeg(_) => shape::JpegImage::new_image(AREA.center(), self.image) .with_align(Alignment2D::CENTER) - .render(target); + .render(target), + ImageInfo::Toif(_) => shape::ToifImage::new_image(AREA.center(), self.image) + .with_align(Alignment2D::CENTER) + .render(target), + _ => {} } self.label.map(|t| { @@ -271,7 +277,7 @@ impl crate::trace::Trace for Homescreen { pub struct Lockscreen<'a> { label: TString<'a>, - custom_image: Option>, + image: BinaryData<'static>, bootscreen: bool, coinjoin_authorized: bool, } @@ -280,7 +286,7 @@ impl<'a> Lockscreen<'a> { pub fn new(label: TString<'a>, bootscreen: bool, coinjoin_authorized: bool) -> Self { Lockscreen { label, - custom_image: get_user_custom_image().ok(), + image: get_homescreen_image(), bootscreen, coinjoin_authorized, } @@ -306,19 +312,19 @@ impl Component for Lockscreen<'_> { } fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { - let img_data = match self.custom_image { - Some(ref img) => img.as_ref(), - None => IMAGE_HOMESCREEN, - }; + let center = AREA.center(); - let center = constant::screen().center(); - - if is_image_jpeg(img_data) { - shape::JpegImage::new(center, img_data) + match ImageInfo::parse(self.image) { + ImageInfo::Jpeg(_) => shape::JpegImage::new_image(center, self.image) .with_align(Alignment2D::CENTER) .with_blur(4) .with_dim(102) - .render(target); + .render(target), + ImageInfo::Toif(_) => shape::ToifImage::new_image(center, self.image) + .with_align(Alignment2D::CENTER) + //.with_blur(5) + .render(target), + _ => {} } shape::ToifImage::new(center, ICON_LOCKSCREEN_FILTER.toif) @@ -394,24 +400,30 @@ impl Component for Lockscreen<'_> { } } -pub fn check_homescreen_format(buffer: &[u8]) -> bool { - #[cfg(not(feature = "new_rendering"))] - let result = is_image_jpeg(buffer) && crate::ui::display::tjpgd::jpeg_test(buffer); - #[cfg(feature = "new_rendering")] - let result = is_image_jpeg(buffer); // !@# TODO: test like if `new_rendering` is off - - result +pub fn check_homescreen_format(image: BinaryData, accept_toif: bool) -> bool { + match ImageInfo::parse(image) { + ImageInfo::Jpeg(info) => { + info.width() == HOMESCREEN_IMAGE_WIDTH + && info.height() == HOMESCREEN_IMAGE_HEIGHT + && info.mcu_height() <= 16 + } + ImageInfo::Toif(info) => { + accept_toif + && info.width() == HOMESCREEN_TOIF_SIZE + && info.height() == HOMESCREEN_TOIF_SIZE + && info.format() == ToifFormat::FullColorBE + } + _ => false, + } } -fn is_image_jpeg(buffer: &[u8]) -> bool { - let jpeg = jpeg_info(buffer); - if let Some((size, mcu_height)) = jpeg { - if size.x == HOMESCREEN_IMAGE_WIDTH && size.y == HOMESCREEN_IMAGE_HEIGHT && mcu_height <= 16 - { - return true; +fn get_homescreen_image() -> BinaryData<'static> { + if let Ok(image) = get_user_custom_image() { + if check_homescreen_format(image, true) { + return image; } } - false + IMAGE_HOMESCREEN.into() } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/model_mercury/layout.rs b/core/embed/rust/src/ui/model_mercury/layout.rs index df100680ab..5e498151f0 100644 --- a/core/embed/rust/src/ui/model_mercury/layout.rs +++ b/core/embed/rust/src/ui/model_mercury/layout.rs @@ -2,9 +2,9 @@ use core::{cmp::Ordering, convert::TryInto}; use crate::{ error::Error, + io::BinaryData, micropython::{ - buffer::get_buffer, gc::Gc, iter::IterBuf, list::List, map::Map, module::Module, obj::Obj, - qstr::Qstr, util, + gc::Gc, iter::IterBuf, list::List, map::Map, module::Module, obj::Obj, qstr::Qstr, util, }, strutil::TString, translations::TR, @@ -14,7 +14,7 @@ use crate::{ base::ComponentExt, connect::Connect, image::BlendedImage, - jpeg::{ImageBuffer, Jpeg}, + jpeg::Jpeg, paginated::{PageMsg, Paginate}, text::{ op::OpTextLayout, @@ -26,7 +26,6 @@ use crate::{ }, Border, Component, Empty, FormattedText, Label, Never, Timeout, }, - display::tjpgd::jpeg_info, geometry, layout::{ obj::{ComponentMsgObj, LayoutObj}, @@ -561,15 +560,15 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?; let image: Obj = kwargs.get(Qstr::MP_QSTR_image)?; - let mut jpeg = unwrap!(ImageBuffer::from_object(image)); + let mut jpeg: BinaryData = image.try_into()?; if jpeg.is_empty() { // Incoming data may be empty, meaning we should // display default homescreen image. - jpeg = ImageBuffer::from_slice(theme::IMAGE_HOMESCREEN); + jpeg = theme::IMAGE_HOMESCREEN.into(); } - if jpeg_info(jpeg.data()).is_none() { + if !check_homescreen_format(jpeg, false) { return Err(value_error!("Invalid image.")); }; @@ -1417,9 +1416,8 @@ extern "C" fn new_show_lockscreen(n_args: usize, args: *const Obj, kwargs: *mut pub extern "C" fn upy_check_homescreen_format(data: Obj) -> Obj { let block = || { - let buffer = unsafe { get_buffer(data) }?; - - Ok(check_homescreen_format(buffer).into()) + let buffer = data.try_into()?; + Ok(check_homescreen_format(buffer, false).into()) }; unsafe { util::try_or_raise(block) } diff --git a/core/embed/rust/src/ui/shape/corner_highlight.rs b/core/embed/rust/src/ui/shape/corner_highlight.rs index f25f4ff872..2474eeb0da 100644 --- a/core/embed/rust/src/ui/shape/corner_highlight.rs +++ b/core/embed/rust/src/ui/shape/corner_highlight.rs @@ -88,7 +88,7 @@ impl CornerHighlight { } impl Shape<'_> for CornerHighlight { - fn bounds(&self, _cache: &DrawingCache) -> Rect { + fn bounds(&self) -> Rect { Rect::snap( self.pos_rect, Offset::uniform(self.length), @@ -154,9 +154,9 @@ impl Shape<'_> for CornerHighlight { } impl<'s> ShapeClone<'s> for CornerHighlight { - fn clone_at_bump<'alloc, T>(self, bump: &'alloc T) -> Option<&'alloc mut dyn Shape<'s>> + fn clone_at_bump(self, bump: &'s T) -> Option<&'s mut dyn Shape<'s>> where - T: LocalAllocLeakExt<'alloc>, + T: LocalAllocLeakExt<'s>, { let clone = bump.alloc_t::()?; Some(clone.uninit.init(CornerHighlight { ..self }))