use gpui::{Hsla, Rgba};
pub fn calculate_contrast_ratio(fg: Hsla, bg: Hsla) -> f32 {
let l1 = relative_luminance(fg);
let l2 = relative_luminance(bg);
let (lighter, darker) = if l1 > l2 { (l1, l2) } else { (l2, l1) };
(lighter + 0.05) / (darker + 0.05)
}
fn relative_luminance(color: Hsla) -> f32 {
let rgba: Rgba = color.into();
let r = linearize(rgba.r);
let g = linearize(rgba.g);
let b = linearize(rgba.b);
0.2126 * r + 0.7152 * g + 0.0722 * b
}
fn linearize(component: f32) -> f32 {
if component <= 0.03928 {
component / 12.92
} else {
((component + 0.055) / 1.055).powf(2.4)
}
}
#[cfg(test)]
mod tests {
use gpui::hsla;
use super::*;
#[test]
fn test_contrast_ratio_formula() {
let white = hsla(0.0, 0.0, 1.0, 1.0);
let black = hsla(0.0, 0.0, 0.0, 1.0);
assert!((calculate_contrast_ratio(white, black) - 21.0).abs() < 0.1);
assert!((calculate_contrast_ratio(black, white) - 21.0).abs() < 0.1);
let mid_gray = hsla(0.0, 0.0, 0.5, 1.0);
assert!((calculate_contrast_ratio(mid_gray, black) - 5.32).abs() < 0.1);
assert!((calculate_contrast_ratio(white, mid_gray) - 3.95).abs() < 0.1);
let red = hsla(0.0, 1.0, 0.5, 1.0);
assert!((calculate_contrast_ratio(red, red) - 1.0).abs() < 0.01);
}
}