render: don’t let URL jump label sub-surfaces extend outside window geometry

We have no guarantee that sub-surfaces extending outside the window
geometry are rendered correctly (if at all).

For example, both Sway and River will render the window border on top
of the sub-surface.

Future versions of Sway may clip the sub-surface.

Since jump-labels are positioned slightly above, and to the left of
the URLs first character, having a label on either the top row, or on
the first column, will likely position it outside the window. This is
handled by simply setting x/y to 0 (or, to -margin, since the label
coordinate is later offsetted with the window margins).

Second, if the label is very long, it may extend outside the
window. This is very unusual for labels only showing the key, and not
the URL itself, but could happen in this case too, if e.g. the user
has configured double-width key characters.

This is handled by calculating its maximum width, and then truncating
the label.

Although very unlikely, it is possible for a label to also extend
outside the window’s vertical size. This could happen for very small
font sizes, where the label’s own margins are large, relative to the
font size. This case is currently not handled.

Closes #443
This commit is contained in:
Daniel Eklöf 2021-04-10 13:16:39 +02:00
parent 4325d5a4ab
commit 8561fdb004
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 60 additions and 27 deletions

View file

@ -40,6 +40,8 @@
* Underline cursor is now rendered below text underline
(https://codeberg.org/dnkl/foot/issues/415).
* Foot now tries much harder to keep URL jump labels inside the window
geometry (https://codeberg.org/dnkl/foot/issues/443).
### Deprecated

View file

@ -2632,6 +2632,26 @@ render_urls(struct terminal *term)
continue;
}
int col = pos->col;
int row = pos->row - term->grid->view;
while (row < 0)
row += term->grid->num_rows;
row &= (term->grid->num_rows - 1);
/* Position label slightly above and to the left */
int x = col * term->cell_width - 15 * term->cell_width / 10;
int y = row * term->cell_height - 5 * term->cell_height / 10;
/* Dont position it outside our window */
if (x < -term->margins.left)
x = -term->margins.left;
if (y < -term->margins.top)
y = -term->margins.top;
/* Maximum width of label, in pixels */
const int max_width =
term->width - term->margins.left - term->margins.right - x;
const size_t key_len = wcslen(key);
size_t url_len = mbstowcs(NULL, url->url, 0);
@ -2641,32 +2661,59 @@ render_urls(struct terminal *term)
wchar_t url_wchars[url_len + 1];
mbstowcs(url_wchars, url->url, url_len + 1);
/* Format label, not yet subject to any size limitations */
size_t chars = key_len + (show_url ? (2 + url_len) : 0);
const size_t max_chars = 50;
chars = min(chars, max_chars);
wchar_t label[chars + 2];
label[chars] = L'';
label[chars + 1] = L'\0';
wchar_t label[chars + 1];
label[chars] = L'\0';
if (show_url)
swprintf(label, chars + 1, L"%ls: %ls", key, url_wchars);
else
wcsncpy(label, key, chars + 1);
wcsncpy(label, key, chars);
/* Upper case the key characters */
for (size_t i = 0; i < wcslen(key); i++)
label[i] = towupper(label[i]);
/* Blank already entered key characters */
for (size_t i = 0; i < entered_key_len; i++)
label[i] = L' ';
size_t len = wcslen(label);
int cols = wcswidth(label, len);
/*
* Dont extend outside our window
*
* Truncate label so that it doesnt extend outside our
* window.
*
* Do it in a way such that we dont cut the label in the
* middle of a double-width character.
*/
const int scale = term->scale;
const int x_margin = 2 * scale;
const int y_margin = 1 * scale;
const int max_cols = max_width / term->cell_width;
int cols = 0;
for (size_t i = 0; i <= wcslen(label); i++) {
int _cols = wcswidth(label, i);
if (_cols == (size_t)-1)
continue;
if (_cols >= max_cols) {
if (i > 0)
label[i - 1] = L'';
label[i] = L'\0';
cols = max_cols;
break;
}
cols = _cols;
}
if (cols == 0)
continue;
const int width =
(2 * x_margin + cols * term->cell_width + scale - 1) / scale * scale;
const int height =
@ -2675,22 +2722,6 @@ render_urls(struct terminal *term)
struct buffer *buf = shm_get_buffer(
term->wl->shm, width, height, shm_cookie_url(url), false, 1);
int col = pos->col;
int row = pos->row - term->grid->view;
while (row < 0)
row += term->grid->num_rows;
row &= (term->grid->num_rows - 1);
int x = col * term->cell_width - 15 * term->cell_width / 10;
int y = row * term->cell_height - 5 * term->cell_height / 10;
if (x < 0)
x = 0;
#if 0
if (y < 0)
y += 15 * term->cell_height / 10;
#endif
wl_subsurface_set_position(
sub_surf,
(term->margins.left + x) / term->scale,