ltkx

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltkx.git
Log | Files | Refs | README | LICENSE

commit 16e9709ac835f46a608c339a632806923465e956
parent cd31b2005fde2440d4277709a0c6efb114718822
Author: lumidify <nobody@lumidify.org>
Date:   Mon, 11 May 2020 21:22:42 +0200

Calculate number of required lines before rendering

Diffstat:
Mtextedit_wip.c | 66+++++++++++++++++++++++++++++++++++++++++-------------------------
Mtextedit_wip.h | 7+++++--
2 files changed, 46 insertions(+), 27 deletions(-)

diff --git a/textedit_wip.c b/textedit_wip.c @@ -44,14 +44,14 @@ extern Ltk *ltk_global; LTK_GAP_BUFFER_INIT_IMPL(uint32, uint32_t) LTK_GAP_BUFFER_INIT_IMPL(script, hb_script_t) LTK_GAP_BUFFER_INIT_IMPL(int, int) -LTK_ARRAY_INIT_IMPL(char_type, FriBidiCharType) LTK_ARRAY_INIT_IMPL(level, FriBidiLevel) LTK_STACK_INIT_IMPL(script, int, hb_script_t, pair_index, script); /* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */ XImage * ltk_render_text_line( - LtkTextLine *tl, + struct ltk_text_line *tl, + int max_width, Display *dpy, Window window, GC gc, @@ -59,10 +59,31 @@ ltk_render_text_line( XColor fg, XColor bg) { + int lines = 0; + int cur_x = 0, cur_y = 0; + struct ltk_text_run *cur = tl->first_run; + do { + for (int i = 0; i < cur->num_glyphs; i++) { + x = cur_x + cur->glyphs[i]->info->xoff + cur->glyphs[i]->x_offset; + if (x > max_width) { + int j = 0; + for (j = i; j >= 0; j--) { + if (glyphs[j]->cluster != glyphs[i]->cluster) { + /* must increase one again so the actual + next character is used */ + j++; + break; + } + } + i = j; + lines++; + } + } + } while (cur = cur->next); XWindowAttributes attrs; XGetWindowAttributes(dpy, window, &attrs); int depth = attrs.depth; - XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, tl->w, tl->h, 32, 0); + XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, max_width, tl->h * lines, 32, 0); img->data = calloc(img->bytes_per_line, img->height); XInitImage(img); int b; @@ -76,7 +97,7 @@ ltk_render_text_line( } } - LtkTextSegment *ts = tl->start_segment; + cur = tl->runs; int x = 0; int y = 0; int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir); @@ -290,6 +311,7 @@ ltk_text_run_create(size_t start_index, size_t len, hb_script_t script, hb_direc run->len = len; run->script = script; run->dir = dir; + run->last = NULL; run->next = NULL; } @@ -323,12 +345,14 @@ ltk_text_line_itemize(struct ltk_text_line *tl) { if (!first_run) { first_run = cur_run = new; } else { - cur->next = new; - cur = new; + cur_run->next = new; + new->last = cur_run; + cur_run = new; } start_index = end_index; } - tl->runs = tl->cur_run = first_run; + tl->first_run = tl->cur_run = first_run; + tl->last_run = cur_run; } static void @@ -348,7 +372,7 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, hb_buffer_t *buf; hb_glyph_info_t *ginf, *gi; hb_glyph_position_t *gpos, *gp; - unsigned int num_glyphs = 0; + tr->num_glyphs = 0; buf = hb_buffer_create(); hb_buffer_set_direction(buf, run->dir); @@ -359,24 +383,23 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, * this should be level 1 clustering instead of level 0 */ hb_buffer_set_cluster_level(buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); hb_shape(font->hb, buf, NULL, 0); - ginf = hb_buffer_get_glyph_infos(buf, &num_glyphs); - gpos = hb_buffer_get_glyph_positions(buf, &num_glyphs); + ginf = hb_buffer_get_glyph_infos(buf, &tr->num_glyphs); + gpos = hb_buffer_get_glyph_positions(buf, &tr->num_glyphs); float scale = stbtt_ScaleForMappingEmToPixels(&tr->font->info, font_size); - LtkGlyph *last_glyph = NULL; int x_min = INT_MAX, x_max = INT_MIN, y_min = INT_MAX, y_max = INT_MIN; int x_abs = 0, y_abs = 0, x1_abs, y1_abs, x2_abs, y2_abs; /* magic, do not touch */ - /* FIXME: array instead of linked list */ + tr->glyphs = malloc(sizeof(LtkGlyph) * num_glyph); + if (!tr->glyphs) { + (void)fprintf("Cannot allocate space for glyphs.\n"); + exit(1); + } LtkGlyph *glyph; - for (int i = 0; i < num_glyphs; i++) { + for (int i = 0; i < tr->num_glyphs; i++) { gi = &ginf[i]; gp = &gpos[i]; - glyph = malloc(sizeof(LtkGlyph)); - if (!glyph) { - (void)fprintf(stderr, "Cannot allocate glyph.\n"); - exit(1); - } + glyph = tr->glyphs[i]; glyph->cluster = gi->cluster; glyph->info = ltk_get_glyph_info(tr->font, gi->codepoint, scale, glyph_cache); glyph->info->refs++; @@ -385,13 +408,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr, glyph->y_offset = (int)(gp->y_offset * scale); glyph->x_advance = (int)(gp->x_advance * scale); glyph->y_advance = (int)(gp->y_advance * scale); - glyph->next = NULL; - if (i == 0) { - tr->start_glyph = glyph; - } else { - last_glyph->next = glyph; - } - last_glyph = glyph; /* Calculate position in order to determine full size of text segment */ x1_abs = x_abs + glyph->info->xoff + glyph->x_offset; diff --git a/textedit_wip.h b/textedit_wip.h @@ -42,8 +42,10 @@ LTK_ARRAY_INIT_DECL(level, FriBidiLevel) LTK_STACK_INIT_DECL(script, int, hb_script_t, pair_index, script); struct ltk_text_run { - struct ltk_glyph *start_glyph; + LtkGlyph *glyphs; + size_t num_glyphs; struct ltk_text_run *next; + struct ltk_text_run *last; size_t start_index; size_t len; LtkFont *font; @@ -66,7 +68,8 @@ struct ltk_text_line { struct ltk_gap_buffer_int *log2vis; struct ltk_gap_buffer_int *vis2log; struct ltk_array_level *bidi_levels; - struct ltk_text_run *runs; /* first node in the linked list of runs */ + struct ltk_text_run *first_run; /* first node in the linked list of runs */ + struct ltk_text_run *last_run; /* last node in the linked list of runs */ struct ltk_text_run *cur_run; /* current node in the linked list of runs */ struct ltk_text_line *next; /* next text line in the buffer */ unsigned int height; /* height of the line (including wrapping) */