Skip to content

Commit

Permalink
Use cell width to compute builtin font thickness
Browse files Browse the repository at this point in the history
While using underline thickness could sound logical to draw other
lines most fonts don't make underlines thick compared to cell bounding
box if you increase font size. So instead we're using cell width to
scale builtin font nicely.

This commit also adjusts arcs drawing and alignment.

Fixes alacritty#5826.
Fixes alacritty#5821.
  • Loading branch information
kchibisov authored Jan 30, 2022
1 parent efae2cc commit 5459492
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed

- The `--help` output was reworked with a new colorful syntax
- Builtin font thickness is now based on cell width instead of underline thickness

### Fixed

Expand All @@ -26,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- OSC 104 not clearing colors when second parameter is empty
- Builtin font lines not contiguous when `font.offset` is used
- `font.glyph_offset` is no longer applied on builtin font
- Buili-in font arcs alignment

## 0.10.0

Expand Down
60 changes: 53 additions & 7 deletions alacritty/src/renderer/builtin_font.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! 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).

use std::{cmp, mem};
use std::{cmp, mem, ops};

use crossfont::{BitmapBuffer, Metrics, RasterizedGlyph};

Expand Down Expand Up @@ -39,8 +39,10 @@ pub fn builtin_glyph(
fn box_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;
let stroke_size = cmp::max(metrics.underline_thickness as usize, 1);
let heavy_stroke_size = stroke_size * 3;
// Use one eight of the cell width, since this is used as a step size for block elemenets.
let stroke_size = cmp::max((width as f32 / 8.).round() as usize, 1);
let heavy_stroke_size = stroke_size * 2;

// Certain symbols require larger canvas than the cell itself, since for proper contiguous
// lines they require drawing on neighbour cells. So treat them specially early on and handle
// 'normal' characters later.
Expand All @@ -66,7 +68,7 @@ fn box_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> Raster

let from_x = 0.;
let to_x = x_end + 1.;
for stroke_size in stroke_size..2 * stroke_size {
for stroke_size in 0..2 * stroke_size {
let stroke_size = stroke_size as f32 / 2.;
if character == '\u{2571}' || character == '\u{2573}' {
let h = y_end - stroke_size as f32;
Expand Down Expand Up @@ -341,7 +343,9 @@ fn box_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> Raster
// Mirror `X` axis.
if character == '\u{256d}' || character == '\u{2570}' {
let center = canvas.x_center() as usize;
let extra_offset = if width % 2 == 0 { 1 } else { 0 };

let extra_offset = if stroke_size % 2 == width % 2 { 0 } else { 1 };

let buffer = canvas.buffer_mut();
for y in 1..height {
let left = (y - 1) * width;
Expand All @@ -357,7 +361,9 @@ fn box_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> Raster
// Mirror `Y` axis.
if character == '\u{256d}' || character == '\u{256e}' {
let center = canvas.y_center() as usize;
let extra_offset = if height % 2 == 0 { 1 } else { 0 };

let extra_offset = if stroke_size % 2 == height % 2 { 0 } else { 1 };

let buffer = canvas.buffer_mut();
if extra_offset != 0 {
let bottom_row = (height - 1) * width;
Expand Down Expand Up @@ -483,6 +489,28 @@ impl Pixel {
}
}

impl ops::Add for Pixel {
type Output = Pixel;

fn add(self, rhs: Pixel) -> Self::Output {
let _r = self._r.saturating_add(rhs._r);
let _g = self._g.saturating_add(rhs._g);
let _b = self._b.saturating_add(rhs._b);
Pixel { _r, _g, _b }
}
}

impl ops::Div<u8> for Pixel {
type Output = Pixel;

fn div(self, rhs: u8) -> Self::Output {
let _r = self._r / rhs;
let _g = self._g / rhs;
let _b = self._b / rhs;
Pixel { _r, _g, _b }
}
}

/// Canvas which is used for simple line drawing operations.
///
/// The coordinate system is the following:
Expand Down Expand Up @@ -716,6 +744,24 @@ impl Canvas {
// Ensure the part closer to edges is properly filled.
self.draw_h_line(0., self.y_center(), stroke_size as f32, stroke_size);
self.draw_v_line(self.x_center(), 0., stroke_size as f32, stroke_size);

// Fill the resulted arc, since it could have gaps in-between.
for y in 0..self.height {
let row = y * self.width;
let left = match self.buffer[row..row + self.width].iter().position(|p| p._r != 0) {
Some(left) => row + left,
_ => continue,
};
let right = match self.buffer[row..row + self.width].iter().rposition(|p| p._r != 0) {
Some(right) => row + right,
_ => continue,
};

for index in left + 1..right {
self.buffer[index] =
self.buffer[index] + self.buffer[index - 1] / 2 + self.buffer[index + 1] / 2;
}
}
}

/// Fills the `Canvas` with the given `Color`.
Expand Down Expand Up @@ -744,7 +790,7 @@ mod test {

#[test]
fn builtin_line_drawing_glyphs_coverage() {
// Dummy metrics values to test builtin glyphs coverage.
// Dummy metrics values to test built-in glyphs coverage.
let metrics = Metrics {
average_advance: 6.,
line_height: 16.,
Expand Down

0 comments on commit 5459492

Please sign in to comment.