From 6d1cc890183fb6a433f4683aba98cdc8d6fe8549 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 12 Nov 2013 22:59:46 +0100 Subject: screen: move renderer to separate file Move the screen rendering helpers into a separate file. They keep getting bigger and are totally separate from screen manipulation. Thus, keep it separate so we can easily simplify it later. Signed-off-by: David Herrmann --- Makefile.am | 1 + src/libtsm_int.h | 2 + src/tsm_render.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tsm_screen.c | 168 ++++--------------------------------------------- 4 files changed, 201 insertions(+), 156 deletions(-) create mode 100644 src/tsm_render.c diff --git a/Makefile.am b/Makefile.am index a052755..a484292 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,6 +119,7 @@ libtsm_la_SOURCES = \ src/tsm_unicode.c \ src/tsm_screen.c \ src/tsm_selection.c \ + src/tsm_render.c \ src/tsm_vte.c \ src/tsm_vte_charsets.c \ external/wcwidth.h \ diff --git a/src/libtsm_int.h b/src/libtsm_int.h index c9faf54..9de690e 100644 --- a/src/libtsm_int.h +++ b/src/libtsm_int.h @@ -149,6 +149,8 @@ struct tsm_screen { struct selection_pos sel_end; }; +void screen_cell_init(struct tsm_screen *con, struct cell *cell); + void tsm_screen_set_opts(struct tsm_screen *scr, unsigned int opts); void tsm_screen_reset_opts(struct tsm_screen *scr, unsigned int opts); unsigned int tsm_screen_get_opts(struct tsm_screen *scr); diff --git a/src/tsm_render.c b/src/tsm_render.c new file mode 100644 index 0000000..03cbbbf --- /dev/null +++ b/src/tsm_render.c @@ -0,0 +1,186 @@ +/* + * libtsm - Rendering + * + * Copyright (c) 2011-2013 David Herrmann + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Rendering + * TSM does not depend on any graphics system or rendering libraries. Instead, + * it provides iterators and ageing support so you can implement renderers + * yourself. + */ + +#include +#include +#include +#include +#include +#include "libtsm.h" +#include "libtsm_int.h" +#include "shl_llog.h" + +#define LLOG_SUBSYSTEM "tsm_render" + +SHL_EXPORT +tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, + void *data) +{ + unsigned int cur_x, cur_y; + unsigned int i, j, k; + struct line *iter, *line = NULL; + struct cell *cell, empty; + struct tsm_screen_attr attr; + int ret, warned = 0; + const uint32_t *ch; + size_t len; + bool in_sel = false, sel_start = false, sel_end = false; + bool was_sel = false; + tsm_age_t age; + + if (!con || !draw_cb) + return 0; + + screen_cell_init(con, &empty); + + cur_x = con->cursor_x; + if (con->cursor_x >= con->size_x) + cur_x = con->size_x - 1; + cur_y = con->cursor_y; + if (con->cursor_y >= con->size_y) + cur_y = con->size_y - 1; + + /* push each character into rendering pipeline */ + + iter = con->sb_pos; + k = 0; + + if (con->sel_active) { + if (!con->sel_start.line && con->sel_start.y == SELECTION_TOP) + in_sel = !in_sel; + if (!con->sel_end.line && con->sel_end.y == SELECTION_TOP) + in_sel = !in_sel; + + if (con->sel_start.line && + (!iter || con->sel_start.line->sb_id < iter->sb_id)) + in_sel = !in_sel; + if (con->sel_end.line && + (!iter || con->sel_end.line->sb_id < iter->sb_id)) + in_sel = !in_sel; + } + + for (i = 0; i < con->size_y; ++i) { + if (iter) { + line = iter; + iter = iter->next; + } else { + line = con->lines[k]; + k++; + } + + if (con->sel_active) { + if (con->sel_start.line == line || + (!con->sel_start.line && + con->sel_start.y == k - 1)) + sel_start = true; + else + sel_start = false; + if (con->sel_end.line == line || + (!con->sel_end.line && + con->sel_end.y == k - 1)) + sel_end = true; + else + sel_end = false; + + was_sel = false; + } + + for (j = 0; j < con->size_x; ++j) { + if (j < line->size) + cell = &line->cells[j]; + else + cell = ∅ + + memcpy(&attr, &cell->attr, sizeof(attr)); + + if (con->sel_active) { + if (sel_start && + j == con->sel_start.x) { + was_sel = in_sel; + in_sel = !in_sel; + } + if (sel_end && + j == con->sel_end.x) { + was_sel = in_sel; + in_sel = !in_sel; + } + } + + if (k == cur_y + 1 && j == cur_x && + !(con->flags & TSM_SCREEN_HIDE_CURSOR)) + attr.inverse = !attr.inverse; + + /* TODO: do some more sophisticated inverse here. When + * INVERSE mode is set, we should instead just select + * inverse colors instead of switching background and + * foreground */ + if (con->flags & TSM_SCREEN_INVERSE) + attr.inverse = !attr.inverse; + + if (in_sel || was_sel) { + was_sel = false; + attr.inverse = !attr.inverse; + } + + if (con->age_reset) { + age = 0; + } else { + age = cell->age; + if (line->age > age) + age = line->age; + if (con->age > age) + age = con->age; + } + + ch = tsm_symbol_get(con->sym_table, &cell->ch, &len); + if (cell->ch == ' ' || cell->ch == 0) + len = 0; + ret = draw_cb(con, cell->ch, ch, len, cell->width, + j, i, &attr, age, data); + if (ret && warned++ < 3) { + llog_debug(con, + "cannot draw glyph at %ux%u via text-renderer", + j, i); + if (warned == 3) + llog_debug(con, + "suppressing further warnings during this rendering round"); + } + } + } + + if (con->age_reset) { + con->age_reset = 0; + return 0; + } else { + return con->age_cnt; + } +} diff --git a/src/tsm_screen.c b/src/tsm_screen.c index ed84718..1813ed1 100644 --- a/src/tsm_screen.c +++ b/src/tsm_screen.c @@ -110,7 +110,7 @@ static void move_cursor(struct tsm_screen *con, unsigned int x, unsigned int y) c->age = con->age_cnt; } -static void cell_init(struct tsm_screen *con, struct cell *cell) +void screen_cell_init(struct tsm_screen *con, struct cell *cell) { cell->ch = 0; cell->width = 1; @@ -142,7 +142,7 @@ static int line_new(struct tsm_screen *con, struct line **out, } for (i = 0; i < width; ++i) - cell_init(con, &line->cells[i]); + screen_cell_init(con, &line->cells[i]); *out = line; return 0; @@ -170,7 +170,7 @@ static int line_resize(struct tsm_screen *con, struct line *line, line->cells = tmp; while (line->size < width) { - cell_init(con, &line->cells[line->size]); + screen_cell_init(con, &line->cells[line->size]); ++line->size; } } @@ -293,7 +293,7 @@ static void screen_scroll_up(struct tsm_screen *con, unsigned int num) } else { cache[i] = con->lines[pos]; for (j = 0; j < con->size_x; ++j) - cell_init(con, &cache[i]->cells[j]); + screen_cell_init(con, &cache[i]->cells[j]); } } @@ -352,7 +352,7 @@ static void screen_scroll_down(struct tsm_screen *con, unsigned int num) for (i = 0; i < num; ++i) { cache[i] = con->lines[con->margin_bottom - i]; for (j = 0; j < con->size_x; ++j) - cell_init(con, &cache[i]->cells[j]); + screen_cell_init(con, &cache[i]->cells[j]); } if (num < max) { @@ -440,7 +440,7 @@ static void screen_erase_region(struct tsm_screen *con, if (protect && line->cells[x_from].attr.protect) continue; - cell_init(con, &line->cells[x_from]); + screen_cell_init(con, &line->cells[x_from]); } x_from = 0; } @@ -678,7 +678,7 @@ int tsm_screen_resize(struct tsm_screen *con, unsigned int x, i = start; for ( ; i < con->main_lines[j]->size; ++i) - cell_init(con, &con->main_lines[j]->cells[i]); + screen_cell_init(con, &con->main_lines[j]->cells[i]); /* alt-lines never go into SB, only clear visible cells */ i = 0; @@ -686,7 +686,7 @@ int tsm_screen_resize(struct tsm_screen *con, unsigned int x, i = con->size_x; for ( ; i < x; ++i) - cell_init(con, &con->alt_lines[j]->cells[i]); + screen_cell_init(con, &con->alt_lines[j]->cells[i]); } /* xterm destroys margins on resize, so do we */ @@ -1357,7 +1357,7 @@ void tsm_screen_insert_lines(struct tsm_screen *con, unsigned int num) for (i = 0; i < num; ++i) { cache[i] = con->lines[con->margin_bottom - i]; for (j = 0; j < con->size_x; ++j) - cell_init(con, &cache[i]->cells[j]); + screen_cell_init(con, &cache[i]->cells[j]); } if (num < max) { @@ -1397,7 +1397,7 @@ void tsm_screen_delete_lines(struct tsm_screen *con, unsigned int num) for (i = 0; i < num; ++i) { cache[i] = con->lines[con->cursor_y + i]; for (j = 0; j < con->size_x; ++j) - cell_init(con, &cache[i]->cells[j]); + screen_cell_init(con, &cache[i]->cells[j]); } if (num < max) { @@ -1442,7 +1442,7 @@ void tsm_screen_insert_chars(struct tsm_screen *con, unsigned int num) mv * sizeof(*cells)); for (i = 0; i < num; ++i) - cell_init(con, &cells[con->cursor_x + i]); + screen_cell_init(con, &cells[con->cursor_x + i]); } SHL_EXPORT @@ -1475,7 +1475,7 @@ void tsm_screen_delete_chars(struct tsm_screen *con, unsigned int num) mv * sizeof(*cells)); for (i = 0; i < num; ++i) - cell_init(con, &cells[con->cursor_x + mv + i]); + screen_cell_init(con, &cells[con->cursor_x + mv + i]); } SHL_EXPORT @@ -1604,147 +1604,3 @@ void tsm_screen_erase_screen(struct tsm_screen *con, bool protect) screen_erase_region(con, 0, 0, con->size_x - 1, con->size_y - 1, protect); } - -SHL_EXPORT -tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, - void *data) -{ - unsigned int cur_x, cur_y; - unsigned int i, j, k; - struct line *iter, *line = NULL; - struct cell *cell, empty; - struct tsm_screen_attr attr; - int ret, warned = 0; - const uint32_t *ch; - size_t len; - bool in_sel = false, sel_start = false, sel_end = false; - bool was_sel = false; - tsm_age_t age; - - if (!con || !draw_cb) - return 0; - - cell_init(con, &empty); - - cur_x = con->cursor_x; - if (con->cursor_x >= con->size_x) - cur_x = con->size_x - 1; - cur_y = con->cursor_y; - if (con->cursor_y >= con->size_y) - cur_y = con->size_y - 1; - - /* push each character into rendering pipeline */ - - iter = con->sb_pos; - k = 0; - - if (con->sel_active) { - if (!con->sel_start.line && con->sel_start.y == SELECTION_TOP) - in_sel = !in_sel; - if (!con->sel_end.line && con->sel_end.y == SELECTION_TOP) - in_sel = !in_sel; - - if (con->sel_start.line && - (!iter || con->sel_start.line->sb_id < iter->sb_id)) - in_sel = !in_sel; - if (con->sel_end.line && - (!iter || con->sel_end.line->sb_id < iter->sb_id)) - in_sel = !in_sel; - } - - for (i = 0; i < con->size_y; ++i) { - if (iter) { - line = iter; - iter = iter->next; - } else { - line = con->lines[k]; - k++; - } - - if (con->sel_active) { - if (con->sel_start.line == line || - (!con->sel_start.line && - con->sel_start.y == k - 1)) - sel_start = true; - else - sel_start = false; - if (con->sel_end.line == line || - (!con->sel_end.line && - con->sel_end.y == k - 1)) - sel_end = true; - else - sel_end = false; - - was_sel = false; - } - - for (j = 0; j < con->size_x; ++j) { - if (j < line->size) - cell = &line->cells[j]; - else - cell = ∅ - - memcpy(&attr, &cell->attr, sizeof(attr)); - - if (con->sel_active) { - if (sel_start && - j == con->sel_start.x) { - was_sel = in_sel; - in_sel = !in_sel; - } - if (sel_end && - j == con->sel_end.x) { - was_sel = in_sel; - in_sel = !in_sel; - } - } - - if (k == cur_y + 1 && j == cur_x && - !(con->flags & TSM_SCREEN_HIDE_CURSOR)) - attr.inverse = !attr.inverse; - - /* TODO: do some more sophisticated inverse here. When - * INVERSE mode is set, we should instead just select - * inverse colors instead of switching background and - * foreground */ - if (con->flags & TSM_SCREEN_INVERSE) - attr.inverse = !attr.inverse; - - if (in_sel || was_sel) { - was_sel = false; - attr.inverse = !attr.inverse; - } - - if (con->age_reset) { - age = 0; - } else { - age = cell->age; - if (line->age > age) - age = line->age; - if (con->age > age) - age = con->age; - } - - ch = tsm_symbol_get(con->sym_table, &cell->ch, &len); - if (cell->ch == ' ' || cell->ch == 0) - len = 0; - ret = draw_cb(con, cell->ch, ch, len, cell->width, - j, i, &attr, age, data); - if (ret && warned++ < 3) { - llog_debug(con, - "cannot draw glyph at %ux%u via text-renderer", - j, i); - if (warned == 3) - llog_debug(con, - "suppressing further warnings during this rendering round"); - } - } - } - - if (con->age_reset) { - con->age_reset = 0; - return 0; - } else { - return con->age_cnt; - } -} -- cgit v1.2.3