1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-19 14:08:11 +00:00

chore(core/rust): move Font and Color into their own modules

This commit is contained in:
grdddj 2023-05-04 16:08:24 +02:00 committed by Martin Milata
parent 5940129bfc
commit 1bb6288512
3 changed files with 314 additions and 287 deletions

View File

@ -0,0 +1,99 @@
use crate::ui::lerp::Lerp;
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Color(u16);
impl Color {
pub const fn from_u16(val: u16) -> Self {
Self(val)
}
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
let r = (r as u16 & 0xF8) << 8;
let g = (g as u16 & 0xFC) << 3;
let b = (b as u16 & 0xF8) >> 3;
Self(r | g | b)
}
pub const fn luminance(self) -> u32 {
(self.r() as u32 * 299) / 1000
+ (self.g() as u32 * 587) / 1000
+ (self.b() as u32 * 114) / 1000
}
pub const fn rgba(bg: Color, r: u8, g: u8, b: u8, alpha: u16) -> Self {
let r_u16 = r as u16;
let g_u16 = g as u16;
let b_u16 = b as u16;
let r = ((256 - alpha) * bg.r() as u16 + alpha * r_u16) >> 8;
let g = ((256 - alpha) * bg.g() as u16 + alpha * g_u16) >> 8;
let b = ((256 - alpha) * bg.b() as u16 + alpha * b_u16) >> 8;
let r = (r & 0xF8) << 8;
let g = (g & 0xFC) << 3;
let b = (b & 0xF8) >> 3;
Self(r | g | b)
}
pub const fn alpha(bg: Color, alpha: u16) -> Self {
Self::rgba(bg, 0xFF, 0xFF, 0xFF, alpha)
}
pub const fn r(self) -> u8 {
(self.0 >> 8) as u8 & 0xF8
}
pub const fn g(self) -> u8 {
(self.0 >> 3) as u8 & 0xFC
}
pub const fn b(self) -> u8 {
(self.0 << 3) as u8 & 0xF8
}
pub fn to_u16(self) -> u16 {
self.0
}
pub fn hi_byte(self) -> u8 {
(self.to_u16() >> 8) as u8
}
pub fn lo_byte(self) -> u8 {
(self.to_u16() & 0xFF) as u8
}
pub fn negate(self) -> Self {
Self(!self.0)
}
pub const fn white() -> Self {
Self::rgb(255, 255, 255)
}
pub const fn black() -> Self {
Self::rgb(0, 0, 0)
}
}
impl Lerp for Color {
fn lerp(a: Self, b: Self, t: f32) -> Self {
let r = u8::lerp(a.r(), b.r(), t);
let g = u8::lerp(a.g(), b.g(), t);
let b = u8::lerp(a.b(), b.b(), t);
Color::rgb(r, g, b)
}
}
impl From<u16> for Color {
fn from(val: u16) -> Self {
Self(val)
}
}
impl From<Color> for u16 {
fn from(val: Color) -> Self {
val.to_u16()
}
}

View File

