From dfc205e706ef261edcbae0e04e8ba5e1d225a886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 27 Jun 2020 12:45:22 +0200 Subject: [PATCH] sixel: add sixel_split_by_rectangle() This function splits a sixel image into up to four pieces. The four pieces correspond to the relative complement (set difference) of the sixel image and the specified rectangle. Use this function when (possibly) overwriting existing sixel images when generating a new one, i.e. in sixel_unhook(). --- sixel.c | 131 ++++++++++++++++++++++++++++++++------------------------ sixel.h | 1 - 2 files changed, 74 insertions(+), 58 deletions(-) diff --git a/sixel.c b/sixel.c index ea7a9caa..8869e46f 100644 --- a/sixel.c +++ b/sixel.c @@ -164,103 +164,102 @@ sixel_delete_in_range(struct terminal *term, int _start, int _end) } } -void -sixel_delete_at_cursor(struct terminal *term) -{ - sixel_delete_at_point( - term, term->grid->cursor.point.row, term->grid->cursor.point.col); -} - static void -sixel_split(struct terminal *term, struct sixel *six, int row, int col) +sixel_split(struct terminal *term, struct sixel *six, + int row, int col, int height, int width) { - assert(row >= six->pos.row); - assert(row < six->pos.row + six->rows); - assert(col >= six->pos.col); - assert(col < six->pos.col + six->cols); + int rel_above = max(row - six->pos.row, 0); + int rel_below = min(row + height - six->pos.row, six->rows); + int rel_left = max(col - six->pos.col, 0); + int rel_right = min(col + width - six->pos.col, six->cols); - int rel_row = row - six->pos.row; - int rel_col = col - six->pos.col; + assert(rel_above >= 0); + assert(rel_below >= 0); + assert(rel_left >= 0); + assert(rel_right >= 0); - if (rel_row > 0) { + LOG_DBG("SPLIT: six (%p): %dx%d-%dx%d, %dx%d-%dx%d, rel: above=%d, below=%d, left=%d, right=%d", + six, six->pos.row, six->pos.col, six->rows, six->cols, + row, col, height, width, + rel_above, rel_below, rel_left, rel_right); + + if (rel_above > 0) { struct sixel above = { .width = six->width, - .height = rel_row * term->cell_height, - .rows = rel_row, + .height = rel_above * term->cell_height, + .rows = rel_above, .cols = six->cols, .pos = six->pos, }; above.data = malloc(above.width * above.height * sizeof(uint32_t)); memcpy(above.data, six->data, above.width * above.height * sizeof(uint32_t)); - above.pix = pixman_image_create_bits_no_clear( PIXMAN_a8r8g8b8, above.width, above.height, above.data, above.width * sizeof(uint32_t)); - tll_push_back(term->grid->sixel_images, above); } - if (rel_row + 1 < six->rows) { + if (rel_below < six->rows) { struct sixel below = { .width = six->width, - .height = six->height - (rel_row + 1) * term->cell_height, - .rows = six->rows - (rel_row + 1), + .height = six->height - rel_below * term->cell_height, + .rows = six->rows - rel_below, .cols = six->cols, .pos = (struct coord){ six->pos.col, - (six->pos.row + rel_row + 1) & (term->grid->num_rows - 1)}, + (six->pos.row + rel_below) & (term->grid->num_rows - 1)}, }; below.data = malloc(below.width * below.height * sizeof(uint32_t)); memcpy( below.data, - &((const uint32_t *)six->data)[(rel_row + 1) * term->cell_height * six->width], + &((const uint32_t *)six->data)[rel_below * term->cell_height * six->width], below.width * below.height * sizeof(uint32_t)); below.pix = pixman_image_create_bits_no_clear( PIXMAN_a8r8g8b8, below.width, below.height, below.data, below.width * sizeof(uint32_t)); - tll_push_back(term->grid->sixel_images, below); } - if (rel_col > 0) { + if (rel_left > 0) { struct sixel left = { - .width = rel_col * term->cell_width, - .height = min(term->cell_height, six->height - rel_row * term->cell_height), + .width = rel_left * term->cell_width, + .height = min(term->cell_height, six->height - rel_above * term->cell_height), .rows = 1, - .cols = rel_col, - .pos = (struct coord){six->pos.col, - (six->pos.row + rel_row) & (term->grid->num_rows - 1)}, + .cols = rel_left, + .pos = (struct coord){ + six->pos.col, + (six->pos.row + rel_above) & (term->grid->num_rows - 1)}, }; left.data = malloc(left.width * left.height * sizeof(uint32_t)); for (size_t i = 0; i < term->cell_height; i++) memcpy( &((uint32_t *)left.data)[i * left.width], - &((const uint32_t *)six->data)[(rel_row * term->cell_height + i) * six->width], + &((const uint32_t *)six->data)[(rel_above * term->cell_height + i) * six->width], left.width * sizeof(uint32_t)); left.pix = pixman_image_create_bits_no_clear( PIXMAN_a8r8g8b8, left.width, left.height, left.data, left.width * sizeof(uint32_t)); tll_push_back(term->grid->sixel_images, left); - } - if (rel_col + 1 < six->cols) { + if (rel_right < six->cols) { struct sixel right = { - .width = six->width - (rel_col + 1) * term->cell_width, - .height = min(term->cell_height, six->height - rel_row * term->cell_height), + .width = six->width - rel_right * term->cell_width, + .height = min(term->cell_height, six->height - rel_above * term->cell_height), .rows = 1, - .cols = six->cols - (rel_col + 1), - .pos = (struct coord){six->pos.col + rel_col + 1, - (six->pos.row + rel_row) & (term->grid->num_rows - 1)}, + .cols = six->cols - rel_right, + .pos = (struct coord){ + six->pos.col + rel_right, + (six->pos.row + rel_above) & (term->grid->num_rows - 1)}, }; right.data = malloc(right.width * right.height * sizeof(uint32_t)); for (size_t i = 0; i < term->cell_height; i++) memcpy( &((uint32_t *)right.data)[i * right.width], - &((const uint32_t *)six->data)[(rel_row * term->cell_height + i) * six->width + (rel_col + 1) * term->cell_width], + &((const uint32_t *)six->data)[(rel_above * term->cell_height + i) * six->width + rel_right * term->cell_width], right.width * sizeof(uint32_t)); right.pix = pixman_image_create_bits_no_clear( PIXMAN_a8r8g8b8, @@ -270,27 +269,46 @@ sixel_split(struct terminal *term, struct sixel *six, int row, int col) } } -void -sixel_split_at_point(struct terminal *term, int _row, int col) +static void +sixel_split_by_rectangle(struct terminal *term, int _row, + int col, int height, int width) { if (likely(tll_length(term->grid->sixel_images) == 0)) return; - const int row = (term->grid->offset + _row) & (term->grid->num_rows - 1); + const int start = (term->grid->offset + _row) & (term->grid->num_rows - 1); + const int end = (start + height - 1) & (term->grid->num_rows - 1); + const bool wraps = end < start; tll_foreach(term->grid->sixel_images, it) { struct sixel *six = &it->item; const int six_start = six->pos.row; - const int six_end = six_start + six->rows - 1; + const int six_end = (six_start + six->rows - 1) & (term->grid->num_rows - 1); + const bool six_wraps = six_end < six_start; - if (row >= six_start && row <= six_end) { + if ((six_wraps == wraps && + ((start <= six_start && end >= six_start) || /* Crosses sixel start boundary */ + (start <= six_end && end >= six_end) || /* Crosses sixel end boundary */ + (start >= six_start && end <= six_end))) || /* Fully within sixel range */ + (six_wraps && !wraps && + ((start <= six_start && end >= six_start) || + (start <= six_end && end >= six_end) || + (start >= six_start || end <= six_end))) || + (!six_wraps && wraps && + ((six_start <= start && six_end >= end) || /* Sixel croses region start boundary */ + (six_start <= end && six_end >= end) || /* Sixel crosses region end boundary */ + (six_start >= start || six_end <= end))) /* Sixel is fully enclosed by region */ + ) + { const int col_start = six->pos.col; - const int col_end = six->pos.col + six->cols; + const int col_end = six->pos.col + six->cols - 1; - if (col >= col_start && col < col_end) { - //sixel_erase(term, six); - sixel_split(term, six, row, col); + if ((col <= col_start && col + width - 1 >= col_start) || + (col <= col_end && col + width - 1 >= col_end) || + (col >= col_start && col + width - 1 <= col_end)) + { + sixel_split(term, six, start, col, height, width); sixel_erase(term, six); tll_remove(term->grid->sixel_images, it); } @@ -301,14 +319,13 @@ sixel_split_at_point(struct terminal *term, int _row, int col) void sixel_split_at_cursor(struct terminal *term) { - sixel_split_at_point(term, term->grid->cursor.point.row, term->grid->cursor.point.col); + sixel_split_by_rectangle( + term, term->grid->cursor.point.row, term->grid->cursor.point.col, 1, 1); } void sixel_unhook(struct terminal *term) { - //sixel_delete_at_cursor(term); - struct sixel image = { .data = term->sixel.image.data, .width = term->sixel.image.width, @@ -320,12 +337,12 @@ sixel_unhook(struct terminal *term) (term->grid->offset + term->grid->cursor.point.row) & (term->grid->num_rows - 1)}, }; - for (int row = 0; row < image.rows; row++) { - for (int col = 0; col < image.cols; col++) - sixel_split_at_point(term, term->grid->cursor.point.row + row, term->grid->cursor.point.col + col); - } + sixel_split_by_rectangle( + term, + term->grid->cursor.point.row, term->grid->cursor.point.col, + image.rows, image.cols); - LOG_DBG("generating %dx%d pixman image", image.width, image.height); + LOG_DBG("generating %dx%d pixman image at %d-%d", image.width, image.height, image.pos.row, image.pos.row + image.rows); image.pix = pixman_image_create_bits_no_clear( PIXMAN_a8r8g8b8, diff --git a/sixel.h b/sixel.h index 2f3b0d86..bb3b6cb0 100644 --- a/sixel.h +++ b/sixel.h @@ -14,7 +14,6 @@ void sixel_destroy(struct sixel *sixel); void sixel_delete_in_range(struct terminal *term, int start, int end); void sixel_delete_at_row(struct terminal *term, int _row); -void sixel_delete_at_cursor(struct terminal *term); void sixel_split_at_cursor(struct terminal *term); void sixel_colors_report_current(struct terminal *term);