use crate::span::Style;
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct FontMetrics {
pub line_height: u32,
pub ascent: u32,
pub space_width: u32,
}
impl Default for FontMetrics {
fn default() -> Self {
FontMetrics {
line_height: 16,
ascent: 12,
space_width: 8,
}
}
}
pub trait TextMeasure {
fn metrics(&self) -> FontMetrics;
fn run_width(&self, text: &str, style: Style) -> u32;
fn fit_prefix(&self, text: &str, style: Style, max_width: u32) -> (usize, u32) {
if text.is_empty() {
return (0, 0);
}
let full = self.run_width(text, style);
if full <= max_width {
return (text.len(), full);
}
let mut lo = 0usize;
let mut hi = text.len();
let mut best = (0usize, 0u32);
while lo < hi {
let mut mid = lo + (hi - lo) / 2;
while mid > lo && !text.is_char_boundary(mid) {
mid -= 1;
}
if mid == lo {
break;
}
let w = self.run_width(&text[..mid], style);
if w <= max_width {
best = (mid, w);
lo = mid;
} else {
hi = mid;
}
}
best
}
fn image_size(&self, intrinsic: (u32, u32), max_width: u32) -> (u32, u32) {
let (w, h) = intrinsic;
if w == 0 || h == 0 {
return (0, 0);
}
if w <= max_width {
return (w, h);
}
let scaled_h = ((h as u64 * max_width as u64) / w as u64) as u32;
(max_width, scaled_h.max(1))
}
}
#[derive(Clone, Copy, Debug)]
pub struct FixedMeasure {
pub char_width: u32,
pub metrics: FontMetrics,
}
impl FixedMeasure {
pub fn new(char_width: u32) -> FixedMeasure {
FixedMeasure {
char_width,
metrics: FontMetrics {
line_height: 16,
ascent: 12,
space_width: char_width,
},
}
}
}
impl Default for FixedMeasure {
fn default() -> Self {
FixedMeasure::new(8)
}
}
impl TextMeasure for FixedMeasure {
fn metrics(&self) -> FontMetrics {
self.metrics
}
fn run_width(&self, text: &str, _style: Style) -> u32 {
(text.chars().count() as u32) * self.char_width
}
}