use crate::color::Color;
use crate::contrast::{contrast_ratio, AA_TEXT, TEXT_ON_DARK, TEXT_ON_LIGHT};
pub fn readable_text(surface: &Color) -> Color {
let light = Color::from_hex(TEXT_ON_LIGHT).expect("constant");
let dark = Color::from_hex(TEXT_ON_DARK).expect("constant");
if contrast_ratio(surface, &light) >= contrast_ratio(surface, &dark) {
light
} else {
dark
}
}
pub fn resolve_text_token(surface: &Color, requested: &Color) -> Color {
let ratio = contrast_ratio(surface, requested);
if ratio >= AA_TEXT {
return *requested;
}
log::warn!(
"rio-theme: text {} fails AA on surface {} (ratio {:.2} < {:.1}); substituting readable fallback",
requested.to_hex(),
surface.to_hex(),
ratio,
AA_TEXT,
);
readable_text(surface)
}
#[cfg(test)]
mod tests {
use super::*;
fn c(hex: &str) -> Color {
Color::from_hex(hex).unwrap()
}
#[test]
fn near_black_surface_with_dark_gray_text_falls_back_to_light() {
let surface = c("#0a0a0a");
let bad_text = c("#222222");
let resolved = resolve_text_token(&surface, &bad_text);
assert_ne!(resolved.to_hex(), bad_text.to_hex());
assert!(contrast_ratio(&surface, &resolved) >= AA_TEXT);
}
#[test]
fn white_surface_with_dark_text_passes_through() {
let surface = c("#ffffff");
let text = c("#1a1a1a");
assert_eq!(resolve_text_token(&surface, &text).to_hex(), text.to_hex());
}
#[test]
fn readable_text_picks_higher_ratio() {
let surface = c("#ffffff");
let t = readable_text(&surface);
assert_eq!(t.to_hex(), "#1a1a1a");
}
}