Use cell width to compute builtin font thickness

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 #5826.
Fixes #5821.
This commit is contained in:
Kirill Chibisov 2022-01-30 15:46:02 +03:00 committed by GitHub
parent efae2cc80c
commit 5459492eae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 7 deletions

View File

@ -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
@ -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

View File

@ -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};
@ -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.
@ -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;
@ -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;
@ -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;
@ -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:
@ -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`.
@ -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.,