use super::FontRegistry;
#[derive(Debug, Clone)]
pub struct FontRun {
pub start: usize,
pub end: usize,
pub family: String,
}
pub fn segment_by_font(
chars: &[char],
families: &str,
weight: u32,
italic: bool,
registry: &FontRegistry,
) -> Vec<FontRun> {
if chars.is_empty() {
return vec![];
}
if !families.contains(',') {
let family = families.trim().trim_matches('"').trim_matches('\'');
let font = registry.resolve(family, weight, italic);
let all_covered = chars
.iter()
.all(|&ch| ch.is_whitespace() || font.has_char(ch));
if all_covered {
return vec![FontRun {
start: 0,
end: chars.len(),
family: family.to_string(),
}];
}
}
let mut runs = Vec::new();
let (_, first_family) = registry.resolve_for_char(families, chars[0], weight, italic);
let mut current_family = first_family;
let mut run_start = 0;
for (i, &ch) in chars.iter().enumerate().skip(1) {
let (_, family) = registry.resolve_for_char(families, ch, weight, italic);
if family != current_family {
runs.push(FontRun {
start: run_start,
end: i,
family: current_family,
});
current_family = family;
run_start = i;
}
}
runs.push(FontRun {
start: run_start,
end: chars.len(),
family: current_family,
});
runs
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_single_font_fast_path() {
let registry = FontRegistry::new();
let chars: Vec<char> = "Hello world".chars().collect();
let runs = segment_by_font(&chars, "Helvetica", 400, false, ®istry);
assert_eq!(runs.len(), 1);
assert_eq!(runs[0].family, "Helvetica");
assert_eq!(runs[0].start, 0);
assert_eq!(runs[0].end, 11);
}
#[test]
fn test_empty_input() {
let registry = FontRegistry::new();
let chars: Vec<char> = vec![];
let runs = segment_by_font(&chars, "Helvetica, Times", 400, false, ®istry);
assert!(runs.is_empty());
}
#[test]
fn test_single_font_builtin_fallback() {
let registry = FontRegistry::new();
let chars: Vec<char> = "\u{041F}\u{0440}\u{0438}\u{0432}\u{0435}\u{0442}"
.chars()
.collect();
let runs = segment_by_font(&chars, "Helvetica", 400, false, ®istry);
assert!(runs.len() >= 1, "Should produce at least one run");
assert_eq!(runs[0].family, "Noto Sans", "Cyrillic should use Noto Sans");
}
#[test]
fn test_single_font_mixed_latin_cyrillic() {
let registry = FontRegistry::new();
let chars: Vec<char> = "Hi \u{041F}".chars().collect();
let runs = segment_by_font(&chars, "Helvetica", 400, false, ®istry);
assert!(
runs.len() >= 2,
"Should have at least 2 runs (Latin + Cyrillic), got {}",
runs.len()
);
}
#[test]
fn test_all_chars_same_font() {
let registry = FontRegistry::new();
let chars: Vec<char> = "ABC".chars().collect();
let runs = segment_by_font(&chars, "Helvetica, Times", 400, false, ®istry);
assert_eq!(runs.len(), 1);
assert_eq!(runs[0].family, "Helvetica");
}
}