mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-17 13:38:46 +00:00
fix(core/ui): fix char boundary bug in Rust layout
This commit is contained in:
parent
ccf364f1da
commit
fce188fb96
@ -158,7 +158,7 @@ fn select_line_breaks(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
trait GlyphMetrics {
|
pub trait GlyphMetrics {
|
||||||
fn char_width(&self, ch: char) -> i32;
|
fn char_width(&self, ch: char) -> i32;
|
||||||
fn line_height(&self) -> i32;
|
fn line_height(&self) -> i32;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::iter::GlyphMetrics;
|
||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
display,
|
display,
|
||||||
display::{Color, Font},
|
display::{Color, Font},
|
||||||
@ -380,6 +381,7 @@ impl<'a> Op<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
struct Span {
|
struct Span {
|
||||||
/// How many characters from the input text this span is laying out.
|
/// How many characters from the input text this span is laying out.
|
||||||
length: usize,
|
length: usize,
|
||||||
@ -398,8 +400,8 @@ impl Span {
|
|||||||
fn fit_horizontally(
|
fn fit_horizontally(
|
||||||
text: &str,
|
text: &str,
|
||||||
max_width: i32,
|
max_width: i32,
|
||||||
text_font: Font,
|
text_font: impl GlyphMetrics,
|
||||||
hyphen_font: Font,
|
hyphen_font: impl GlyphMetrics,
|
||||||
breaking: LineBreaking,
|
breaking: LineBreaking,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
const ASCII_LF: char = '\n';
|
const ASCII_LF: char = '\n';
|
||||||
@ -427,7 +429,10 @@ impl Span {
|
|||||||
let mut span_width = 0;
|
let mut span_width = 0;
|
||||||
let mut found_any_whitespace = false;
|
let mut found_any_whitespace = false;
|
||||||
|
|
||||||
for (i, ch) in text.char_indices() {
|
let mut char_indices_iter = text.char_indices().peekable();
|
||||||
|
// Iterating manually because we need a reference to the iterator inside the
|
||||||
|
// loop.
|
||||||
|
while let Some((i, ch)) = char_indices_iter.next() {
|
||||||
let char_width = text_font.char_width(ch);
|
let char_width = text_font.char_width(ch);
|
||||||
|
|
||||||
// Consider if we could be breaking the line at this position.
|
// Consider if we could be breaking the line at this position.
|
||||||
@ -456,7 +461,10 @@ impl Span {
|
|||||||
|| !found_any_whitespace;
|
|| !found_any_whitespace;
|
||||||
if have_space_for_break && can_break_word {
|
if have_space_for_break && can_break_word {
|
||||||
// Break after this character, append hyphen.
|
// Break after this character, append hyphen.
|
||||||
line.length = i + 1;
|
line.length = match char_indices_iter.peek() {
|
||||||
|
Some((idx, _)) => *idx,
|
||||||
|
None => text.len(),
|
||||||
|
};
|
||||||
line.advance.x = span_width + char_width;
|
line.advance.x = span_width + char_width;
|
||||||
line.insert_hyphen_before_line_break = true;
|
line.insert_hyphen_before_line_break = true;
|
||||||
line.skip_next_chars = 0;
|
line.skip_next_chars = 0;
|
||||||
@ -475,3 +483,98 @@ impl Span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct Fixed {
|
||||||
|
pub width: i32,
|
||||||
|
pub height: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlyphMetrics for Fixed {
|
||||||
|
fn char_width(&self, _ch: char) -> i32 {
|
||||||
|
self.width
|
||||||
|
}
|
||||||
|
|
||||||
|
fn line_height(&self) -> i32 {
|
||||||
|
self.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FIXED_FONT: Fixed = Fixed {
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_span() {
|
||||||
|
assert_eq!(spans_from("hello", 5), vec![("hello", false)]);
|
||||||
|
assert_eq!(spans_from("", 5), vec![("", false)]);
|
||||||
|
assert_eq!(
|
||||||
|
spans_from("hello world", 5),
|
||||||
|
vec![("hello", false), ("world", false)]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
spans_from("hello\nworld", 5),
|
||||||
|
vec![("hello", false), ("world", false)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_leading_trailing() {
|
||||||
|
assert_eq!(
|
||||||
|
spans_from("\nhello\nworld\n", 5),
|
||||||
|
vec![("", false), ("hello", false), ("world", false), ("", false)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_long_word() {
|
||||||
|
assert_eq!(
|
||||||
|
spans_from("Down with the establishment!", 5),
|
||||||
|
vec![
|
||||||
|
("Down", false),
|
||||||
|
("with", false),
|
||||||
|
("the", false),
|
||||||
|
("esta", true),
|
||||||
|
("blis", true),
|
||||||
|
("hmen", true),
|
||||||
|
("t!", false),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_char_boundary() {
|
||||||
|
assert_eq!(
|
||||||
|
spans_from("+ěščřžýáíé", 5),
|
||||||
|
vec![("+ěšč", true), ("řžýá", true), ("íé", false)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spans_from(text: &str, max_width: i32) -> Vec<(&str, bool)> {
|
||||||
|
let mut spans = vec![];
|
||||||
|
let mut remaining_text = text;
|
||||||
|
loop {
|
||||||
|
let span = Span::fit_horizontally(
|
||||||
|
remaining_text,
|
||||||
|
max_width,
|
||||||
|
FIXED_FONT,
|
||||||
|
FIXED_FONT,
|
||||||
|
LineBreaking::BreakAtWhitespace,
|
||||||
|
);
|
||||||
|
spans.push((
|
||||||
|
&remaining_text[..span.length],
|
||||||
|
span.insert_hyphen_before_line_break,
|
||||||
|
));
|
||||||
|
remaining_text = &remaining_text[span.length + span.skip_next_chars..];
|
||||||
|
if remaining_text.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spans
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@ use core::ops::{Add, Sub};
|
|||||||
/// Relative offset in 2D space, used for representing translation and
|
/// Relative offset in 2D space, used for representing translation and
|
||||||
/// dimensions of objects. Absolute positions on the screen are represented by
|
/// dimensions of objects. Absolute positions on the screen are represented by
|
||||||
/// the `Point` type.
|
/// the `Point` type.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Offset {
|
pub struct Offset {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32,
|
pub y: i32,
|
||||||
|
Loading…
Reference in New Issue
Block a user