summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--alacritty/src/renderer/text/builtin_font.rs201
-rw-r--r--extra/man/alacritty.5.scd3
3 files changed, 190 insertions, 15 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 51588864..c387e8a1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -45,6 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Synchronized updates now use `CSI 2026` instead of legacy `DCS` variant
- In mouse mode with `Shift` pressed, mouse bindings without `Shift` are only triggered
if no exact binding (i.e. one with `Shift`) is found.
+- Use built-in font for powerline symbols from `U+E0B0` to `U+E0B3`
### Fixed
diff --git a/alacritty/src/renderer/text/builtin_font.rs b/alacritty/src/renderer/text/builtin_font.rs
index 3934b30f..68d2fade 100644
--- a/alacritty/src/renderer/text/builtin_font.rs
+++ b/alacritty/src/renderer/text/builtin_font.rs
@@ -1,5 +1,5 @@
//! Hand-rolled drawing of unicode [box drawing](http://www.unicode.org/charts/PDF/U2500.pdf)
-//! and [block elements](https://www.unicode.org/charts/PDF/U2580.pdf).
+//! and [block elements](https://www.unicode.org/charts/PDF/U2580.pdf), and also powerline symbols.
use std::{cmp, mem, ops};
@@ -25,6 +25,8 @@ pub fn builtin_glyph(
let mut glyph = match character {
// Box drawing characters and block elements.
'\u{2500}'..='\u{259f}' => box_drawing(character, metrics, offset),
+ // Powerline symbols: '','','',''
+ '\u{e0b0}'..='\u{e0b3}' => powerline_drawing(character, metrics, offset),
_ => return None,
};
@@ -495,6 +497,125 @@ fn box_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> Raster
}
}
+fn powerline_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> RasterizedGlyph {
+ let height = (metrics.line_height as i32 + offset.y as i32) as usize;
+ let width = (metrics.average_advance as i32 + offset.x as i32) as usize;
+ // Use one eight of the cell width, since this is used as a step size for block elements.
+ let stroke_size = cmp::max((width as f32 / 8.).round() as usize, 1) as f32;
+
+ let mut canvas = Canvas::new(width, height);
+
+ let y_center = (height - 1) as f32 / 2.;
+ // Start with offset `1` and draw until the intersection of the f(x) = x + 1 and
+ // g(x) = H - x + 1 lines. The intersection happens when f(x) = g(x), which is at
+ // x = H/2 (`y_center`).
+ let from_y = 1;
+ let x_end = y_center.floor();
+ let y_end = (height - from_y - 1) as f32;
+
+ // Pick the start point outside of the canvas to even-out the start.
+ let from_x = 0.;
+ let to_x = x_end;
+ canvas.draw_line_grid(from_x, from_y as f32, to_x, y_center.floor());
+ canvas.draw_line_grid(from_x, y_end, to_x, y_center.ceil());
+
+ // For regular arrows we handle thickness by drawing 2 angle arrows and then just filling
+ // the contents between them.
+ if (character == '\u{e0b1}' || character == '\u{e0b3}') && stroke_size > 1. {
+ // The default line is of stroke size 1, so the 0.5 is computed by subtracting 1 from
+ // stroke_size and then adding 0.5 to to put the target in the center of the cell.
+ let to_x = x_end - stroke_size;
+ canvas.draw_line_grid(from_x, from_y as f32 + stroke_size, to_x, y_center.floor());
+ canvas.draw_line_grid(from_x, y_end - stroke_size, to_x, y_center.ceil());
+ }
+
+ let buffer = canvas.buffer_mut();
+ if character == '\u{e0b0}' || character == '\u{e0b2}' {
+ for row in from_y..height - from_y {
+ let row_offset = row * width;
+ for index in 1..width {
+ let index = row_offset + index;
+ if buffer[index - 1]._r > buffer[index]._r && buffer[index]._r == 0 {
+ break;
+ }
+
+ buffer[index - 1] = COLOR_FILL;
+ }
+ }
+ } else if stroke_size > 1. {
+ // Find the bottom/top most points of extra line we draw, so we can properly set the
+ // `start`.
+
+ let mut y1 = 0;
+ for row in (0..height / 2).rev() {
+ if buffer[row * width]._r != 0 {
+ y1 = row;
+ break;
+ }
+ }
+ let mut y2 = height / 2;
+ for row in height / 2..height {
+ if buffer[row * width]._r != 0 {
+ y2 = row;
+ break;
+ }
+ }
+
+ for row in from_y..height - from_y {
+ let row_offset = row * width;
+
+ // Find the point on the inner line.
+ let mut start = 0;
+ if row >= y1 && row <= y2 {
+ for base_index in 0..width - 1 {
+ let index = row_offset + base_index;
+ if buffer[index]._r != 0 {
+ start = base_index + 1;
+ break;
+ }
+ }
+ }
+
+ // Find the point on the outer line.
+ let mut end = 0;
+ for base_index in (1..width).rev() {
+ let index = row_offset + base_index;
+ if buffer[index]._r != 0 {
+ end = base_index - 1;
+ break;
+ }
+ }
+
+ if (row == y1 || row == y2) && start == end {
+ start = 0;
+ }
+
+ // Fill the canvas between inner and outer points in the row.
+ for index in start..=end {
+ let index = row_offset + index;
+ buffer[index] = COLOR_FILL;
+ }
+ }
+ }
+
+ // Some glyphs are just flipped versions of others, so just flip them.
+ if character == '\u{e0b2}' || character == '\u{e0b3}' {
+ canvas.flip_horizontal();
+ }
+
+ let top = height as i32 + metrics.descent as i32;
+ let buffer = BitmapBuffer::Rgb(canvas.into_raw());
+ RasterizedGlyph {
+ character,
+ top,
+ left: 0,
+ height: height as i32,
+ width: width as i32,
+ buffer,
+ advance: (width as i32, height as i32),
+ }
+}
+
#[repr(packed)]
#[derive(Clone, Copy, Debug, Default)]
struct Pixel {
@@ -593,6 +714,16 @@ impl Canvas {
(start_x, end_x)
}
+ /// Flip horizontally.
+ fn flip_horizontal(&mut self) {
+ for row in 0..self.height {
+ for col in 0..self.width / 2 {
+ let index = row * self.width;
+ self.buffer.swap(index + col, index + self.width - col - 1)
+ }
+ }
+ }
+
/// Draws a horizontal straight line from (`x`, `y`) of `size` with the given `stroke_size`.
fn draw_h_line(&mut self, x: f32, y: f32, size: f32, stroke_size: usize) {
let (start_y, end_y) = self.h_line_bounds(y, stroke_size);
@@ -700,6 +831,33 @@ impl Canvas {
}
}
+ /// WalkGrid line drawing from (`from_x`, `from_y`) to (`to_x`, `to_y`).
+ fn draw_line_grid(&mut self, from_x: f32, from_y: f32, to_x: f32, to_y: f32) {
+ let dx = (to_x - from_x).trunc();
+ let nx = dx.abs();
+
+ let dy = (to_y - from_y).trunc();
+ let ny = dy.abs();
+
+ let sign_x = dx.signum();
+ let sign_y = dy.signum();
+
+ let mut point = (from_x.trunc(), from_y.trunc());
+ let mut ix = 0.;
+ let mut iy = 0.;
+ while ix <= nx && iy <= ny {
+ self.put_pixel(point.0, point.1, COLOR_FILL);
+
+ if (0.5 + ix) / nx < (0.5 + iy) / ny {
+ point.0 += sign_x;
+ ix += 1.;
+ } else {
+ point.1 += sign_y;
+ iy += 1.;
+ }
+ }
+ }
+
/// Draws a part of an ellipse centered in `(0., 0.)` with `self.x_center()` and `self.y_center`
/// vertex and co-vertex respectively using a given `stroke` in the bottom-right quadrant of the
/// `Canvas` coordinate system.
@@ -807,29 +965,44 @@ mod tests {
use super::*;
use crossfont::Metrics;
+ // Dummy metrics values to test builtin glyphs coverage.
+ const METRICS: Metrics = Metrics {
+ average_advance: 6.,
+ line_height: 16.,
+ descent: 4.,
+ underline_position: 2.,
+ underline_thickness: 2.,
+ strikeout_position: 2.,
+ strikeout_thickness: 2.,
+ };
+
#[test]
fn builtin_line_drawing_glyphs_coverage() {
- // Dummy metrics values to test built-in glyphs coverage.
- let metrics = Metrics {
- average_advance: 6.,
- line_height: 16.,
- descent: 4.,
- underline_position: 2.,
- underline_thickness: 2.,
- strikeout_position: 2.,
- strikeout_thickness: 2.,
- };
-
let offset = Default::default();
let glyph_offset = Default::default();
// Test coverage of box drawing characters.
for character in '\u{2500}'..='\u{259f}' {
- assert!(builtin_glyph(character, &metrics, &offset, &glyph_offset).is_some());
+ assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_some());
}
for character in ('\u{2450}'..'\u{2500}').chain('\u{25a0}'..'\u{2600}') {
- assert!(builtin_glyph(character, &metrics, &offset, &glyph_offset).is_none());
+ assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_none());
+ }
+ }
+
+ #[test]
+ fn builtin_powerline_glyphs_coverage() {
+ let offset = Default::default();
+ let glyph_offset = Default::default();
+
+ // Test coverage of box drawing characters.
+ for character in '\u{e0b0}'..='\u{e0b3}' {
+ assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_some());
+ }
+
+ for character in ('\u{e0a0}'..'\u{e0b0}').chain('\u{e0b4}'..'\u{e0c0}') {
+ assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_none());
}
}
}
diff --git a/extra/man/alacritty.5.scd b/extra/man/alacritty.5.scd
index 0d4c28cf..9ca82e5f 100644
--- a/extra/man/alacritty.5.scd
+++ b/extra/man/alacritty.5.scd
@@ -256,7 +256,8 @@ macOS: _{ family = "Menlo", style = "Regular" }_
*builtin_box_drawing* <boolean>
When _true_, Alacritty will use a custom built-in font for box drawing
- characters (Unicode points _U+2500_ - _U+259f_).
+ characters (Unicode points _U+2500_ - _U+259F_) and powerline symbols
+ (Unicode points _U+E0B0_ - _U+E0B3_).
Default: _true_