ltkx

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

commit 48e6e0b3b9804877d23cf36c1390352115340689
parent 16e9709ac835f46a608c339a632806923465e956
Author: lumidify <nobody@lumidify.org>
Date:   Tue, 12 May 2020 18:22:40 +0200

Improve array; store wrapping indeces for paragraphs

Diffstat:
Marray.h | 20++++++++++++++++++--
Mgap_buffer.h | 4++++
Mtextedit_wip.c | 109+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mtextedit_wip.h | 7++++++-
4 files changed, 87 insertions(+), 53 deletions(-)

diff --git a/array.h b/array.h @@ -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 * \ @@ -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; \ diff --git a/gap_buffer.h b/gap_buffer.h @@ -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) { \ diff --git a/textedit_wip.c b/textedit_wip.c @@ -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 */ @@ -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) { @@ -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; @@ -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; @@ -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) @@ -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); @@ -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; @@ -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; diff --git a/textedit_wip.h b/textedit_wip.h @@ -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; @@ -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;