diff --git a/src/gtktsm/gtktsm-terminal.c b/src/gtktsm/gtktsm-terminal.c index 8afa0af..335b512 100644 --- a/src/gtktsm/gtktsm-terminal.c +++ b/src/gtktsm/gtktsm-terminal.c @@ -358,7 +358,7 @@ static int create_glyph(struct gtktsm_face *face, { PangoLayoutLine *line; cairo_surface_t *surface; - PangoRectangle rec; + PangoRectangle rec, logical_rec; cairo_format_t format; PangoLayout *layout; cairo_t *cr; @@ -381,8 +381,34 @@ static int create_glyph(struct gtktsm_face *face, break; } + layout = pango_layout_new(face->ctx); + + val = g_ucs4_to_utf8(ch, len, NULL, &ulen, NULL); + if (!val) { + r = -ERANGE; + goto err_layout; + } + + /* render one line only */ + pango_layout_set_height(layout, 0); + /* no line spacing */ + pango_layout_set_spacing(layout, 0); + /* set text to char [+combining-chars] */ + pango_layout_set_text(layout, val, ulen); + + g_free(val); + + cnt = pango_layout_get_line_count(layout); + if (cnt == 0) { + r = -ERANGE; + goto err_layout; + } + + line = pango_layout_get_line_readonly(layout, 0); + pango_layout_line_get_pixel_extents(line, &logical_rec, &rec); + glyph->format = c2f(format); - glyph->width = face->width * glyph->cwidth; + glyph->width = (logical_rec.width > face->width) ? face->width * 2 : face->width * glyph->cwidth; glyph->stride = cairo_format_stride_for_width(format, glyph->width); glyph->height = face->height; @@ -407,31 +433,6 @@ static int create_glyph(struct gtktsm_face *face, } pango_cairo_update_context(cr, face->ctx); - layout = pango_layout_new(face->ctx); - - val = g_ucs4_to_utf8(ch, len, NULL, &ulen, NULL); - if (!val) { - r = -ERANGE; - goto err_layout; - } - - /* render one line only */ - pango_layout_set_height(layout, 0); - /* no line spacing */ - pango_layout_set_spacing(layout, 0); - /* set text to char [+combining-chars] */ - pango_layout_set_text(layout, val, ulen); - - g_free(val); - - cnt = pango_layout_get_line_count(layout); - if (cnt == 0) { - r = -ERANGE; - goto err_layout; - } - - line = pango_layout_get_line_readonly(layout, 0); - pango_layout_line_get_pixel_extents(line, NULL, &rec); cairo_move_to(cr, -rec.x, face->baseline), cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); @@ -442,14 +443,14 @@ static int create_glyph(struct gtktsm_face *face, glyph->surface = surface; return 0; -err_layout: - g_object_unref(layout); - cairo_destroy(cr); err_surface: + cairo_destroy(cr); cairo_surface_destroy(surface); err_buffer: free(glyph->buffer); glyph->buffer = NULL; +err_layout: + g_object_unref(layout); return r; } @@ -945,6 +946,7 @@ static int renderer_draw_cell(struct tsm_screen *screen, unsigned int posy, const struct tsm_screen_attr *attr, tsm_age_t age, + bool overflow_next, void *data) { const struct gtktsm_renderer_ctx *ctx = data; @@ -1040,6 +1042,67 @@ static int renderer_draw_cell(struct tsm_screen *screen, return 0; } +static int gtktsm_get_overflow(struct gtktsm_renderer_ctx *ctx, + const uint32_t *ch, + size_t len, + bool *overflow_next) +{ + PangoLayout *layout; + PangoAttrList *attrlist; + PangoRectangle rec, logical_rec; + PangoLayoutLine *line; + struct gtktsm_face *face = ctx->face_regular; + unsigned int cwidth; + size_t ulen, cnt; + char *val; + + cwidth = tsm_ucs4_get_width(*ch); + if (!cwidth) + return -ERANGE; + + layout = pango_layout_new(face->ctx); + attrlist = pango_layout_get_attributes(layout); + if (attrlist == NULL) { + attrlist = pango_attr_list_new(); + pango_layout_set_attributes(layout, attrlist); + pango_attr_list_unref(attrlist); + } + + /* render one line only */ + pango_layout_set_height(layout, 0); + + /* no line spacing */ + pango_layout_set_spacing(layout, 0); + + val = tsm_ucs4_to_utf8_alloc(ch, len, &ulen); + if (!val) { + return -ERANGE; + } + pango_layout_set_text(layout, val, ulen); + free(val); + + cnt = pango_layout_get_line_count(layout); + if (cnt == 0) { + return -ERANGE; + } + + line = pango_layout_get_line_readonly(layout, 0); + + pango_layout_line_get_pixel_extents(line, &logical_rec, &rec); + + *overflow_next = (cwidth < 2) && (logical_rec.width > face->width); + + return 0; +} + +static int renderer_get_overflow(const uint32_t *ch, + size_t len, + bool *overflow_next, + void *data) +{ + return gtktsm_get_overflow(data, ch, len, overflow_next); +} + static void gtktsm_renderer_draw(const struct gtktsm_renderer_ctx *ctx) { struct gtktsm_renderer *rend = ctx->rend; @@ -1054,6 +1117,7 @@ static void gtktsm_renderer_draw(const struct gtktsm_renderer_ctx *ctx) cairo_surface_flush(rend->surface); rend->age = tsm_screen_draw(ctx->screen, renderer_draw_cell, + renderer_get_overflow, (void*)ctx); cairo_surface_mark_dirty(rend->surface); diff --git a/src/tsm/libtsm.h b/src/tsm/libtsm.h index 23eb472..bda7b19 100644 --- a/src/tsm/libtsm.h +++ b/src/tsm/libtsm.h @@ -181,6 +181,12 @@ typedef int (*tsm_screen_draw_cb) (struct tsm_screen *con, unsigned int posy, const struct tsm_screen_attr *attr, tsm_age_t age, + bool overflow_next, + void *data); + +typedef int (*tsm_screen_overflow_cb) (const uint32_t *ch, + size_t len, + bool *overflow_next, void *data); int tsm_screen_new(struct tsm_screen **out, tsm_log_t log, void *log_data); @@ -263,7 +269,7 @@ void tsm_screen_selection_target(struct tsm_screen *con, int tsm_screen_selection_copy(struct tsm_screen *con, char **out); tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, - void *data); + tsm_screen_overflow_cb overflow_cb, void *data); /** @} */ diff --git a/src/tsm/tsm-render.c b/src/tsm/tsm-render.c index 88ad847..8e28a38 100644 --- a/src/tsm/tsm-render.c +++ b/src/tsm/tsm-render.c @@ -43,7 +43,7 @@ SHL_EXPORT tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, - void *data) + tsm_screen_overflow_cb overflow_cb, void *data) { unsigned int cur_x, cur_y; unsigned int i, j, k; @@ -57,6 +57,7 @@ tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, bool in_sel = false, sel_start = false, sel_end = false; bool was_sel = false; tsm_age_t age; + bool overflow_next = false; if (!con || !draw_cb) return 0; @@ -176,10 +177,18 @@ tsm_age_t tsm_screen_draw(struct tsm_screen *con, tsm_screen_draw_cb draw_cb, id |= 1ULL << (TSM_UCS4_MAX_BITS + 4); ch = tsm_symbol_get(con->sym_table, &cell->ch, &len); - if (cell->ch == 0 || (cell->ch == ' ' && !attr.underline)) + if (cell->ch == 0 || (cell->ch == ' ' && !attr.underline)) { len = 0; + if (overflow_next) { + overflow_next = false; + continue; + } + } else { + ret = overflow_cb(ch, len, &overflow_next, data); + } + ret = draw_cb(con, id, ch, len, cell->width, - j, i, &attr, age, data); + j, i, &attr, age, overflow_next, data); if (ret && warned++ < 3) { llog_debug(con, "cannot draw glyph at %ux%u via text-renderer",