From 817f0997cf5d43457194ecad14008cdff8b7bf33 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 10 Aug 2020 17:28:08 +0530 Subject: [PATCH] Fix one pixel mis-alignment of rounded corners when either the cell dimensions or the thickness of the line is an odd number of pixels The control points of the Bezier curve and the spread due to thickness must match up with the values used to draw straight lines. In order to ensure that, one calculates them before upscaling by the super sampling factor, rather than after. Fixes #2907 --- docs/changelog.rst | 3 +++ kitty/fonts/box_drawing.py | 45 +++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index f005921d9..5e6aab243 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -17,6 +17,9 @@ To update |kitty|, :doc:`follow the instructions `. - Fix image leaving behind a black rectangle when switch away and back to alternate screen (:iss:`2901`) +- Fix one pixel mis-alignment of rounded corners when either the cell + dimensions or the thickness of the line is an odd number of pixels + (:iss:`2907`) 0.18.2 [2020-07-28] -------------------- diff --git a/kitty/fonts/box_drawing.py b/kitty/fonts/box_drawing.py index 91bcc281b..3ae400e81 100644 --- a/kitty/fonts/box_drawing.py +++ b/kitty/fonts/box_drawing.py @@ -364,20 +364,19 @@ def D(buf: BufType, width: int, height: int, left: bool = True) -> None: buf[offset + dest_x] = mbuf[offset + src_x] -def draw_parametrized_curve(buf: BufType, width: int, height: int, thickness_in_pixels: int, xfunc: BezierFunc, yfunc: BezierFunc) -> None: +def draw_parametrized_curve(buf: BufType, width: int, height: int, delta: int, extra: int, xfunc: BezierFunc, yfunc: BezierFunc) -> None: num_samples = height*4 seen = set() - delta, extra = divmod(thickness_in_pixels, 2) for i in range(num_samples + 1): t = (i / num_samples) p = x_p, y_p = int(xfunc(t)), int(yfunc(t)) if p in seen: continue seen.add(p) - for y in range(int(y_p) - delta, int(y_p) + delta + extra): + for y in range(y_p - delta, y_p + delta + extra): if 0 <= y < height: offset = y * width - for x in range(int(x_p) - delta, int(x_p) + delta + extra): + for x in range(x_p - delta, x_p + delta + extra): if 0 <= x < width: pos = offset + x buf[pos] = min(255, buf[pos] + 255) @@ -386,29 +385,31 @@ def draw_parametrized_curve(buf: BufType, width: int, height: int, thickness_in_ @supersampled() def rounded_corner(buf: BufType, width: int, height: int, level: int = 1, which: str = '╭') -> None: supersample_factor = getattr(buf, 'supersample_factor') - thickness_in_pixels = thickness(level) * supersample_factor + delta, extra = divmod(thickness(level), 2) + hw = ((width / supersample_factor) // 2) * supersample_factor + hh = ((height / supersample_factor) // 2) * supersample_factor if which == '╭': - start = width // 2, height - 1 - end = width - 1, height // 2 - c1 = width // 2, int(0.75 * height) - c2 = width // 2, height // 2 + 1 + start = hw, height - 1 + end = width - 1, hh + c1 = hw, int(0.75 * height) + c2 = hw, hh + 1 elif which == '╮': - start = 0, height // 2 - end = width // 2, height - 1 - c1 = width // 2, height // 2 + 1 - c2 = width // 2, int(0.75 * height) + start = 0, hh + end = hw, height - 1 + c1 = hw, hh + 1 + c2 = hw, int(0.75 * height) elif which == '╰': start = width // 2, 0 - end = width - 1, height // 2 - c1 = width // 2, int(0.25 * height) - c2 = width // 2 - 1, height // 2 - 1 + end = width - 1, hh + c1 = hw, int(0.25 * height) + c2 = hw, hh - 1 elif which == '╯': - start = 0, height // 2 - end = width // 2, 0 - c1 = width // 2 - 1, height // 2 - 1 - c2 = width // 2, int(0.25 * height) + start = 0, hh + end = hw, 0 + c1 = hw, hh - 1 + c2 = hw, int(0.25 * height) xfunc, yfunc = cubic_bezier(start, end, c1, c2) - draw_parametrized_curve(buf, width, height, thickness_in_pixels, xfunc, yfunc) + draw_parametrized_curve(buf, width, height, delta * supersample_factor, extra * supersample_factor, xfunc, yfunc) def half_dhline(buf: BufType, width: int, height: int, level: int = 1, which: str = 'left', only: Optional[str] = None) -> Tuple[int, int]: @@ -686,7 +687,7 @@ t, f = 1, 3 for start in '┌┐└┘': for i, (hlevel, vlevel) in enumerate(((t, t), (f, t), (t, f), (f, f))): box_chars[chr(ord(start) + i)] = [p(corner, which=start, hlevel=hlevel, vlevel=vlevel)] -for ch in '╭╮╯╰': +for ch in '╭╮╰╯': box_chars[ch] = [p(rounded_corner, which=ch)] for i, (a_, b_, c_, d_) in enumerate((