@ -0,0 +1,213 @@
use crate::{
trezorhal::display,
ui::{
constant,
geometry::{Offset, Point, Rect},
},
};
use core::slice;
use super::{get_color_table, get_offset, pixeldata, set_window, Color};
pub struct Glyph {
pub width: i16,
pub height: i16,
pub adv: i16,
pub bearing_x: i16,
pub bearing_y: i16,
data: &'static [u8],
}
impl Glyph {
/// Construct a `Glyph` from a raw pointer.
///
/// # Safety
///
/// This function is unsafe because the caller has to guarantee that `data`
/// is pointing to a memory containing a valid glyph data, that is:
/// - contains valid glyph metadata
/// - data has appropriate size
/// - data must have static lifetime
pub unsafe fn load(data: *const u8) -> Self {
unsafe {
let width = *data.offset(0) as i16;
let height = *data.offset(1) as i16;
let data_bits = constant::FONT_BPP * width * height;
let data_bytes = if data_bits % 8 == 0 {
data_bits / 8
} else {
(data_bits / 8) + 1
};
Glyph {
width,
height,
adv: *data.offset(2) as i16,
bearing_x: *data.offset(3) as i16,
bearing_y: *data.offset(4) as i16,
data: slice::from_raw_parts(data.offset(5), data_bytes as usize),
}
}
}
pub fn print(&self, pos: Point, colortable: [Color; 16]) -> i16 {
let bearing = Offset::new(self.bearing_x, -self.bearing_y);
let size = Offset::new(self.width, self.height);
let pos_adj = pos + bearing;
let r = Rect::from_top_left_and_size(pos_adj, size);
let area = r.translate(get_offset());
let window = area.clamp(constant::screen());
set_window(window);
for y in window.y0..window.y1 {
for x in window.x0..window.x1 {
let p = Point::new(x, y);
let r = p - pos_adj;
let c = self.get_pixel_data(r);
pixeldata(colortable[c as usize]);
}
}
self.adv
}
pub fn unpack_bpp1(&self, a: i16) -> u8 {
let c_data = self.data[(a / 8) as usize];
((c_data >> (7 - (a % 8))) & 0x01) * 15
}
pub fn unpack_bpp2(&self, a: i16) -> u8 {
let c_data = self.data[(a / 4) as usize];
((c_data >> (6 - (a % 4) * 2)) & 0x03) * 5
}
pub fn unpack_bpp4(&self, a: i16) -> u8 {
let c_data = self.data[(a / 2) as usize];
(c_data >> (4 - (a % 2) * 4)) & 0x0F
}
pub fn unpack_bpp8(&self, a: i16) -> u8 {
let c_data = self.data[a as usize];
c_data >> 4
}
pub fn get_pixel_data(&self, p: Offset) -> u8 {
let a = p.x + p.y * self.width;
match constant::FONT_BPP {
1 => self.unpack_bpp1(a),
2 => self.unpack_bpp2(a),
4 => self.unpack_bpp4(a),
8 => self.unpack_bpp8(a),
_ => 0,
}
}
}
/// Font constants. Keep in sync with FONT_ definitions in
/// `extmod/modtrezorui/fonts/fonts.h`.
#[derive(Copy, Clone, PartialEq, Eq, FromPrimitive)]
#[repr(u8)]
pub enum Font {
NORMAL = 1,
BOLD = 2,
MONO = 3,
DEMIBOLD = 5,
}
impl From<Font> for i32 {
fn from(font: Font) -> i32 {
-(font as i32)
}
}
impl Font {
pub fn text_width(self, text: &str) -> i16 {
display::text_width(text, self.into())
}
pub fn char_width(self, ch: char) -> i16 {
display::char_width(ch, self.into())
}
pub fn text_height(self) -> i16 {
display::text_height(self.into())
}
pub fn text_max_height(self) -> i16 {
display::text_max_height(self.into())
}
pub fn text_baseline(self) -> i16 {
display::text_baseline(self.into())
}
pub fn max_height(self) -> i16 {
display::text_max_height(self.into())
}
pub fn line_height(self) -> i16 {
constant::LINE_SPACE + self.text_height()
}
pub fn get_glyph(self, char_byte: u8) -> Option<Glyph> {
let gl_data = display::get_char_glyph(char_byte, self.into());
if gl_data.is_null() {
return None;
}
// SAFETY: Glyph::load is valid for data returned by get_char_glyph
unsafe { Some(Glyph::load(gl_data)) }
}
pub fn display_text(self, text: &str, baseline: Point, fg_color: Color, bg_color: Color) {
let colortable = get_color_table(fg_color, bg_color);
let mut adv_total = 0;
for c in text.bytes() {
let g = self.get_glyph(c);
if let Some(gly) = g {
let adv = gly.print(baseline + Offset::new(adv_total, 0), colortable);
adv_total += adv;
}
}
}
/// Get the length of the longest suffix from a given `text`
/// that will fit into the area `width` pixels wide.
pub fn longest_suffix(self, width: i16, text: &str) -> usize {
let mut text_width = 0;
for (chars_from_right, c) in text.chars().rev().enumerate() {
let c_width = self.char_width(c);
if text_width + c_width > width {
// Another character cannot be fitted, we're done.
return chars_from_right;
}
text_width += c_width;
}
text.len() // it fits in its entirety
}
}
pub trait GlyphMetrics {
fn char_width(&self, ch: char) -> i16;
fn text_width(&self, text: &str) -> i16;
fn line_height(&self) -> i16;
}
impl GlyphMetrics for Font {
fn char_width(&self, ch: char) -> i16 {
Font::char_width(*self, ch)
}
fn text_width(&self, text: &str) -> i16 {
Font::text_width(*self, text)
}
fn line_height(&self) -> i16 {
Font::line_height(*self)
}
}

