URI: 
       tCalculate number of required lines before rendering - ltkx - GUI toolkit for X11 (WIP)
  HTML git clone git://lumidify.org/ltkx.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 16e9709ac835f46a608c339a632806923465e956
   DIR parent cd31b2005fde2440d4277709a0c6efb114718822
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Mon, 11 May 2020 21:22:42 +0200
       
       Calculate number of required lines before rendering
       
       Diffstat:
         M textedit_wip.c                      |      66 +++++++++++++++++++------------
         M textedit_wip.h                      |       7 +++++--
       
       2 files changed, 46 insertions(+), 27 deletions(-)
       ---
   DIR diff --git a/textedit_wip.c b/textedit_wip.c
       t@@ -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,
       t@@ -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;
       t@@ -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);
       t@@ -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;
        }
        
       t@@ -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
       t@@ -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);
       t@@ -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++;
       t@@ -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;
   DIR diff --git a/textedit_wip.h b/textedit_wip.h
       t@@ -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;
       t@@ -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) */