mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-24 09:05:48 -04:00
Merge branch 'allow-bleeding-glyphs'
This commit is contained in:
commit
a18959f2df
6 changed files with 71 additions and 75 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
|
@ -33,6 +33,9 @@
|
||||||
|
|
||||||
* `locked-title=no|yes` to `foot.ini`
|
* `locked-title=no|yes` to `foot.ini`
|
||||||
(https://codeberg.org/dnkl/foot/issues/386).
|
(https://codeberg.org/dnkl/foot/issues/386).
|
||||||
|
* `tweak.overflowing-glyphs` option, which can be enabled to fix rendering
|
||||||
|
issues with glyphs of any width that appear cut-off
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/592).
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
@ -45,6 +48,12 @@
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
* The `tweak.allow-overflowing-double-width-glyphs` and
|
||||||
|
`tweak.pua-double-width` options (which have been superseded by
|
||||||
|
`tweak.overflowing-glyphs`).
|
||||||
|
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
* Glyph offset not being taken into account when applying
|
* Glyph offset not being taken into account when applying
|
||||||
|
|
@ -69,6 +78,8 @@
|
||||||
### Security
|
### Security
|
||||||
### Contributors
|
### Contributors
|
||||||
|
|
||||||
|
* [clktmr](https://codeberg.org/clktmr)
|
||||||
|
|
||||||
|
|
||||||
## 1.8.1
|
## 1.8.1
|
||||||
|
|
||||||
|
|
|
||||||
17
config.c
17
config.c
|
|
@ -2213,16 +2213,10 @@ parse_section_tweak(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(key, "allow-overflowing-double-width-glyphs") == 0) {
|
else if (strcmp(key, "overflowing-glyphs") == 0) {
|
||||||
conf->tweak.allow_overflowing_double_width_glyphs = str_to_bool(value);
|
conf->tweak.overflowing_glyphs = str_to_bool(value);
|
||||||
if (!conf->tweak.allow_overflowing_double_width_glyphs)
|
if (!conf->tweak.overflowing_glyphs)
|
||||||
LOG_WARN("tweak: disabled overflowing double-width glyphs");
|
LOG_WARN("tweak: disabled overflowing glyphs");
|
||||||
}
|
|
||||||
|
|
||||||
else if (strcmp(key, "pua-double-width") == 0) {
|
|
||||||
conf->tweak.pua_double_width = str_to_bool(value);
|
|
||||||
if (conf->tweak.pua_double_width)
|
|
||||||
LOG_WARN("tweak: PUA double width glyphs enabled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(key, "damage-whole-window") == 0) {
|
else if (strcmp(key, "damage-whole-window") == 0) {
|
||||||
|
|
@ -2833,7 +2827,7 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
|
|
||||||
.tweak = {
|
.tweak = {
|
||||||
.fcft_filter = FCFT_SCALING_FILTER_LANCZOS3,
|
.fcft_filter = FCFT_SCALING_FILTER_LANCZOS3,
|
||||||
.allow_overflowing_double_width_glyphs = true,
|
.overflowing_glyphs = true,
|
||||||
.grapheme_shaping = false,
|
.grapheme_shaping = false,
|
||||||
.grapheme_width_method = GRAPHEME_WIDTH_DOUBLE,
|
.grapheme_width_method = GRAPHEME_WIDTH_DOUBLE,
|
||||||
.delayed_render_lower_ns = 500000, /* 0.5ms */
|
.delayed_render_lower_ns = 500000, /* 0.5ms */
|
||||||
|
|
@ -2844,7 +2838,6 @@ config_load(struct config *conf, const char *conf_path,
|
||||||
.damage_whole_window = false,
|
.damage_whole_window = false,
|
||||||
.box_drawing_base_thickness = 0.04,
|
.box_drawing_base_thickness = 0.04,
|
||||||
.box_drawing_solid_shades = true,
|
.box_drawing_solid_shades = true,
|
||||||
.pua_double_width = false,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.notifications = tll_init(),
|
.notifications = tll_init(),
|
||||||
|
|
|
||||||
3
config.h
3
config.h
|
|
@ -245,7 +245,7 @@ struct config {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
enum fcft_scaling_filter fcft_filter;
|
enum fcft_scaling_filter fcft_filter;
|
||||||
bool allow_overflowing_double_width_glyphs;
|
bool overflowing_glyphs;
|
||||||
bool grapheme_shaping;
|
bool grapheme_shaping;
|
||||||
enum {GRAPHEME_WIDTH_WCSWIDTH, GRAPHEME_WIDTH_DOUBLE} grapheme_width_method;
|
enum {GRAPHEME_WIDTH_WCSWIDTH, GRAPHEME_WIDTH_DOUBLE} grapheme_width_method;
|
||||||
bool render_timer_osd;
|
bool render_timer_osd;
|
||||||
|
|
@ -256,7 +256,6 @@ struct config {
|
||||||
off_t max_shm_pool_size;
|
off_t max_shm_pool_size;
|
||||||
float box_drawing_base_thickness;
|
float box_drawing_base_thickness;
|
||||||
bool box_drawing_solid_shades;
|
bool box_drawing_solid_shades;
|
||||||
bool pua_double_width;
|
|
||||||
} tweak;
|
} tweak;
|
||||||
|
|
||||||
user_notifications_t notifications;
|
user_notifications_t notifications;
|
||||||
|
|
|
||||||
|
|
@ -847,34 +847,24 @@ any of these options.
|
||||||
|
|
||||||
Default: _lanczos3_.
|
Default: _lanczos3_.
|
||||||
|
|
||||||
*allow-overflowing-double-width-glyphs*
|
*overflowing-glyphs*
|
||||||
Boolean. When enabled, double width glyphs with a character width
|
Boolean. When enabled, glyphs wider than their cell(s) are allowed
|
||||||
of 1 are allowed to overflow into the neighbouring cell.
|
to render into one additional neighbouring cell.
|
||||||
|
|
||||||
One use case for this is fonts "icon" characters in the Unicode
|
One use case for this are fonts with wide italic characters that
|
||||||
private usage area, e.g. Nerd Fonts, or Powerline Fonts. Without
|
"bend" into the next cell. Without this option, such glyphs will
|
||||||
this option, such glyphs will appear "cut off".
|
appear "cut off".
|
||||||
|
|
||||||
Another use case are legacy emoji characters like *WHITE FROWNING
|
Another use case are fonts with "icon" characters in the Unicode
|
||||||
FACE*.
|
private usage area, e.g. Nerd Fonts, or Powerline Fonts and legacy
|
||||||
|
emoji characters like *WHITE FROWNING FACE*.
|
||||||
|
|
||||||
Note: this feature uses _heuristics_ to determine *which* glyphs
|
Note: might impact performance depending on the font used.
|
||||||
should be allowed to overflow.
|
Especially small font sizes can cause many overflowing glyphs
|
||||||
|
because of subpixel rendering.
|
||||||
See also: *pua-double-width*
|
|
||||||
|
|
||||||
Default: _yes_.
|
Default: _yes_.
|
||||||
|
|
||||||
*pua-double-width*
|
|
||||||
Boolean. When enabled, Unicode code points from the private usage
|
|
||||||
area (PUA) are always considered to be double width, regardless of
|
|
||||||
the actual glyph width.
|
|
||||||
|
|
||||||
Ignored if *allow-overflowing-double-width-glyphs* has been
|
|
||||||
disabled.
|
|
||||||
|
|
||||||
Default: _no_.
|
|
||||||
|
|
||||||
*render-timer*
|
*render-timer*
|
||||||
Enables a frame rendering timer, that prints the time it takes to
|
Enables a frame rendering timer, that prints the time it takes to
|
||||||
render each frame, in microseconds, either on-screen, to stderr,
|
render each frame, in microseconds, either on-screen, to stderr,
|
||||||
|
|
|
||||||
78
render.c
78
render.c
|
|
@ -437,6 +437,20 @@ draw_cursor(const struct terminal *term, const struct cell *cell,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
render_cell_prepass(struct terminal *term, struct row *row, int col)
|
||||||
|
{
|
||||||
|
for (; col < term->cols - 1; col++) {
|
||||||
|
if (row->cells[col].attrs.confined ||
|
||||||
|
(row->cells[col].attrs.clean == row->cells[col + 1].attrs.clean)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
row->cells[col].attrs.clean = 0;
|
||||||
|
row->cells[col + 1].attrs.clean = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
render_cell(struct terminal *term, pixman_image_t *pix,
|
render_cell(struct terminal *term, pixman_image_t *pix,
|
||||||
struct row *row, int col, int row_no, bool has_cursor)
|
struct row *row, int col, int row_no, bool has_cursor)
|
||||||
|
|
@ -446,6 +460,7 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cell->attrs.clean = 1;
|
cell->attrs.clean = 1;
|
||||||
|
cell->attrs.confined = true;
|
||||||
|
|
||||||
int width = term->cell_width;
|
int width = term->cell_width;
|
||||||
int height = term->cell_height;
|
int height = term->cell_height;
|
||||||
|
|
@ -597,51 +612,32 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
||||||
cell_cols = max(1, min(cell_cols, cols_left));
|
cell_cols = max(1, min(cell_cols, cols_left));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hack!
|
* Determine cells that will bleed into their right neighbor and remember
|
||||||
*
|
* them for cleanup in the next frame.
|
||||||
* Deal with double-width glyphs for which wcwidth() returns
|
|
||||||
* 1. Typically Unicode private usage area characters,
|
|
||||||
* e.g. powerline, or nerd hack fonts.
|
|
||||||
*
|
|
||||||
* Users can enable a tweak option that lets this glyphs
|
|
||||||
* overflow/bleed into the neighbouring cell.
|
|
||||||
*
|
|
||||||
* We only apply this workaround if:
|
|
||||||
* - the user has explicitly enabled this feature
|
|
||||||
* - the *character* width is 1
|
|
||||||
* - the *glyph* width is at least 1.5 cells
|
|
||||||
* - the *glyph* width is less than 3 cells
|
|
||||||
* - *this* column isn’t the last column
|
|
||||||
* - *this* cells is followed by an empty cell, or a space
|
|
||||||
*/
|
*/
|
||||||
if (term->conf->tweak.allow_overflowing_double_width_glyphs &&
|
int render_width = cell_cols * width;
|
||||||
glyph_count > 0 &&
|
if (term->conf->tweak.overflowing_glyphs &&
|
||||||
cell_cols == 1 &&
|
glyph_count > 0)
|
||||||
col < term->cols - 1 &&
|
|
||||||
((glyphs[0]->x + glyphs[0]->width >= term->cell_width * 15 / 10 &&
|
|
||||||
glyphs[0]->x + glyphs[0]->width < 3 * term->cell_width) ||
|
|
||||||
(term->conf->tweak.pua_double_width &&
|
|
||||||
((base >= 0x00e000 && base <= 0x00f8ff) ||
|
|
||||||
(base >= 0x0f0000 && base <= 0x0ffffd) ||
|
|
||||||
(base >= 0x100000 && base <= 0x10fffd)))) &&
|
|
||||||
(row->cells[col + 1].wc == 0 || row->cells[col + 1].wc == L' '))
|
|
||||||
{
|
{
|
||||||
cell_cols = 2;
|
int glyph_width = 0, advance = 0;
|
||||||
|
for (size_t i = 0; i < glyph_count; i++) {
|
||||||
|
glyph_width = max(glyph_width,
|
||||||
|
advance + glyphs[i]->x + glyphs[i]->width);
|
||||||
|
advance += glyphs[i]->advance.x;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
if (glyph_width > render_width) {
|
||||||
* Ensure the cell we’re overflowing into gets re-rendered, to
|
render_width = min(glyph_width, render_width + width);
|
||||||
* ensure it is erased if *this* cell is erased. Note that we
|
|
||||||
* do *not* mark the row as dirty - we don’t need to re-render
|
for (int i = 0; i < cell_cols; i++)
|
||||||
* the cell if nothing else on the row has changed.
|
row->cells[col + i].attrs.confined = false;
|
||||||
*/
|
}
|
||||||
row->cells[col].attrs.clean = 0;
|
|
||||||
row->cells[col + 1].attrs.clean = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_t clip;
|
pixman_region32_t clip;
|
||||||
pixman_region32_init_rect(
|
pixman_region32_init_rect(
|
||||||
&clip, x, y,
|
&clip, x, y,
|
||||||
cell_cols * term->cell_width, term->cell_height);
|
render_width, term->cell_height);
|
||||||
pixman_image_set_clip_region32(pix, &clip);
|
pixman_image_set_clip_region32(pix, &clip);
|
||||||
|
|
||||||
/* Background */
|
/* Background */
|
||||||
|
|
@ -771,6 +767,10 @@ static void
|
||||||
render_row(struct terminal *term, pixman_image_t *pix, struct row *row,
|
render_row(struct terminal *term, pixman_image_t *pix, struct row *row,
|
||||||
int row_no, int cursor_col)
|
int row_no, int cursor_col)
|
||||||
{
|
{
|
||||||
|
if (term->conf->tweak.overflowing_glyphs)
|
||||||
|
for (int col = term->cols - 1; col >= 0; col--)
|
||||||
|
render_cell_prepass(term, row, col);
|
||||||
|
|
||||||
for (int col = term->cols - 1; col >= 0; col--)
|
for (int col = term->cols - 1; col >= 0; col--)
|
||||||
render_cell(term, pix, row, col, row_no, cursor_col == col);
|
render_cell(term, pix, row, col, row_no, cursor_col == col);
|
||||||
}
|
}
|
||||||
|
|
@ -1192,8 +1192,10 @@ render_sixel(struct terminal *term, pixman_image_t *pix,
|
||||||
(last_col_needs_erase && last_col))
|
(last_col_needs_erase && last_col))
|
||||||
{
|
{
|
||||||
render_cell(term, pix, row, col, term_row_no, cursor_col == col);
|
render_cell(term, pix, row, col, term_row_no, cursor_col == col);
|
||||||
} else
|
} else {
|
||||||
cell->attrs.clean = 1;
|
cell->attrs.clean = 1;
|
||||||
|
cell->attrs.confined = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,12 @@ struct attributes {
|
||||||
uint32_t fg:24;
|
uint32_t fg:24;
|
||||||
|
|
||||||
bool clean:1;
|
bool clean:1;
|
||||||
|
bool confined:1;
|
||||||
bool have_fg:1;
|
bool have_fg:1;
|
||||||
bool have_bg:1;
|
bool have_bg:1;
|
||||||
uint32_t selected:2;
|
uint32_t selected:2;
|
||||||
bool url:1;
|
bool url:1;
|
||||||
uint32_t reserved:2;
|
uint32_t reserved:1;
|
||||||
uint32_t bg:24;
|
uint32_t bg:24;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(struct attributes) == 8, "VT attribute struct too large");
|
static_assert(sizeof(struct attributes) == 8, "VT attribute struct too large");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue