feat(core): add kernings into rust drawing functions.
What changed, and why it matters
This commit adds font kerning support to Trezor's Rust-based UI text rendering. Kerning adjusts the spacing between specific pairs of characters to make text look better. There is no security issue visible in the change; it is a normal typography feature.
No security action required; review as a normal UI feature change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch extends FontInfo with a kernings table and updates text_width() and Text shape rendering to apply per-character-pair kerning offsets. The implementation is straightforward: it iterates over the kerning list and adds the matching offset when a pair is found. No memory-unsafe operations, bounds-checking bypasses, or input-validation flaws are introduced.
Changed components
core/embed/rust/src/ui/display/font.rscore/embed/rust/src/ui/shape/text.rsInspect captured patch +31 / −6
diff --git a/core/embed/rust/src/ui/display/font.rs b/core/embed/rust/src/ui/display/font.rs
index 3b19f68f..76c8b01d 100644
--- a/core/embed/rust/src/ui/display/font.rs
+++ b/core/embed/rust/src/ui/display/font.rs
@@ -21,6 +21,7 @@ pub struct FontInfo {
pub baseline: i16,
pub glyph_data: &'static [&'static [u8]],
pub glyph_nonprintable: &'static [u8],
+ pub kernings: &'static [(u8, u8, i8)],
}
/// Convenience type for font references defined in the `fonts` module.
pub type Font = &'static FontInfo;
@@ -205,12 +206,17 @@ fn calculate_glyph_size(header: &[u8]) -> usize {
impl FontInfo {
/// Supports UTF8 characters
pub fn text_width(&'static self, text: &str) -> i16 {
- self.with_glyph_data(|data| {
- text.chars().fold(0, |acc, c| {
- let char_width = data.get_glyph(c).adv;
- acc + char_width
- })
- })
+ let mut width = 0;
+ let mut prev_char: Option<char> = None;
+
+ for c in text.chars() {
+ if let Some(left) = prev_char {
+ width += self.get_kerning(left, c) as i16;
+ }
+ width += self.char_width(c);
+ prev_char = Some(c);
+ }
+ width
}
/// Width of the text that is visible.
@@ -254,6 +260,17 @@ impl FontInfo {
ascent + descent
}
+ pub fn get_kerning(&self, left_ch: char, right_ch: char) -> i8 {
+ let left: u8 = left_ch as u8;
+ let right = right_ch as u8;
+ for &(l, r, v) in self.kernings {
+ if l == left && r == right {
+ return v;
+ }
+ }
+ 0
+ }
+
/// Calculates the height of text containing both uppercase
/// and lowercase characters.
///
diff --git a/core/embed/rust/src/ui/shape/text.rs b/core/embed/rust/src/ui/shape/text.rs
index 10552870..4638603b 100644
--- a/core/embed/rust/src/ui/shape/text.rs
+++ b/core/embed/rust/src/ui/shape/text.rs
@@ -94,11 +94,17 @@ impl<'a> Shape<'_> for Text<'a> {
// TODO: optimize text clipping, use canvas.viewport()
self.font.with_glyph_data(|glyph_data| {
+ let mut prev_char: Option<char> = None;
+
for ch in self.text.chars() {
if r.x0 >= r.x1 {
break;
}
+ if let Some(left) = prev_char {
+ r.x0 += self.font.get_kerning(left, ch) as i16;
+ }
+
let glyph = glyph_data.get_glyph(ch);
let glyph_bitmap = glyph.bitmap();
let glyph_view = BitmapView::new(&glyph_bitmap)
@@ -110,7 +116,9 @@ impl<'a> Shape<'_> for Text<'a> {
));
canvas.blend_bitmap(r, glyph_view);
+
r.x0 += glyph.adv;
+ prev_char = Some(ch)
}
});
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.