From bb26b3d54960af86770870d5ed8745972215ea6c Mon Sep 17 00:00:00 2001 From: Yang Tang Date: Tue, 15 Jun 2021 14:52:43 -0400 Subject: [PATCH 1/2] Add option `adjust_baseline` to adjust the baseline position on macOS --- kitty/core_text.m | 2 +- kitty/options/definition.py | 9 +++++++++ kitty/options/parse.py | 3 +++ kitty/options/to-c-generated.h | 15 +++++++++++++++ kitty/options/types.py | 2 ++ kitty/state.h | 1 + 6 files changed, 31 insertions(+), 1 deletion(-) diff --git a/kitty/core_text.m b/kitty/core_text.m index 61c48fbc3..8c54ba69b 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -366,7 +366,7 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u 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; + CGFloat bounds_ascent = bounds_without_leading.size.height + bounds_without_leading.origin.y - OPT(adjust_baseline); *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 diff --git a/kitty/options/definition.py b/kitty/options/definition.py index d8371fe9c..e22475c9f 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -94,6 +94,15 @@ opt('adjust_column_width', '0', option_type='adjust_line_height', ctype='!adjust_column_width', ) +opt('adjust_baseline', '0', + option_type='int', ctype='int', + add_to_default=False, + long_text=''' +Adjust the baseline position of each character (in pixels) on macOS. A positive +number moves all characters up, and a negative number moves them down. +''' + ) + opt('+symbol_map', 'U+E0A0-U+E0A3,U+E0C0-U+E0C7 PowerlineSymbols', option_type='symbol_map', add_to_default=False, diff --git a/kitty/options/parse.py b/kitty/options/parse.py index b98d19b2b..b03396912 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -37,6 +37,9 @@ class Parser: def active_tab_title_template(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['active_tab_title_template'] = active_tab_title_template(val) + def adjust_baseline(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: + ans['adjust_baseline'] = int(val) + def adjust_column_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['adjust_column_width'] = adjust_line_height(val) diff --git a/kitty/options/to-c-generated.h b/kitty/options/to-c-generated.h index 89d13e5bb..d18dcb7a2 100644 --- a/kitty/options/to-c-generated.h +++ b/kitty/options/to-c-generated.h @@ -57,6 +57,19 @@ convert_from_opts_adjust_column_width(PyObject *py_opts, Options *opts) { Py_DECREF(ret); } +static void +convert_from_python_adjust_baseline(PyObject *val, Options *opts) { + opts->adjust_baseline = PyLong_AsLong(val); +} + +static void +convert_from_opts_adjust_baseline(PyObject *py_opts, Options *opts) { + PyObject *ret = PyObject_GetAttrString(py_opts, "adjust_baseline"); + if (ret == NULL) return; + convert_from_python_adjust_baseline(ret, opts); + Py_DECREF(ret); +} + static void convert_from_python_disable_ligatures(PyObject *val, Options *opts) { opts->disable_ligatures = PyLong_AsLong(val); @@ -886,6 +899,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) { if (PyErr_Occurred()) return false; convert_from_opts_adjust_column_width(py_opts, opts); if (PyErr_Occurred()) return false; + convert_from_opts_adjust_baseline(py_opts, opts); + if (PyErr_Occurred()) return false; convert_from_opts_disable_ligatures(py_opts, opts); if (PyErr_Occurred()) return false; convert_from_opts_cursor_shape(py_opts, opts); diff --git a/kitty/options/types.py b/kitty/options/types.py index bf7b9d2d2..9d3e14431 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -45,6 +45,7 @@ option_names = ( # {{{ 'active_tab_font_style', 'active_tab_foreground', 'active_tab_title_template', + 'adjust_baseline', 'adjust_column_width', 'adjust_line_height', 'allow_hyperlinks', @@ -435,6 +436,7 @@ class Options: active_tab_font_style: typing.Tuple[bool, bool] = (True, True) active_tab_foreground: Color = Color(red=0, green=0, blue=0) active_tab_title_template: typing.Optional[str] = None + adjust_baseline: int = 0 adjust_column_width: typing.Union[int, float] = 0 adjust_line_height: typing.Union[int, float] = 0 allow_hyperlinks: int = 1 diff --git a/kitty/state.h b/kitty/state.h index 9971565ad..5fd909084 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -42,6 +42,7 @@ typedef struct { WindowTitleIn macos_show_window_title_in; int adjust_line_height_px, adjust_column_width_px; float adjust_line_height_frac, adjust_column_width_frac; + int adjust_baseline; float background_opacity, dim_opacity; char* background_image; From e964ac86d5d9954ba835c3853fa787de41e16224 Mon Sep 17 00:00:00 2001 From: Yang Tang Date: Tue, 15 Jun 2021 23:44:01 -0400 Subject: [PATCH 2/2] Allow specifying `adjust_baseline` as either pixels or percentage --- kitty/core_text.m | 6 ++++-- kitty/freetype.c | 9 ++++++--- kitty/options/definition.py | 9 ++++++--- kitty/options/parse.py | 22 +++++++++++----------- kitty/options/to-c-generated.h | 2 +- kitty/options/to-c.h | 2 ++ kitty/options/types.py | 2 +- kitty/options/utils.py | 10 ++++++++++ kitty/state.h | 5 ++--- 9 files changed, 43 insertions(+), 24 deletions(-) diff --git a/kitty/core_text.m b/kitty/core_text.m index 8c54ba69b..ff1be554f 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -366,9 +366,11 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u 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 - OPT(adjust_baseline); - *baseline = (unsigned int)floor(bounds_ascent + 0.5); *cell_height = MAX(4u, (unsigned int)ceilf(line_height)); + CGFloat bounds_ascent = bounds_without_leading.size.height + bounds_without_leading.origin.y; + if (OPT(adjust_baseline_px) != 0) bounds_ascent -= OPT(adjust_baseline_px); + if (OPT(adjust_baseline_frac) != 0) bounds_ascent -= *cell_height * OPT(adjust_baseline_frac); + *baseline = (unsigned int)floor(bounds_ascent + 0.5); // 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); diff --git a/kitty/freetype.c b/kitty/freetype.c index d6a53a836..95d83c3a1 100644 --- a/kitty/freetype.c +++ b/kitty/freetype.c @@ -307,12 +307,15 @@ cell_metrics(PyObject *s, unsigned int* cell_width, unsigned int* cell_height, u Face *self = (Face*)s; *cell_width = calc_cell_width(self); *cell_height = calc_cell_height(self, true); - *baseline = font_units_to_pixels_y(self, self->ascender); - *underline_position = MIN(*cell_height - 1, (unsigned int)font_units_to_pixels_y(self, MAX(0, self->ascender - self->underline_position))); + int baseline_offset = 0; + if (OPT(adjust_baseline_px) != 0) baseline_offset = OPT(adjust_baseline_px); + if (OPT(adjust_baseline_frac) != 0) baseline_offset = (int)(*cell_height * OPT(adjust_baseline_frac)); + *baseline = font_units_to_pixels_y(self, self->ascender) - baseline_offset; + *underline_position = MIN(*cell_height - 1, (unsigned int)MAX(0, font_units_to_pixels_y(self, MAX(0, self->ascender - self->underline_position)) - baseline_offset)); *underline_thickness = MAX(1, font_units_to_pixels_y(self, self->underline_thickness)); if (self->strikethrough_position != 0) { - *strikethrough_position = MIN(*cell_height - 1, (unsigned int)font_units_to_pixels_y(self, MAX(0, self->ascender - self->strikethrough_position))); + *strikethrough_position = MIN(*cell_height - 1, (unsigned int)MAX(0, font_units_to_pixels_y(self, MAX(0, self->ascender - self->strikethrough_position)) - baseline_offset)); } else { *strikethrough_position = (unsigned int)floor(*baseline * 0.65); } diff --git a/kitty/options/definition.py b/kitty/options/definition.py index e22475c9f..a9f9cce12 100644 --- a/kitty/options/definition.py +++ b/kitty/options/definition.py @@ -95,11 +95,14 @@ opt('adjust_column_width', '0', ) opt('adjust_baseline', '0', - option_type='int', ctype='int', + option_type='adjust_baseline', ctype='!adjust_baseline', add_to_default=False, long_text=''' -Adjust the baseline position of each character (in pixels) on macOS. A positive -number moves all characters up, and a negative number moves them down. +Adjust the baseline position of each character. You can use either +a number, which is interpreted as pixels or a percentage (number followed by %), +which is interpreted as the percentage of the line height. A positive +value moves all characters up, and a negative value moves them down. +The underline and strikethrough positions are adjusted accordingly. ''' ) diff --git a/kitty/options/parse.py b/kitty/options/parse.py index b03396912..c84cb4f41 100644 --- a/kitty/options/parse.py +++ b/kitty/options/parse.py @@ -7,16 +7,16 @@ from kitty.conf.utils import ( unit_float ) from kitty.options.utils import ( - active_tab_title_template, adjust_line_height, allow_hyperlinks, allow_remote_control, - box_drawing_scale, clear_all_shortcuts, clipboard_control, config_or_absolute_path, copy_on_select, - cursor_text_color, deprecated_hide_window_decorations_aliases, - deprecated_macos_show_window_title_in_menubar_alias, deprecated_send_text, disable_ligatures, - edge_width, env, font_features, hide_window_decorations, kitten_alias, macos_option_as_alt, - macos_titlebar_color, optional_edge_width, parse_map, parse_mouse_map, resize_draw_strategy, - scrollback_lines, scrollback_pager_history_size, symbol_map, tab_activity_symbol, tab_bar_edge, - tab_bar_margin_height, tab_bar_min_tabs, tab_fade, tab_font_style, tab_separator, - tab_title_template, to_cursor_shape, to_font_size, to_layout_names, to_modifiers, url_prefixes, - url_style, window_border_width, window_size + active_tab_title_template, adjust_baseline, adjust_line_height, allow_hyperlinks, + allow_remote_control, box_drawing_scale, clear_all_shortcuts, clipboard_control, + config_or_absolute_path, copy_on_select, cursor_text_color, + deprecated_hide_window_decorations_aliases, deprecated_macos_show_window_title_in_menubar_alias, + deprecated_send_text, disable_ligatures, edge_width, env, font_features, hide_window_decorations, + kitten_alias, macos_option_as_alt, macos_titlebar_color, optional_edge_width, parse_map, + parse_mouse_map, resize_draw_strategy, scrollback_lines, scrollback_pager_history_size, symbol_map, + tab_activity_symbol, tab_bar_edge, tab_bar_margin_height, tab_bar_min_tabs, tab_fade, + tab_font_style, tab_separator, tab_title_template, to_cursor_shape, to_font_size, to_layout_names, + to_modifiers, url_prefixes, url_style, window_border_width, window_size ) @@ -38,7 +38,7 @@ class Parser: ans['active_tab_title_template'] = active_tab_title_template(val) def adjust_baseline(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: - ans['adjust_baseline'] = int(val) + ans['adjust_baseline'] = adjust_baseline(val) def adjust_column_width(self, val: str, ans: typing.Dict[str, typing.Any]) -> None: ans['adjust_column_width'] = adjust_line_height(val) diff --git a/kitty/options/to-c-generated.h b/kitty/options/to-c-generated.h index d18dcb7a2..7fa2db6b1 100644 --- a/kitty/options/to-c-generated.h +++ b/kitty/options/to-c-generated.h @@ -59,7 +59,7 @@ convert_from_opts_adjust_column_width(PyObject *py_opts, Options *opts) { static void convert_from_python_adjust_baseline(PyObject *val, Options *opts) { - opts->adjust_baseline = PyLong_AsLong(val); + adjust_baseline(val, opts); } static void diff --git a/kitty/options/to-c.h b/kitty/options/to-c.h index 4de83e3b8..2875f1d23 100644 --- a/kitty/options/to-c.h +++ b/kitty/options/to-c.h @@ -162,4 +162,6 @@ static void adjust_line_height(PyObject *al, Options *opts) { read_adjust(adjust_line_height); } static void adjust_column_width(PyObject *al, Options *opts) { read_adjust(adjust_column_width); } +static void +adjust_baseline(PyObject *al, Options *opts) { read_adjust(adjust_baseline); } #undef read_adjust diff --git a/kitty/options/types.py b/kitty/options/types.py index 9d3e14431..6b3632ecb 100644 --- a/kitty/options/types.py +++ b/kitty/options/types.py @@ -436,7 +436,7 @@ class Options: active_tab_font_style: typing.Tuple[bool, bool] = (True, True) active_tab_foreground: Color = Color(red=0, green=0, blue=0) active_tab_title_template: typing.Optional[str] = None - adjust_baseline: int = 0 + adjust_baseline: typing.Union[int, float] = 0 adjust_column_width: typing.Union[int, float] = 0 adjust_line_height: typing.Union[int, float] = 0 allow_hyperlinks: int = 1 diff --git a/kitty/options/utils.py b/kitty/options/utils.py index cf57697d2..5f20390d1 100644 --- a/kitty/options/utils.py +++ b/kitty/options/utils.py @@ -424,6 +424,16 @@ def adjust_line_height(x: str) -> Union[int, float]: return int(x) +def adjust_baseline(x: str) -> Union[int, float]: + if x.endswith('%'): + ans = float(x[:-1].strip()) / 100.0 + if abs(ans) > 1: + log_error('Percentage adjustments of the baseline cannot exceed 100%') + return 0 + return ans + return int(x) + + def to_font_size(x: str) -> float: return max(MINIMUM_FONT_SIZE, float(x)) diff --git a/kitty/state.h b/kitty/state.h index 5fd909084..66f6f70ec 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -40,9 +40,8 @@ typedef struct { unsigned int macos_option_as_alt; float macos_thicken_font; WindowTitleIn macos_show_window_title_in; - int adjust_line_height_px, adjust_column_width_px; - float adjust_line_height_frac, adjust_column_width_frac; - int adjust_baseline; + int adjust_line_height_px, adjust_column_width_px, adjust_baseline_px; + float adjust_line_height_frac, adjust_column_width_frac, adjust_baseline_frac; float background_opacity, dim_opacity; char* background_image;