Exemple #1
0
unsigned int tsm_symbol_get_width(struct tsm_symbol_table *tbl,
				  tsm_symbol_t sym)
{
	const uint32_t *ch;
	size_t len;

	if (!tbl)
		return 0;

	ch = tsm_symbol_get(tbl, &sym, &len);
	if (len == 0)
		return 0;

	return tsm_ucs4_get_width(*ch);
}
Exemple #2
0
SHL_EXPORT
unsigned int tsm_symbol_get_width(struct tsm_symbol_table *tbl,
				  tsm_symbol_t sym)
{
	int ret;
	const uint32_t *ch;
	size_t len;

	if (!tbl)
		tbl = tsm_symbol_table_default;

	if (!tbl) {
		ret = tsm_symbol_table_new(&tbl);
		if (ret)
			return sym;
		tsm_symbol_table_default = tbl;
	}

	ch = tsm_symbol_get(tbl, &sym, &len);
	if (len == 0)
		return 0;

	return tsm_ucs4_get_width(*ch);
}
Exemple #3
0
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 = &empty;

			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.underline = !attr.underline;
                                //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;
	}
}
Exemple #4
0
tsm_symbol_t tsm_symbol_append(struct tsm_symbol_table *tbl,
			       tsm_symbol_t sym, uint32_t ucs4)
{
	uint32_t buf[TSM_UCS4_MAXLEN + 1], nsym, *nval;
	const uint32_t *ptr;
	size_t s;
	bool res;
	int ret;

	if (!tbl)
		return sym;

	if (ucs4 > TSM_UCS4_MAX)
		return sym;

	ptr = tsm_symbol_get(tbl, &sym, &s);
	if (s >= TSM_UCS4_MAXLEN)
		return sym;

	memcpy(buf, ptr, s * sizeof(uint32_t));
	buf[s++] = ucs4;
	buf[s++] = TSM_UCS4_MAX + 1;

	res = shl_htable_lookup(&tbl->symbols, buf, hash_ucs4(buf, NULL),
				(void**)&nval);
	if (res) {
		/* key is prefixed with actual value */
		return *--nval;
	}

	/* We save the key in nval and prefix it with the new ID. Note that
	 * the prefix is hidden, we actually store "++nval" in the htable. */
	nval = malloc(sizeof(uint32_t) * (s + 1));
	if (!nval)
		return sym;

	++nval;
	memcpy(nval, buf, s * sizeof(uint32_t));

	nsym = tbl->next_id + 1;
	/* Out of IDs; we actually have 2 Billion IDs so this seems
	 * very unlikely but lets be safe here */
	if (nsym <= tbl->next_id++)
		goto err_id;

	/* store ID hidden before the key */
	*(nval - 1) = nsym;

	ret = shl_htable_insert(&tbl->symbols, nval, hash_ucs4(nval, NULL));
	if (ret)
		goto err_id;

	ret = shl_array_push(tbl->index, &nval);
	if (ret)
		goto err_symbol;

	return nsym;

err_symbol:
	shl_htable_remove(&tbl->symbols, nval, hash_ucs4(nval, NULL), NULL);
err_id:
	--tbl->next_id;
	free(nval);
	return sym;
}
Exemple #5
0
SHL_EXPORT
tsm_symbol_t tsm_symbol_append(struct tsm_symbol_table *tbl,
			       tsm_symbol_t sym, uint32_t ucs4)
{
	uint32_t buf[TSM_UCS4_MAXLEN + 1], nsym, *nval;
	const uint32_t *ptr;
	size_t s;
	void *tmp;
	bool res;
	int ret;

	if (!tbl)
		tbl = tsm_symbol_table_default;

	if (!tbl) {
		ret = tsm_symbol_table_new(&tbl);
		if (ret)
			return sym;
		tsm_symbol_table_default = tbl;
	}

	if (ucs4 > TSM_UCS4_MAX)
		return sym;

	ptr = tsm_symbol_get(tbl, &sym, &s);
	if (s >= TSM_UCS4_MAXLEN)
		return sym;

	memcpy(buf, ptr, s * sizeof(uint32_t));
	buf[s++] = ucs4;
	buf[s++] = TSM_UCS4_MAX + 1;

	res = shl_hashtable_find(tbl->symbols, &tmp, buf);
	if (res)
		return (uint32_t)(long)tmp;

	nval = malloc(sizeof(uint32_t) * s);
	if (!nval)
		return sym;

	memcpy(nval, buf, s * sizeof(uint32_t));
	nsym = tbl->next_id + 1;
	/* Out of IDs; we actually have 2 Billion IDs so this seems
	 * very unlikely but lets be safe here */
	if (nsym <= tbl->next_id++)
		goto err_id;

	ret = shl_hashtable_insert(tbl->symbols, nval, (void*)(long)nsym);
	if (ret)
		goto err_id;

	ret = shl_array_push(tbl->index, &nval);
	if (ret)
		goto err_symbol;

	return nsym;

err_symbol:
	shl_hashtable_remove(tbl->symbols, nval);
err_id:
	--tbl->next_id;
	free(nval);
	return sym;
}
Exemple #6
0
void tsm_screen_draw(struct tsm_screen *con,
			 tsm_screen_prepare_cb prepare_cb,
			 tsm_screen_draw_cb draw_cb,
			 tsm_screen_render_cb render_cb,
			 void *data)
{
	unsigned int cur_x, cur_y;
	unsigned int i, j, k;
	struct line *iter, *line = NULL;
	struct cell *cell;
	struct tsm_screen_attr attr;
	bool cursor_done = false;
	int ret, warned = 0;
	uint64_t time_prep = 0, time_draw = 0, time_rend = 0;
	const uint32_t *ch;
	size_t len;
	struct cell empty;

	if (!con || !draw_cb)
		return;

	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;

	/* render preparation */

	if (prepare_cb) {
		if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING)
			shl_timer_reset(con->timer);

		ret = prepare_cb(con, data);
		if (ret) {
			llog_warning(con,
				     "cannot prepare text-renderer for rendering");
			return;
		}

		if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING)
			time_prep = shl_timer_elapsed(con->timer);
	} else {
		time_prep = 0;
	}

	/* push each character into rendering pipeline */

	if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING)
		shl_timer_reset(con->timer);

	iter = con->sb_pos;
	k = 0;
	for (i = 0; i < con->size_y; ++i) {
		if (iter) {
			line = iter;
			iter = iter->next;
		} else {
			line = con->lines[k];
			k++;
		}

		for (j = 0; j < con->size_x; ++j) {
			if (j < line->size)
				cell = &line->cells[j];
			else
				cell = &empty;
			memcpy(&attr, &cell->attr, sizeof(attr));

			if (k == cur_y + 1 &&
			    j == cur_x) {
				cursor_done = true;
				if (!(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;

			ch = tsm_symbol_get(NULL, &cell->ch, &len);
			if (cell->ch == ' ' || cell->ch == 0)
				len = 0;
			ret = draw_cb(con, cell->ch, ch, len, j, i, &attr,
				      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 (k == cur_y + 1 && !cursor_done) {
			cursor_done = true;
			if (!(con->flags & TSM_SCREEN_HIDE_CURSOR)) {
				if (!(con->flags & TSM_SCREEN_INVERSE))
					attr.inverse = !attr.inverse;
				draw_cb(con, 0, NULL, 0, cur_x, i, &attr, data);
			}
		}
	}

	if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING)
		time_draw = shl_timer_elapsed(con->timer);

	/* perform final rendering steps */

	if (render_cb) {
		if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING)
			shl_timer_reset(con->timer);

		ret = render_cb(con, data);
		if (ret)
			llog_warning(con,
				     "cannot render via text-renderer");

		if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING)
			time_rend = shl_timer_elapsed(con->timer);
	} else {
		time_rend = 0;
	}

	if (con->opts & TSM_SCREEN_OPT_RENDER_TIMING)
		llog_debug(con,
			   "timing: sum: %" PRIu64 " prepare: %" PRIu64 " draw: %" PRIu64 " render: %" PRIu64,
			   time_prep + time_draw + time_rend,
			   time_prep, time_draw, time_rend);
}