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
This commit is contained in:
Kovid Goyal 2020-08-10 17:28:08 +05:30
parent 1d651270d3
commit 817f0997cf
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 26 additions and 22 deletions

View File

@ -17,6 +17,9 @@ To update |kitty|, :doc:`follow the instructions <binary>`.
- 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]
--------------------

View File

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