URI: 
       tImprove array; store wrapping indeces for paragraphs - 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 48e6e0b3b9804877d23cf36c1390352115340689
   DIR parent 16e9709ac835f46a608c339a632806923465e956
  HTML Author: lumidify <nobody@lumidify.org>
       Date:   Tue, 12 May 2020 18:22:40 +0200
       
       Improve array; store wrapping indeces for paragraphs
       
       Diffstat:
         M array.h                             |      20 ++++++++++++++++++--
         M gap_buffer.h                        |       4 ++++
         M textedit_wip.c                      |     109 +++++++++++++++++--------------
         M textedit_wip.h                      |       7 ++++++-
       
       4 files changed, 87 insertions(+), 53 deletions(-)
       ---
   DIR diff --git a/array.h b/array.h
       t@@ -35,7 +35,9 @@ struct ltk_array_##name {                                                                \
        }                                                                                        \
        struct ltk_array_##name *ltk_array_create_##name(size_t initial_len);                        \
        void ltk_array_resize_##name(struct ltk_array_##name *ar, size_t size);                        \
       -void ltk_array_destroy_##name(struct ltk_array_##name *ar);
       +void ltk_array_destroy_##name(struct ltk_array_##name *ar);                                \
       +void ltk_array_clear_##name(struct ltk_array_##name *ar);                                \
       +void ltk_array_append_##name(struct ltk_array_##name *ar, type elem);
        
        #define LTK_ARRAY_INIT_IMPL(name, type)                                                        \
        struct ltk_array_##name *                                                                \
       t@@ -56,12 +58,26 @@ error:                                                                                        \
        }                                                                                        \
                                                                                                \
        void                                                                                        \
       +ltk_array_append_##name(struct ltk_array_##name *ar, type elem) {                        \
       +        if (ar->len == ar->buf_size)                                                        \
       +                ltk_array_resize_##name(ar, ar->len + 1);                                \
       +        ar->buf[ar->len] = elem;                                                        \
       +        ar->len++;                                                                        \
       +}                                                                                        \
       +                                                                                        \
       +void                                                                                        \
       +ltk_array_clear_##name(struct ltk_array_##name *ar) {                                        \
       +        ar->len = 0;                                                                        \
       +        ltk_array_resize_##name(ar, 1);                                                        \
       +}                                                                                        \
       +                                                                                        \
       +void                                                                                        \
        ltk_array_resize_##name(struct ltk_array_##name *ar, size_t len) {                        \
                size_t new_size;                                                                \
                if (4 * len <= ar->buf_size) {                                                        \
                        new_size = 2 * len;                                                        \
                }                                                                                \
       -        } else if (len > ar->len) {                                                        \
       +        } else if (len > ar->buf_size) {                                                \
                        new_size = 2 * len;                                                        \
                } else {                                                                        \
                        return;                                                                        \
   DIR diff --git a/gap_buffer.h b/gap_buffer.h
       t@@ -106,6 +106,10 @@ ltk_gap_buffer_get_##name(                                                        \
                exit(1);                                                                \
        }                                                                                \
                                                                                        \
       +/* FIXME:                                                                        \
       +   a) use memmove()                                                                \
       +   b) properly calculate the most efficient larger size                                \
       +*/                                                                                \
        void                                                                                \
        ltk_gap_buffer_resize_gap_##name(                                                \
            struct ltk_gap_buffer_##name *gb, int len) {                                \
   DIR diff --git a/textedit_wip.c b/textedit_wip.c
       t@@ -45,6 +45,7 @@ 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(level, FriBidiLevel)
       +LTK_ARRAY_INIT_IMPL(int, int)
        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 */
       t@@ -59,13 +60,17 @@ ltk_render_text_line(
                XColor fg,
                XColor bg)
        {
       -        int lines = 0;
                int cur_x = 0, cur_y = 0;
       +        int par_is_rtl = FRIBIDI_IS_RTL(tl->dir);
       +        ltk_array_clear_int(tl->wrap_indeces);
       +        tl->wrap_num = 0;
       +
       +        /* FIXME: wrap bidi text properly */
                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) {
       +                        cur_x += cur->glyphs[i]->x_advance;
       +                        if (cur_x > max_width) {
                                        int j = 0;
                                        for (j = i; j >= 0; j--) {
                                                if (glyphs[j]->cluster != glyphs[i]->cluster) {
       t@@ -76,16 +81,20 @@ ltk_render_text_line(
                                                }
                                        }
                                        i = j;
       -                                lines++;
       +                                ltk_array_append_int(tl->wrap_indeces, cur->start_index + i);
       +                                tl->wrap_num++;
       +                                cur_x = 0;
                                }
                        }
                } while (cur = cur->next);
       +
                XWindowAttributes attrs;
                XGetWindowAttributes(dpy, window, &attrs);
                int depth = attrs.depth;
       -        XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, max_width, tl->h * lines, 32, 0);
       +        XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, max_width, tl->h * (tl->wrap_num + 1), 32, 0);
                img->data = calloc(img->bytes_per_line, img->height);
                XInitImage(img);
       +
                int b;
                for (int i = 0; i < tl->h; i++) {
                        b = img->bytes_per_line * i;
       t@@ -97,20 +106,13 @@ ltk_render_text_line(
                        }
                }
        
       -        cur = tl->runs;
       +        cur = tl->first_run;
                int x = 0;
                int y = 0;
       -        int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir);
                do {
       -                if (is_hor) {
       -                        y = tl->h - tl->y_max;
       -                        ltk_render_text_segment(ts, x + ts->start_x, y, img, fg);
       -                        x += ts->w;
       -                } else {
       -                        x = tl->w - tl->x_max;
       -                        ltk_render_text_segment(ts, x, y + ts->start_y, img, fg);
       -                        y += ts->h;
       -                }
       +                y = tl->h - tl->y_max;
       +                ltk_render_text_segment(ts, x + ts->start_x, y, img, fg);
       +                x += ts->w;
                } while (ts = ts->next);
        
                return img;
       t@@ -177,42 +179,41 @@ when reshaping with context, only the text in the current run has to be passed a
        /* Special paired characters for script detection */
        static size_t paired_len = 34;
        static const FriBidiChar paired_chars[] = {
       -  0x0028, 0x0029, /* ascii paired punctuation */
       -  0x003c, 0x003e,
       -  0x005b, 0x005d,
       -  0x007b, 0x007d,
       -  0x00ab, 0x00bb, /* guillemets */
       -  0x2018, 0x2019, /* general punctuation */
       -  0x201c, 0x201d,
       -  0x2039, 0x203a,
       -  0x3008, 0x3009, /* chinese paired punctuation */
       -  0x300a, 0x300b,
       -  0x300c, 0x300d,
       -  0x300e, 0x300f,
       -  0x3010, 0x3011,
       -  0x3014, 0x3015,
       -  0x3016, 0x3017,
       -  0x3018, 0x3019,
       -  0x301a, 0x301b
       +        0x0028, 0x0029, /* ascii paired punctuation */
       +        0x003c, 0x003e,
       +        0x005b, 0x005d,
       +        0x007b, 0x007d,
       +        0x00ab, 0x00bb, /* guillemets */
       +        0x2018, 0x2019, /* general punctuation */
       +        0x201c, 0x201d,
       +        0x2039, 0x203a,
       +        0x3008, 0x3009, /* chinese paired punctuation */
       +        0x300a, 0x300b,
       +        0x300c, 0x300d,
       +        0x300e, 0x300f,
       +        0x3010, 0x3011,
       +        0x3014, 0x3015,
       +        0x3016, 0x3017,
       +        0x3018, 0x3019,
       +        0x301a, 0x301b
        };
        
        static int
        get_pair_index (const FriBidiChar ch) {
       -  int lower = 0;
       -  int upper = paired_len - 1;
       -
       -  while (lower <= upper)
       -  {
       -    int mid = (lower + upper) / 2;
       -    if (ch < paired_chars[mid])
       -      upper = mid - 1;
       -    else if (ch > paired_chars[mid])
       -      lower = mid + 1;
       -    else
       -      return mid;
       -  }
       -
       -  return -1;
       +        int lower = 0;
       +        int upper = paired_len - 1;
       +
       +        while (lower <= upper) {
       +        int mid = (lower + upper) / 2;
       +        if (ch < paired_chars[mid])
       +                upper = mid - 1;
       +        else if (ch > paired_chars[mid])
       +                lower = mid + 1;
       +        else
       +                return mid;
       +        }
       +
       +        return -1;
        }
        
        #define STACK_IS_EMPTY(stack) ((stack)->size <= 0)
       t@@ -327,6 +328,7 @@ ltk_text_line_itemize(struct ltk_text_line *tl) {
                size_t start_index = 0;
                size_t end_index;
                hb_direction_t dir;
       +        int par_is_rtl = FRIBIDI_IS_RTL(tl->dir);
                while (start_index < tl->len) {
                        end_index = start_index;
                        cur_level = last_level = ltk_gap_buffer_get_level(tl->bidi_levels, start_index);
       t@@ -345,8 +347,13 @@ ltk_text_line_itemize(struct ltk_text_line *tl) {
                        if (!first_run) {
                                first_run = cur_run = new;
                        } else {
       -                        cur_run->next = new;
       -                        new->last = cur_run;
       +                        if (par_is_rtl) {
       +                                new->next = cur_run;
       +                                cur_run->last = new;
       +                        } else {
       +                                cur_run->next = new;
       +                                new->last = cur_run;
       +                        }
                                cur_run = new;
                        }
                        start_index = end_index;
       t@@ -581,6 +588,8 @@ ltk_text_line_create(void) {
                line->log2vis = ltk_gap_buffer_create_int();
                line->vis2log = ltk_gap_buffer_create_int();
                line->bidi_levels = ltk_array_create_levels(8);
       +        line->wrap_indeces = ltk_array_create_int(1);
       +        line->wrap_num = 0;
                line->runs = NULL;
                line->cur_run = NULL;
                line->next = NULL;
   DIR diff --git a/textedit_wip.h b/textedit_wip.h
       t@@ -35,15 +35,18 @@ Requires the following includes:
        #include "array.h"
        #include "stack.h"
        
       +/* Note: hb_script_t and FriBidiLevel are really just uint32_t's, but
       +   I'm not sure if I should rely on that, so they're separate here */
        LTK_GAP_BUFFER_INIT_DECL(uint32, uint32_t)
        LTK_GAP_BUFFER_INIT_DECL(script, hb_script_t)
        LTK_GAP_BUFFER_INIT_DECL(int, int)
        LTK_ARRAY_INIT_DECL(level, FriBidiLevel)
       +LTK_ARRAY_INIT_DECL(int, int)
        LTK_STACK_INIT_DECL(script, int, hb_script_t, pair_index, script);
        
        struct ltk_text_run {
                LtkGlyph *glyphs;
       -        size_t num_glyphs;
       +        unsigned int num_glyphs;
                struct ltk_text_run *next;
                struct ltk_text_run *last;
                size_t start_index;
       t@@ -74,6 +77,8 @@ struct ltk_text_line {
                struct ltk_text_line *next; /* next text line in the buffer */
                unsigned int height; /* height of the line (including wrapping) */
                FribidiCharType dir; /* overall paragraph direction */
       +        struct ltk_array_int *wrap_indeces;;
       +        size_t wrap_num;
                size_t len;
                uint16_t font_size;
                int x_max;