diff options
| author | Znarf <90558133+FrancisTheCat@users.noreply.github.com> | 2025-07-31 18:03:31 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-31 16:03:31 +0000 |
| commit | f07622e9082af24dee1501889e13b298c57a1c4d (patch) | |
| tree | bdf240fb41c11ddbe20cb3e0ecf93800ccc953aa | |
| parent | 9f8fed7c9e76b013f8c2632105d1abec18e6a64e (diff) | |
| download | r-alacritty-f07622e9082af24dee1501889e13b298c57a1c4d.tar.gz r-alacritty-f07622e9082af24dee1501889e13b298c57a1c4d.tar.bz2 r-alacritty-f07622e9082af24dee1501889e13b298c57a1c4d.zip | |
Improve builtin font ellipse rendering
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | alacritty/src/renderer/text/builtin_font.rs | 137 |
2 files changed, 63 insertions, 75 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f8dbeb7..2054e25c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its ### Changed - Hide login message if `~/.hushlogin` is present +- Improve rendering of rounded corners with builtin box drawing ### Fixed diff --git a/alacritty/src/renderer/text/builtin_font.rs b/alacritty/src/renderer/text/builtin_font.rs index 1d7664f9..ce4b3bfd 100644 --- a/alacritty/src/renderer/text/builtin_font.rs +++ b/alacritty/src/renderer/text/builtin_font.rs @@ -349,7 +349,7 @@ fn box_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> Raster }, // Arcs: '╭', '╮', '╯', '╰'. '\u{256d}' | '\u{256e}' | '\u{256f}' | '\u{2570}' => { - canvas.draw_ellipse_arc(stroke_size); + canvas.draw_rounded_corner(stroke_size); // Mirror `X` axis. if character == '\u{256d}' || character == '\u{2570}' { @@ -875,86 +875,73 @@ impl Canvas { } } - /// 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. - fn draw_ellipse_arc(&mut self, stroke_size: usize) { - fn colors_with_error(error: f32, max_transparency: f32) -> (Pixel, Pixel) { - let transparency = error * max_transparency; - let alpha_1 = 1. - transparency; - let alpha_2 = 1. - (max_transparency - transparency); - let color_1 = Pixel::gray((COLOR_FILL._r as f32 * alpha_1) as u8); - let color_2 = Pixel::gray((COLOR_FILL._r as f32 * alpha_2) as u8); - (color_1, color_2) + /// Draws a quarter of a circle centered in `(0., self.height - radius)` with radius + /// `self.width` and an attached rectangle to form a "╭" using a given `stroke_size` in the + /// bottom-right quadrant of the `Canvas` coordinate system. + fn draw_rounded_corner(&mut self, stroke_size: usize) { + let radius = (self.width.min(self.height) + stroke_size) as f32 / 2.; + let stroke_size_f = stroke_size as f32; + + let mut x_offset = 0.; + let mut y_offset = 0.; + let (long_side, short_side, offset) = if self.height > self.width { + (&self.height, &self.width, &mut y_offset) + } else { + (&self.width, &self.height, &mut x_offset) + }; + let distance_bias = if short_side % 2 == stroke_size % 2 { 0. } else { 0.5 }; + *offset = *long_side as f32 / 2. - radius + stroke_size_f / 2.; + if (self.width % 2 != self.height % 2) && (long_side % 2 == stroke_size % 2) { + *offset += 1.; } - let h_line_bounds = self.h_line_bounds(self.y_center(), stroke_size); - let v_line_bounds = self.v_line_bounds(self.x_center(), stroke_size); - let h_line_bounds = (h_line_bounds.0 as usize, h_line_bounds.1 as usize); - let v_line_bounds = (v_line_bounds.0 as usize, v_line_bounds.1 as usize); - let max_transparency = 0.5; - - for (radius_y, radius_x) in - (h_line_bounds.0..h_line_bounds.1).zip(v_line_bounds.0..v_line_bounds.1) - { - let radius_x = radius_x as f32; - let radius_y = radius_y as f32; - let radius_x2 = radius_x * radius_x; - let radius_y2 = radius_y * radius_y; - let quarter = f32::round(radius_x2 / f32::sqrt(radius_x2 + radius_y2)) as usize; - - for x in 0..=quarter { - let x = x as f32; - let y = radius_y * f32::sqrt(1. - x * x / radius_x2); - let error = y.fract(); - - let (color_1, color_2) = colors_with_error(error, max_transparency); - - let x = x.clamp(0., radius_x); - let y_next = (y + 1.).clamp(0., h_line_bounds.1 as f32 - 1.); - let y = y.clamp(0., h_line_bounds.1 as f32 - 1.); - - self.put_pixel(x, y, color_1); - self.put_pixel(x, y_next, color_2); - } - - let quarter = f32::round(radius_y2 / f32::sqrt(radius_x2 + radius_y2)) as usize; - for y in 0..=quarter { + let radius_i = (short_side + stroke_size + 1) / 2; + for y in 0..radius_i { + for x in 0..radius_i { let y = y as f32; - let x = radius_x * f32::sqrt(1. - y * y / radius_y2); - let error = x - x.fract(); - - let (color_1, color_2) = colors_with_error(error, max_transparency); - - let x_next = (x + 1.).clamp(0., v_line_bounds.1 as f32 - 1.); - let x = x.clamp(0., v_line_bounds.1 as f32 - 1.); - let y = y.clamp(0., radius_y); - - self.put_pixel(x, y, color_1); - self.put_pixel(x_next, y, color_2); + let x = x as f32; + let distance = x.hypot(y) + distance_bias; + let value = if distance < radius - stroke_size_f - 1. { + // Inside the circle. + 0. + } else if distance < radius - stroke_size_f { + // On the inner border. + 1. + distance - (radius - stroke_size_f) + } else if distance < radius - 1. { + // Inside the stroke. + 1. + } else if distance < radius { + // On the outer border. + radius - distance + } else { + // Outside of the circle. + 0. + }; + + self.put_pixel( + x + x_offset, + y + y_offset, + Pixel::gray((COLOR_FILL._r as f32 * value) as u8), + ); } } - // 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; - } + if self.height > self.width { + self.draw_rect( + self.x_center() - stroke_size_f * 0.5, + 0., + stroke_size_f, + y_offset, + COLOR_FILL, + ); + } else { + self.draw_rect( + 0., + self.y_center() - stroke_size_f * 0.5, + x_offset, + stroke_size_f, + COLOR_FILL, + ); } } |