From 39b3d3de0f97d921ad8ccf0191b95ab40ba18076 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 29 May 2021 14:15:08 +0530 Subject: [PATCH] macOS: Fix the baseline for text not matching other CoreText based applications for some fonts Finally found an API to query CoreText for the adjusted baseline position, so the baseline should now match up with other CoreText based applications. Fixes #2022 --- docs/changelog.rst | 3 +++ kitty/core_text.m | 28 +++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 8b4754e6a..2b2e7279b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -43,6 +43,9 @@ To update |kitty|, :doc:`follow the instructions `. - macOS: Add a new ``Shell`` menu to the global menubar with some commonly used actions (:pull:`3653`) +- macOS: Fix the baseline for text not matching other CoreText based + applications for some fonts (:iss:`2022`) + - Add a few more special commandline arguments for the launch command. Now all ``KITTY_PIPE_DATA`` is also available via command line argument substitution (:iss:`3593`) diff --git a/kitty/core_text.m b/kitty/core_text.m index 725499299..05ae87f20 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -21,6 +21,8 @@ #import #import +#define debug(...) if (global_state.debug_rendering) { fprintf(stderr, __VA_ARGS__); fflush(stderr); } + typedef struct { PyObject_HEAD @@ -339,9 +341,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u } } *cell_width = MAX(1u, width); - *underline_position = (unsigned int)floor(self->ascent - self->underline_position + 0.5); *underline_thickness = (unsigned int)ceil(MAX(0.1, self->underline_thickness)); - *baseline = (unsigned int)self->ascent; *strikethrough_position = (unsigned int)floor(*baseline * 0.65); *strikethrough_thickness = *underline_thickness; // float line_height = MAX(1, floor(self->ascent + self->descent + MAX(0, self->leading) + 0.5)); @@ -361,8 +361,30 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u CTFrameGetLineOrigins(test_frame, CFRangeMake(0, 1), &origin1); CTFrameGetLineOrigins(test_frame, CFRangeMake(1, 1), &origin2); CGFloat line_height = origin1.y - origin2.y; - CFRelease(test_frame); CFRelease(path); CFRelease(framesetter); + CFArrayRef lines = CTFrameGetLines(test_frame); + CTLineRef line = CFArrayGetValueAtIndex(lines, 0); + CGRect bounds = CTLineGetBoundsWithOptions(line, 0); + CGRect bounds_without_leading = CTLineGetBoundsWithOptions(line, kCTLineBoundsExcludeTypographicLeading); + CGFloat typographic_ascent, typographic_descent, typographic_leading; + CTLineGetTypographicBounds(line, &typographic_ascent, &typographic_descent, &typographic_leading); + CGFloat bounds_ascent = bounds_without_leading.size.height + bounds_without_leading.origin.y; + *baseline = (unsigned int)floor(bounds_ascent + 0.5); *cell_height = MAX(4u, (unsigned int)ceilf(line_height)); + // Not sure if we should add this to bounds ascent and then round it or add + // it to already rounded baseline and round again. + *underline_position = (unsigned int)floor(bounds_ascent - self->underline_position + 0.5); + + debug("Cell height calculation:\n"); + debug("\tline height from line origins: %f\n", line_height); + debug("\tline bounds: origin-y: %f height: %f\n", bounds.origin.y, bounds.size.height); + debug("\tline bounds-no-leading: origin-y: %f height: %f\n", bounds.origin.y, bounds.size.height); + debug("\tbounds metrics: ascent: %f", bounds_ascent); + debug("\tline metrics: ascent: %f descent: %f leading: %f\n", typographic_ascent, typographic_descent, typographic_leading); + debug("\tfont metrics: ascent: %f descent: %f leading: %f underline_position: %f\n", self->ascent, self->descent, self->leading, self->underline_position); + debug("\tcell_height: %u baseline: %u underline_position: %u\n", *cell_height, *baseline, *underline_position); + + CFRelease(test_frame); CFRelease(path); CFRelease(framesetter); + #undef count }