perf(core/rust): parse Toif metadata on demand

[no changelog]
pull/2742/head
Martin Milata 1 year ago
parent 194868438a
commit 0df81b18e3

@ -289,7 +289,6 @@ fn generate_trezorhal_bindings() {
.allowlist_function("display_bar_radius")
.allowlist_function("display_bar_radius_buffer")
.allowlist_function("display_image")
.allowlist_function("display_toif_info")
.allowlist_function("display_loader")
.allowlist_function("display_pixeldata")
.allowlist_function("display_pixeldata_dirty")

@ -1,7 +1,6 @@
use super::ffi;
use core::ptr;
use cty::c_int;
use num_traits::FromPrimitive;
use crate::trezorhal::buffers::BufferText;
@ -13,12 +12,6 @@ pub enum ToifFormat {
GrayScaleEH = ffi::toif_format_t_TOIF_GRAYSCALE_EH as _,
}
pub struct ToifInfo {
pub width: u16,
pub height: u16,
pub format: ToifFormat,
}
pub fn backlight(val: i32) -> i32 {
unsafe { ffi::display_backlight(val) }
}
@ -116,31 +109,6 @@ pub fn image(x: i16, y: i16, w: i16, h: i16, data: &[u8]) {
}
}
pub fn toif_info(data: &[u8]) -> Result<ToifInfo, ()> {
let mut width: cty::uint16_t = 0;
let mut height: cty::uint16_t = 0;
let mut format: ffi::toif_format_t = ffi::toif_format_t_TOIF_FULL_COLOR_BE;
if unsafe {
ffi::display_toif_info(
data.as_ptr() as _,
data.len() as _,
&mut width,
&mut height,
&mut format,
)
} {
let format = ToifFormat::from_usize(format as usize).unwrap_or(ToifFormat::FullColorBE);
Ok(ToifInfo {
width,
height,
format,
})
} else {
Err(())
}
}
pub fn loader(
progress: u16,
indeterminate: bool,

@ -16,8 +16,8 @@ pub struct Image {
impl Image {
pub fn new(data: &'static [u8]) -> Self {
let toif = Toif::new(data);
assert!(toif.format == ToifFormat::FullColorLE);
let toif = unwrap!(Toif::new(data));
assert!(toif.format() == ToifFormat::FullColorLE);
Self {
toif,
area: Rect::zero(),
@ -27,8 +27,8 @@ impl Image {
/// Display the icon with baseline Point, aligned according to the
/// `alignment` argument.
pub fn draw(&self, baseline: Point, alignment: Alignment2D) {
let r = Rect::snap(baseline, self.toif.size, alignment);
image(r.x0, r.y0, r.width(), r.height(), self.toif.data);
let r = Rect::snap(baseline, self.toif.size(), alignment);
image(r.x0, r.y0, r.width(), r.height(), self.toif.zdata());
}
}
@ -51,7 +51,7 @@ impl Component for Image {
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
sink(Rect::from_center_and_size(
self.area.center(),
self.toif.size,
self.toif.size(),
));
}
}
@ -101,12 +101,12 @@ impl Component for BlendedImage {
type Msg = Never;
fn place(&mut self, bounds: Rect) -> Rect {
self.bg_top_left = self.bg.toif.size.snap(bounds.center(), CENTER);
self.bg_top_left = self.bg.toif.size().snap(bounds.center(), CENTER);
let ft_top_left = self.fg.toif.size.snap(bounds.center(), CENTER);
let ft_top_left = self.fg.toif.size().snap(bounds.center(), CENTER);
self.fg_offset = ft_top_left - self.bg_top_left;
Rect::from_top_left_and_size(self.bg_top_left, self.bg.toif.size)
Rect::from_top_left_and_size(self.bg_top_left, self.bg.toif.size())
}
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
@ -120,7 +120,7 @@ impl Component for BlendedImage {
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
sink(Rect::from_top_left_and_size(
self.bg_top_left,
self.bg.toif.size,
self.bg.toif.size(),
));
}
}

@ -43,10 +43,11 @@ pub fn loader_uncompress(
const ICON_MAX_SIZE: i16 = constant::LOADER_ICON_MAX_SIZE;
if let Some((icon, color)) = icon {
if icon.toif.width() <= ICON_MAX_SIZE && icon.toif.height() <= ICON_MAX_SIZE {
let toif_size = icon.toif.size();
if toif_size.x <= ICON_MAX_SIZE && toif_size.y <= ICON_MAX_SIZE {
let mut icon_data = [0_u8; ((ICON_MAX_SIZE * ICON_MAX_SIZE) / 2) as usize];
icon.toif.uncompress(&mut icon_data);
let i = Some((icon, color, icon.toif.size));
let i = Some((icon, color, toif_size));
loader_rust(y_offset, fg_color, bg_color, progress, indeterminate, i);
} else {
loader_rust(y_offset, fg_color, bg_color, progress, indeterminate, None);
@ -237,7 +238,7 @@ pub fn loader_rust(
let x_i = x_c - icon_area.x0;
let y_i = y_c - icon_area.y0;
let data = unwrap!(icon_data).data()
let data = unwrap!(icon_data).zdata()
[(((x_i & 0xFE) + (y_i * icon_width)) / 2) as usize];
if (x_i & 0x01) == 0 {
underlying_color = icon_colortable[(data & 0xF) as usize];
@ -337,7 +338,7 @@ pub fn loader_rust(
icon_buffer_used.buffer[icon_offset as usize..(icon_offset + icon_width / 2) as usize]
.copy_from_slice(
&unwrap!(icon_data).toif.data[(y_i * (icon_width / 2)) as usize
&unwrap!(icon_data).toif.zdata()[(y_i * (icon_width / 2)) as usize
..((y_i + 1) * (icon_width / 2)) as usize],
);
icon_buffer = icon_buffer_used;

@ -24,11 +24,10 @@ use crate::{
error::Error,
time::Duration,
trezorhal::{display, qr, time, uzlib::UzlibContext},
ui::lerp::Lerp,
ui::{component::image::Image, lerp::Lerp},
};
use core::slice;
use crate::ui::component::image::Image;
pub use crate::ui::display::toif::Icon;
#[cfg(any(feature = "model_tt", feature = "model_tr"))]
pub use loader::{loader, loader_indeterminate, LOADER_MAX, LOADER_MIN};
@ -228,8 +227,9 @@ pub fn rect_rounded2_partial(
let mut icon_width = 0;
if let Some((icon, icon_color)) = icon {
if icon.toif.width() <= MAX_ICON_SIZE && icon.toif.height() <= MAX_ICON_SIZE {
icon_area = Rect::from_center_and_size(center, icon.toif.size);
let icon_size = icon.toif.size();
if icon_size.x <= MAX_ICON_SIZE && icon_size.y <= MAX_ICON_SIZE {
icon_area = Rect::from_center_and_size(center, icon_size);
icon_area_clamped = icon_area.clamp(constant::screen());
icon.toif.uncompress(&mut icon_data);
icon_colortable = get_color_table(icon_color, bg_color);
@ -461,10 +461,10 @@ pub fn text_over_image(
empty_img.buffer.copy_from_slice(&img1.buffer);
area = a;
r_img = Rect::from_top_left_and_size(a.top_left() + offset_img, image.toif.size);
r_img = Rect::from_top_left_and_size(a.top_left() + offset_img, image.toif.size());
offset_img_final = offset_img;
} else {
area = Rect::from_top_left_and_size(offset_img.into(), image.toif.size);
area = Rect::from_top_left_and_size(offset_img.into(), image.toif.size());
r_img = area;
offset_img_final = Offset::zero();
}
@ -583,26 +583,26 @@ pub fn icon_over_icon(
let final_offset_bg;
if let Some(a) = bg_area {
area = a;
r_bg = Rect::from_top_left_and_size(a.top_left() + offset_bg, icon_bg.toif.size);
r_bg = Rect::from_top_left_and_size(a.top_left() + offset_bg, icon_bg.toif.size());
final_offset_bg = offset_bg;
} else {
r_bg =
Rect::from_top_left_and_size(Point::new(offset_bg.x, offset_bg.y), icon_bg.toif.size);
Rect::from_top_left_and_size(Point::new(offset_bg.x, offset_bg.y), icon_bg.toif.size());
area = r_bg;
final_offset_bg = Offset::zero();
}
let r_fg = Rect::from_top_left_and_size(area.top_left() + offset_fg, icon_fg.toif.size);
let r_fg = Rect::from_top_left_and_size(area.top_left() + offset_fg, icon_fg.toif.size());
let clamped = area.clamp(constant::screen()).ensure_even_width();
set_window(clamped);
let mut window_bg = [0; UZLIB_WINDOW_SIZE];
let mut ctx_bg = UzlibContext::new(icon_bg.toif.data, Some(&mut window_bg));
let mut ctx_bg = UzlibContext::new(icon_bg.toif.zdata(), Some(&mut window_bg));
let mut window_fg = [0; UZLIB_WINDOW_SIZE];
let mut ctx_fg = UzlibContext::new(icon_fg.toif.data, Some(&mut window_fg));
let mut ctx_fg = UzlibContext::new(icon_fg.toif.zdata(), Some(&mut window_fg));
dma2d_setup_4bpp_over_4bpp(color_icon_bg.into(), bg_color.into(), color_icon_fg.into());

@ -1,5 +1,4 @@
use crate::{
trezorhal,
trezorhal::{
display::ToifFormat,
uzlib::{UzlibContext, UZLIB_WINDOW_SIZE},
@ -15,22 +14,8 @@ use super::Color;
const TOIF_HEADER_LENGTH: usize = 12;
pub fn toif_info(data: &[u8]) -> Option<(Offset, ToifFormat)> {
if let Ok(info) = trezorhal::display::toif_info(data) {
Some((
Offset::new(
unwrap!(info.width.try_into()),
unwrap!(info.height.try_into()),
),
info.format,
))
} else {
None
}
}
pub fn icon(icon: &Icon, center: Point, fg_color: Color, bg_color: Color) {
let r = Rect::from_center_and_size(center, icon.toif.size);
let r = Rect::from_center_and_size(center, icon.toif.size());
let area = r.translate(get_offset());
let clamped = area.clamp(constant::screen());
let colortable = get_color_table(fg_color, bg_color);
@ -65,29 +50,49 @@ pub fn icon(icon: &Icon, center: Point, fg_color: Color, bg_color: Color) {
}
/// Holding toif data and allowing it to draw itself.
/// See https://docs.trezor.io/trezor-firmware/misc/toif.html for data format.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Toif {
pub data: &'static [u8],
pub size: Offset,
pub format: ToifFormat,
data: &'static [u8],
}
impl Toif {
pub fn new(data: &'static [u8]) -> Self {
let info = unwrap!(toif_info(data));
Self {
data: data[TOIF_HEADER_LENGTH..].as_ref(),
size: info.0,
format: info.1,
pub const fn new(data: &'static [u8]) -> Option<Self> {
if data.len() < TOIF_HEADER_LENGTH || data[0] != b'T' || data[1] != b'O' || data[2] != b'I'
{
return None;
}
let zdatalen = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize;
if zdatalen + TOIF_HEADER_LENGTH != data.len() {
return None;
}
Some(Self { data })
}
pub const fn format(&self) -> ToifFormat {
match self.data[3] {
b'f' => ToifFormat::FullColorBE,
b'g' => ToifFormat::GrayScaleOH,
b'F' => ToifFormat::FullColorLE,
b'G' => ToifFormat::GrayScaleEH,
_ => panic!(),
}
}
pub fn width(&self) -> i16 {
self.size.x
pub const fn width(&self) -> i16 {
u16::from_le_bytes([self.data[4], self.data[5]]) as i16
}
pub const fn height(&self) -> i16 {
u16::from_le_bytes([self.data[6], self.data[7]]) as i16
}
pub const fn size(&self) -> Offset {
Offset::new(self.width(), self.height())
}
pub fn height(&self) -> i16 {
self.size.y
pub fn zdata(&self) -> &'static [u8] {
&self.data[TOIF_HEADER_LENGTH..]
}
pub fn uncompress(&self, dest: &mut [u8]) {
@ -99,7 +104,7 @@ impl Toif {
&'a self,
window: Option<&'a mut [u8; UZLIB_WINDOW_SIZE]>,
) -> UzlibContext {
UzlibContext::new(self.data, window)
UzlibContext::new(self.zdata(), window)
}
}
@ -110,15 +115,15 @@ pub struct Icon {
impl Icon {
pub fn new(data: &'static [u8]) -> Self {
let toif = Toif::new(data);
assert!(toif.format == ToifFormat::GrayScaleEH);
let toif = unwrap!(Toif::new(data));
assert!(toif.format() == ToifFormat::GrayScaleEH);
Self { toif }
}
/// Display the icon with baseline Point, aligned according to the
/// `alignment` argument.
pub fn draw(&self, baseline: Point, alignment: Alignment2D, fg_color: Color, bg_color: Color) {
let r = Rect::snap(baseline, self.toif.size, alignment);
let r = Rect::snap(baseline, self.toif.size(), alignment);
icon(self, r.center(), fg_color, bg_color);
}
}

@ -131,10 +131,11 @@ fn homescreen_position_text(
let text_width_clamped = text_width.clamp(0, screen().width());
let icon_size = if let Some(icon) = text.icon {
assert!(icon.toif.width() <= HOMESCREEN_MAX_ICON_SIZE);
assert!(icon.toif.height() <= HOMESCREEN_MAX_ICON_SIZE);
let size = icon.toif.size();
assert!(size.x <= HOMESCREEN_MAX_ICON_SIZE);
assert!(size.y <= HOMESCREEN_MAX_ICON_SIZE);
icon.toif.uncompress(icon_buffer);
icon.toif.size
size
} else {
Offset::zero()
};

Loading…
Cancel
Save