diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b3b95c7..7e0196a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,7 +112,7 @@ characters (e.g. emojis). * Rendering of CSD borders when `csd.border-width > 0` and desktop scaling has been enabled. -* Failure to launch when `exec(3)’:ed with an empty argv. +* Failure to launch when `exec(3)`:ed with an empty argv. * Pasting from the primary clipboard (mouse middle clicking) did not reset the scrollback view to the bottom. * Wrong mouse binding triggered when doing two mouse selections in @@ -120,6 +120,9 @@ (https://codeberg.org/dnkl/foot/issues/883). * Bash completion giving an error when completing a list of short options +* Sixel: large image resizes (triggered by e.g. large repeat counts in + `DECGRI`) are now truncated instead of ignored. +* Sixel: a repeat count of 0 in `DECGRI` now emits a single sixel. ### Security diff --git a/sixel.c b/sixel.c index b659a3c0..5316c0ad 100644 --- a/sixel.c +++ b/sixel.c @@ -1104,7 +1104,7 @@ sixel_unhook(struct terminal *term) render_refresh(term); } -static bool +static void resize_horizontally(struct terminal *term, int new_width) { LOG_DBG("resizing image horizontally: %dx(%d) -> %dx(%d)", @@ -1112,10 +1112,13 @@ resize_horizontally(struct terminal *term, int new_width) new_width, term->sixel.image.height); if (unlikely(new_width > term->sixel.max_width)) { - LOG_WARN("maximum image dimensions reached"); - return false; + LOG_WARN("maximum image dimensions exceeded, truncating"); + new_width = term->sixel.max_width; } + if (unlikely(term->sixel.image.width == new_width)) + return; + uint32_t *old_data = term->sixel.image.data; const int old_width = term->sixel.image.width; const int height = term->sixel.image.height; @@ -1145,7 +1148,6 @@ resize_horizontally(struct terminal *term, int new_width) term->sixel.image.data = new_data; term->sixel.image.width = new_width; term->sixel.row_byte_ofs = term->sixel.pos.row * new_width; - return true; } static bool @@ -1197,11 +1199,14 @@ resize(struct terminal *term, int new_width, int new_height) term->sixel.image.width, term->sixel.image.height, new_width, new_height); - if (new_width > term->sixel.max_width || - new_height > term->sixel.max_height) - { - LOG_WARN("maximum image dimensions reached"); - return false; + if (unlikely(new_width > term->sixel.max_width)) { + LOG_WARN("maximum image width exceeded, truncating"); + new_width = term->sixel.max_width; + } + + if (unlikely(new_height > term->sixel.max_height)) { + LOG_WARN("maximum image height exceeded, truncating"); + new_height = term->sixel.max_height; } uint32_t *old_data = term->sixel.image.data; @@ -1291,9 +1296,9 @@ sixel_add_many(struct terminal *term, uint8_t c, unsigned count) int width = term->sixel.image.width; if (unlikely(col + count - 1 >= width)) { - width = col + count; - if (unlikely(!resize_horizontally(term, width))) - return; + resize_horizontally(term, col + count); + width = term->sixel.image.width; + count = min(count, width - col); } uint32_t color = term->sixel.color; @@ -1412,7 +1417,8 @@ decgra(struct terminal *term, uint8_t c) /* This ensures the sixel’s final image size is *at least* * this large */ - term->sixel.max_non_empty_row_no = pv - 1; + term->sixel.max_non_empty_row_no = + min(pv, term->sixel.image.height) - 1; } term->sixel.state = SIXEL_DECSIXEL; @@ -1445,9 +1451,16 @@ decgri(struct terminal *term, uint8_t c) unsigned count = term->sixel.param; if (likely(count > 0)) sixel_add_many(term, c - 63, count); + else if (unlikely(count == 0)) + sixel_add_many(term, c - 63, 1); term->sixel.state = SIXEL_DECSIXEL; break; } + + default: + term->sixel.state = SIXEL_DECSIXEL; + sixel_put(term, c); + break; } }