View File

@ -1,3 +1,5 @@
pub mod color;
pub mod font;
pub mod loader;
#[cfg(feature = "jpeg")]
pub mod tjpgd;
@ -919,290 +921,3 @@ pub fn get_color_table(fg_color: Color, bg_color: Color) -> [Color; 16] {
table
}
pub struct Glyph {
pub width: i16,
pub height: i16,
pub adv: i16,
pub bearing_x: i16,
pub bearing_y: i16,
data: &'static [u8],
}
impl Glyph {
/// Construct a `Glyph` from a raw pointer.
///
/// # Safety
///
/// This function is unsafe because the caller has to guarantee that `data`
/// is pointing to a memory containing a valid glyph data, that is:
/// - contains valid glyph metadata
/// - data has appropriate size
/// - data must have static lifetime
pub unsafe fn load(data: *const u8) -> Self {
unsafe {
let width = *data.offset(0) as i16;
let height = *data.offset(1) as i16;
let data_bits = constant::FONT_BPP * width * height;
let data_bytes = if data_bits % 8 == 0 {
data_bits / 8
} else {
(data_bits / 8) + 1
};
Glyph {
width,
height,
adv: *data.offset(2) as i16,
bearing_x: *data.offset(3) as i16,
bearing_y: *data.offset(4) as i16,
data: slice::from_raw_parts(data.offset(5), data_bytes as usize),
}
}
}
pub fn print(&self, pos: Point, colortable: [Color; 16]) -> i16 {
let bearing = Offset::new(self.bearing_x, -self.bearing_y);
let size = Offset::new(self.width, self.height);
let pos_adj = pos + bearing;
let r = Rect::from_top_left_and_size(pos_adj, size);
let area = r.translate(get_offset());
let window = area.clamp(constant::screen());
set_window(window);
for y in window.y0..window.y1 {
for x in window.x0..window.x1 {
let p = Point::new(x, y);
let r = p - pos_adj;
let c = self.get_pixel_data(r);
pixeldata(colortable[c as usize]);
}
}
self.adv
}
pub fn unpack_bpp1(&self, a: i16) -> u8 {
let c_data = self.data[(a / 8) as usize];
((c_data >> (7 - (a % 8))) & 0x01) * 15
}
pub fn unpack_bpp2(&self, a: i16) -> u8 {
let c_data = self.data[(a / 4) as usize];
((c_data >> (6 - (a % 4) * 2)) & 0x03) * 5
}
pub fn unpack_bpp4(&self, a: i16) -> u8 {
let c_data = self.data[(a / 2) as usize];
(c_data >> (4 - (a % 2) * 4)) & 0x0F
}
pub fn unpack_bpp8(&self, a: i16) -> u8 {
let c_data = self.data[a as usize];
c_data >> 4
}
pub fn get_pixel_data(&self, p: Offset) -> u8 {
let a = p.x + p.y * self.width;
match constant::FONT_BPP {
1 => self.unpack_bpp1(a),
2 => self.unpack_bpp2(a),
4 => self.unpack_bpp4(a),
8 => self.unpack_bpp8(a),
_ => 0,
}
}
}
/// Font constants. Keep in sync with FONT_ definitions in
/// `extmod/modtrezorui/fonts/fonts.h`.
#[derive(Copy, Clone, PartialEq, Eq, FromPrimitive)]
#[repr(u8)]
pub enum Font {
NORMAL = 1,
BOLD = 2,
MONO = 3,
DEMIBOLD = 5,
}
impl From<Font> for i32 {
fn from(font: Font) -> i32 {
-(font as i32)
}
}
impl Font {
pub fn text_width(self, text: &str) -> i16 {
display::text_width(text, self.into())
}
pub fn char_width(self, ch: char) -> i16 {
display::char_width(ch, self.into())
}
pub fn text_height(self) -> i16 {
display::text_height(self.into())
}
pub fn text_max_height(self) -> i16 {
display::text_max_height(self.into())
}
pub fn text_baseline(self) -> i16 {
display::text_baseline(self.into())
}
pub fn max_height(self) -> i16 {
display::text_max_height(self.into())
}
pub fn baseline(self) -> i16 {
display::text_baseline(self.into())
}
pub fn line_height(self) -> i16 {
constant::LINE_SPACE + self.text_height()
}
pub fn get_glyph(self, char_byte: u8) -> Option<Glyph> {
let gl_data = display::get_char_glyph(char_byte, self.into());
if gl_data.is_null() {
return None;
}
unsafe { Some(Glyph::load(gl_data)) }
}
pub fn display_text(self, text: &str, baseline: Point, fg_color: Color, bg_color: Color) {
let colortable = get_color_table(fg_color, bg_color);
let mut adv_total = 0;
for c in text.bytes() {
let g = self.get_glyph(c);
if let Some(gly) = g {
let adv = gly.print(baseline + Offset::new(adv_total, 0), colortable);
adv_total += adv;
}
}
}
/// Get the length of the longest suffix from a given `text`
/// that will fit into the area `width` pixels wide.
pub fn longest_suffix(self, width: i16, text: &str) -> usize {
let mut text_width = 0;
for (chars_from_right, c) in text.chars().rev().enumerate() {
let c_width = self.char_width(c);
if text_width + c_width > width {
// Another character cannot be fitted, we're done.
return chars_from_right;
}
text_width += c_width;
}
text.len() // it fits in its entirety
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct Color(u16);
#[macro_export]
macro_rules! alpha {
($n: expr) => {
if ($n >= 1.0) {
256_u16
} else {
($n * 256.0) as u16
}
};
}
impl Color {
pub const fn from_u16(val: u16) -> Self {
Self(val)
}
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
let r = (r as u16 & 0xF8) << 8;
let g = (g as u16 & 0xFC) << 3;
let b = (b as u16 & 0xF8) >> 3;
Self(r | g | b)
}
pub const fn luminance(self) -> u32 {
(self.r() as u32 * 299) / 1000
+ (self.g() as u32 * 587) / 1000
+ (self.b() as u32 * 114) / 1000
}
pub const fn rgba(bg: Color, r: u8, g: u8, b: u8, alpha: u16) -> Self {
let r_u16 = r as u16;
let g_u16 = g as u16;
let b_u16 = b as u16;
let r = ((256 - alpha) * bg.r() as u16 + alpha * r_u16) >> 8;
let g = ((256 - alpha) * bg.g() as u16 + alpha * g_u16) >> 8;
let b = ((256 - alpha) * bg.b() as u16 + alpha * b_u16) >> 8;
let r = (r & 0xF8) << 8;
let g = (g & 0xFC) << 3;
let b = (b & 0xF8) >> 3;
Self(r | g | b)
}
pub const fn alpha(bg: Color, alpha: u16) -> Self {
Self::rgba(bg, 0xFF, 0xFF, 0xFF, alpha)
}
pub const fn r(self) -> u8 {
(self.0 >> 8) as u8 & 0xF8
}
pub const fn g(self) -> u8 {
(self.0 >> 3) as u8 & 0xFC
}
pub const fn b(self) -> u8 {
(self.0 << 3) as u8 & 0xF8
}
pub fn to_u16(self) -> u16 {
self.0
}
pub fn hi_byte(self) -> u8 {
(self.to_u16() >> 8) as u8
}
pub fn lo_byte(self) -> u8 {
(self.to_u16() & 0xFF) as u8
}
pub fn negate(self) -> Self {
Self(!self.0)
}
}
impl Lerp for Color {
fn lerp(a: Self, b: Self, t: f32) -> Self {
let r = u8::lerp(a.r(), b.r(), t);
let g = u8::lerp(a.g(), b.g(), t);
let b = u8::lerp(a.b(), b.b(), t);
Color::rgb(r, g, b)
}
}
impl From<u16> for Color {
fn from(val: u16) -> Self {
Self(val)
}
}
impl From<Color> for u16 {
fn from(val: Color) -> Self {
val.to_u16()
}
}