summaryrefslogtreecommitdiff
path: root/alacritty_terminal
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal')
-rw-r--r--alacritty_terminal/src/term/color.rs61
-rw-r--r--alacritty_terminal/src/term/mod.rs21
2 files changed, 79 insertions, 3 deletions
diff --git a/alacritty_terminal/src/term/color.rs b/alacritty_terminal/src/term/color.rs
index 9aeb7061..fc35952b 100644
--- a/alacritty_terminal/src/term/color.rs
+++ b/alacritty_terminal/src/term/color.rs
@@ -25,6 +25,42 @@ pub struct Rgb {
pub b: u8,
}
+impl Rgb {
+ /// Implementation of W3C's luminance algorithm:
+ /// https://www.w3.org/TR/WCAG20/#relativeluminancedef
+ fn luminance(self) -> f64 {
+ let channel_luminance = |channel| {
+ let channel = channel as f64 / 255.;
+ if channel <= 0.03928 {
+ channel / 12.92
+ } else {
+ f64::powf((channel + 0.055) / 1.055, 2.4)
+ }
+ };
+
+ let r_luminance = channel_luminance(self.r);
+ let g_luminance = channel_luminance(self.g);
+ let b_luminance = channel_luminance(self.b);
+
+ 0.2126 * r_luminance + 0.7152 * g_luminance + 0.0722 * b_luminance
+ }
+
+ /// Implementation of W3C's contrast algorithm:
+ /// https://www.w3.org/TR/WCAG20/#contrast-ratiodef
+ pub fn contrast(self, other: Rgb) -> f64 {
+ let self_luminance = self.luminance();
+ let other_luminance = other.luminance();
+
+ let (darker, lighter) = if self_luminance > other_luminance {
+ (other_luminance, self_luminance)
+ } else {
+ (self_luminance, other_luminance)
+ };
+
+ (lighter + 0.05) / (darker + 0.05)
+ }
+}
+
// A multiply function for Rgb, as the default dim is just *2/3.
impl Mul<f32> for Rgb {
type Output = Rgb;
@@ -370,3 +406,28 @@ impl IndexMut<u8> for List {
&mut self.0[idx as usize]
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use std::f64::EPSILON;
+
+ #[test]
+ fn contrast() {
+ let rgb1 = Rgb { r: 0xff, g: 0xff, b: 0xff };
+ let rgb2 = Rgb { r: 0x00, g: 0x00, b: 0x00 };
+ assert!((rgb1.contrast(rgb2) - 21.).abs() < EPSILON);
+
+ let rgb1 = Rgb { r: 0xff, g: 0xff, b: 0xff };
+ assert!((rgb1.contrast(rgb1) - 1.).abs() < EPSILON);
+
+ let rgb1 = Rgb { r: 0xff, g: 0x00, b: 0xff };
+ let rgb2 = Rgb { r: 0x00, g: 0xff, b: 0x00 };
+ assert!((rgb1.contrast(rgb2) - 2.285_543_608_124_253_3).abs() < EPSILON);
+
+ let rgb1 = Rgb { r: 0x12, g: 0x34, b: 0x56 };
+ let rgb2 = Rgb { r: 0xfe, g: 0xdc, b: 0xba };
+ assert!((rgb1.contrast(rgb2) - 9.786_558_997_257_74).abs() < EPSILON);
+ }
+}
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index f27852de..7d00961e 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -31,6 +31,9 @@ mod search;
/// Max size of the window title stack.
const TITLE_STACK_MAX_DEPTH: usize = 4096;
+/// Minimum contrast between a fixed cursor color and the cell's background.
+const MIN_CURSOR_CONTRAST: f64 = 1.5;
+
/// Maximum number of linewraps followed outside of the viewport during search highlighting.
const MAX_SEARCH_LINES: usize = 100;
@@ -389,13 +392,19 @@ impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
if self.cursor.point.line == self.inner.line()
&& self.cursor.point.col == self.inner.column()
{
- // Handle cell below cursor.
if self.cursor.rendered {
+ // Handle cell below cursor.
let cell = self.inner.next()?;
let mut cell = RenderableCell::new(self, cell);
if self.cursor.key.style == CursorStyle::Block {
- cell.fg = self.cursor.text_color.color(cell.fg, cell.bg);
+ // Invert cursor if static background is close to the cell's background.
+ match self.cursor.cursor_color {
+ CellRgb::Rgb(col) if col.contrast(cell.bg) >= MIN_CURSOR_CONTRAST => {
+ cell.fg = self.cursor.text_color.color(cell.fg, cell.bg);
+ },
+ _ => cell.fg = cell.bg,
+ }
}
return Some(cell);
@@ -412,7 +421,13 @@ impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
let mut cell = RenderableCell::new(self, cell);
cell.inner = RenderableCellContent::Cursor(self.cursor.key);
- cell.fg = self.cursor.cursor_color.color(cell.fg, cell.bg);
+
+ // Only apply static color if it isn't close to the cell's current background.
+ if let CellRgb::Rgb(color) = self.cursor.cursor_color {
+ if color.contrast(cell.bg) >= MIN_CURSOR_CONTRAST {
+ cell.fg = self.cursor.cursor_color.color(cell.fg, cell.bg);
+ }
+ }
return Some(cell);
}