commit c990c56e3031b2973a251347dc2f8935b957cd79
parent 91ef917f5e9467ba6f4c187b70ed98517010489e
Author: lumidify <nobody@lumidify.org>
Date: Thu, 21 May 2020 17:43:02 +0200
Start work on actual text buffer
Diffstat:
4 files changed, 106 insertions(+), 46 deletions(-)
diff --git a/test1.c b/test1.c
@@ -42,6 +42,6 @@ int main(int argc, char *argv[])
LtkTextEdit *edit = ltk_create_text_edit(window1, "ہمارے بارے میں blabla bla");
LtkButton *button4 = ltk_create_button(window1, "ہمارے بارے میں blablabla", &bob3, edit);
ltk_grid_widget(button4, grid1, 1, 0, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM | LTK_STICKY_RIGHT);
- ltk_grid_widget(edit, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_BOTTOM | LTK_STICKY_TOP | LTK_STICKY_RIGHT);
+ ltk_grid_widget(edit, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_TOP | LTK_STICKY_RIGHT);
ltk_mainloop();
}
diff --git a/text_buffer.c b/text_buffer.c
@@ -21,6 +21,7 @@
* SOFTWARE.
*/
+#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -76,14 +77,12 @@ ltk_text_line_cleanup_soft_lines(struct ltk_array_line *soft_lines, int old_len)
ltk_array_resize_line(soft_lines, soft_lines->len);
}
-/* FIXME: redo this to store a list of all runs and indeces to be drawn in
- each soft line -> that would take a bit more space but simplify later
- logic and (most importantly) allow ltk_soft_line_get_index_from_pos to
- loop over the actual runs and see what direction each one is (that's
- necessary for determining on which side of the glyph the new text has
- to be inserted) */
void
ltk_text_line_wrap(struct ltk_text_line *tl, int max_width) {
+ struct timeval t1, t2;
+ gettimeofday(&t1, NULL);
+ printf("wrap1: %d, %d\n", t1.tv_sec, t1.tv_usec);
+
tl->w_wrapped = max_width;
int old_len = tl->soft_lines->len;
tl->soft_lines->len = 0;
@@ -213,6 +212,9 @@ ltk_text_line_wrap(struct ltk_text_line *tl, int max_width) {
ltk_text_line_cleanup_soft_lines(tl->soft_lines, old_len);
tl->w_wrapped = max_width;
tl->h_wrapped = tl->soft_lines->len * tl->h;
+
+ gettimeofday(&t2, NULL);
+ printf("wrap2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
}
XImage *
@@ -266,6 +268,9 @@ ltk_text_line_render(
XColor fg,
XColor bg)
{
+ struct timeval t1, t2;
+ gettimeofday(&t1, NULL);
+ printf("render1: %d, %d\n", t1.tv_sec, t1.tv_usec);
LtkGlyph *glyph;
int par_is_rtl = tl->dir == HB_DIRECTION_RTL;
@@ -341,7 +346,11 @@ ltk_text_line_render(
}
cur = par_is_rtl ? cur->last : cur->next;
}
+ ltk_array_resize_int(sl->glyph_pos, sl->glyph_pos->len);
+ ltk_array_resize_uint32(sl->glyph_clusters, sl->glyph_clusters->len);
}
+ gettimeofday(&t2, NULL);
+ printf("render2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
}
uint32_t
@@ -588,6 +597,8 @@ ltk_text_line_itemize(struct ltk_text_line *tl) {
static void
ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
struct ltk_text_line *tl, uint16_t font_size, uint16_t font_id, int *ret_y_max) {
+ struct timeval t1, t2;
+ gettimeofday(&t1, NULL);
khash_t(glyphinfo) *glyph_cache;
khint_t k;
@@ -607,15 +618,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
tr->num_glyphs = 0;
buf = hb_buffer_create();
- /* Harfbuzz requires the original, non-reversed text.
- Yes, I know this is a bit hacky
- Update: This is now done in the ltk_text_line_itemize already */
- /*
- size_t start_index = tl->vis2log->buf[tr->start_index];
- size_t end_index = tl->vis2log->buf[tr->start_index + tr->len - 1];
- if (start_index > end_index)
- start_index = end_index;
- */
hb_buffer_add_utf32(buf, tl->log_buf->buf, tl->len, tr->start_index, tr->len);
hb_buffer_set_direction(buf, tr->dir);
hb_buffer_set_script(buf, tr->script);
@@ -625,6 +627,8 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
hb_shape(tr->font->hb, buf, NULL, 0);
ginf = hb_buffer_get_glyph_infos(buf, &tr->num_glyphs);
gpos = hb_buffer_get_glyph_positions(buf, &tr->num_glyphs);
+ gettimeofday(&t2, NULL);
+ printf("hb_shape: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
float scale = stbtt_ScaleForMappingEmToPixels(&tr->font->info, font_size);
int x_min = INT_MAX, x_max = INT_MIN, y_min = INT_MAX, y_max = INT_MIN;
@@ -676,6 +680,8 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
*ret_y_max = y_max;
tr->font->refs++;
+ gettimeofday(&t2, NULL);
+ printf("run_shape: %d\n", t2.tv_usec - t1.tv_usec);
}
static void
@@ -685,14 +691,17 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) {
int y_max;
int y_max_overall = INT_MIN;
int y_min_overall = INT_MAX;
+ struct timeval t1, t2;
while (run) {
- /* Question: Why does this not work with Duplicate? */
- FcPattern *pat = FcPatternCreate();//FcPatternDuplicate(tm->fcpattern);
+ /* Question: Why does this not work with FcPatternDuplicate? */
+ gettimeofday(&t1, NULL);
+ FcPattern *pat = FcPatternCreate();
FcPattern *match;
FcResult result;
FcPatternAddBool(pat, FC_SCALABLE, 1);
FcConfigSubstitute(NULL, pat, FcMatchPattern);
FcDefaultSubstitute(pat);
+ /* FIXME: make this more efficient */
FcCharSet *cs = FcCharSetCreate();
for (size_t i = run->start_index; i < run->start_index + run->len; i++) {
FcCharSetAddChar(cs, tl->log_buf->buf[i]);
@@ -706,6 +715,8 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) {
run->font = kh_value(tm->font_cache, k);
FcPatternDestroy(match);
FcPatternDestroy(pat);
+ gettimeofday(&t2, NULL);
+ printf("fontconfig: %d\n", t2.tv_usec - t1.tv_usec);
ltk_text_run_shape(tm, run, tl, tl->font_size, font_id, &y_max);
if (y_max_overall < y_max)
y_max_overall = y_max;
@@ -776,18 +787,31 @@ ltk_text_line_destroy_runs(struct ltk_text_run *runs) {
static void
ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) {
FriBidiCharType par_dir = FRIBIDI_TYPE_ON;
+ struct timeval t1, t2;
+ gettimeofday(&t1, NULL);
+ printf("fribidi1: %d, %d\n", t1.tv_sec, t1.tv_usec);
fribidi_log2vis(
tl->log_buf->buf, tl->log_buf->len,
&par_dir, tl->vis_buf->buf, tl->log2vis->buf, tl->vis2log->buf, tl->bidi_levels->buf
);
+ gettimeofday(&t2, NULL);
+ printf("fribidi2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
if (FRIBIDI_IS_RTL(par_dir))
tl->dir = HB_DIRECTION_RTL;
else
tl->dir = HB_DIRECTION_LTR;
struct ltk_text_run *old_runs = tl->first_run;
+ gettimeofday(&t1, NULL);
+ printf("itemize1: %d, %d\n", t1.tv_sec, t1.tv_usec);
ltk_text_line_itemize(tl);
+ gettimeofday(&t2, NULL);
+ printf("itemize2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
struct ltk_text_run *cur = tl->first_run;
+ gettimeofday(&t1, NULL);
+ printf("shape1: %d, %d\n", t1.tv_sec, t1.tv_usec);
ltk_text_line_shape(tm, tl);
+ gettimeofday(&t2, NULL);
+ printf("shape2: %d, %d, diff: %d\n", t2.tv_sec, t2.tv_usec, t2.tv_usec - t1.tv_usec);
/* this needs to be done after shaping so the fonts, etc. aren't
removed if their reference counts drop and then loaded again
right afterwards */
@@ -797,25 +821,24 @@ ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) {
void
-ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len) {
- ltk_array_insert_uint32(tl->log_buf, tl->cursor_pos, text, len);
- ltk_array_prepare_gap_script(tl->scripts, tl->cursor_pos, len);
+ltk_text_line_insert_utf32(struct ltk_text_line *tl, size_t index, uint32_t *text, size_t len) {
+ ltk_array_insert_uint32(tl->log_buf, index, text, len);
+ ltk_array_prepare_gap_script(tl->scripts, index, len);
hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default();
for (int i = 0; i < len; i++)
- tl->scripts->buf[tl->cursor_pos + i] = hb_unicode_script(ufuncs, text[i]);
+ tl->scripts->buf[index + i] = hb_unicode_script(ufuncs, text[i]);
ltk_array_resize_uint32(tl->vis_buf, tl->len + len);
ltk_array_resize_int(tl->log2vis, tl->len + len);
ltk_array_resize_int(tl->vis2log, tl->len + len);
ltk_array_resize_level(tl->bidi_levels, tl->len + len);
tl->len += len;
- /*tl->cursor_pos += len;*/ /* FIXME */
/* FIXME: Why am I passing tm? It's global anyways */
ltk_text_line_recalculate(ltk_global->tm, tl);
}
/* must be NULL-terminated */
void
-ltk_text_line_insert_utf8(struct ltk_text_line *tl, char *text) {
+ltk_text_line_insert_utf8(struct ltk_text_line *tl, size_t index, char *text) {
size_t len = u8_strlen(text);
uint32_t *new = malloc(sizeof(uint32_t) * len);
if (!new) {
@@ -825,7 +848,7 @@ ltk_text_line_insert_utf8(struct ltk_text_line *tl, char *text) {
size_t inc = 0;
for (int i = 0; i < len; i++)
new[i] = u8_nextmemchar(text, &inc);
- ltk_text_line_insert_text(tl, new, len);
+ ltk_text_line_insert_utf32(tl, index, new, len);
free(new);
}
@@ -843,7 +866,6 @@ ltk_text_line_create(void) {
line->first_run = NULL;
line->next = NULL;
line->len = 0;
- line->cursor_pos = 0;
line->w_wrapped = line->h_wrapped = 0;
line->img = NULL;
/* FIXME */
@@ -855,6 +877,57 @@ error:
exit(1);
}
+void
+ltk_text_buffer_scroll(struct ltk_text_buffer *tb, int offset_y) {
+}
+
+void
+ltk_text_buffer_render(struct ltk_text_buffer *tb, int offset_y, int offset_x, int w, int h) {
+ struct ltk_text_line *cur = tb->head;
+ int cur_y = 0;
+ while (cur) {
+ if (cur_y > offset_y + h)
+ break;
+ if (cur_y > offset_y || cur_y + cur->h_wrapped > offset_y) {
+ }
+ cur_y += cur->h_wrapped;
+ cur = cur->next;
+ }
+}
+
+void
+ltk_text_buffer_wrap(struct ltk_text_buffer *tb, int max_width) {
+ struct ltk_text_line *cur = tb->head;
+ while (cur) {
+ ltk_text_line_wrap(cur, max_width);
+ cur = cur->next;
+ }
+}
+
+void
+ltk_text_buffer_insert_utf8_at_cursor(struct ltk_text_buffer *tb, char *text) {
+ size_t len = u8_strlen(text);
+ uint32_t *new = malloc(sizeof(uint32_t) * len);
+ if (!new) {
+ (void)fprintf(stderr, "Error allocating memory for string\n");
+ exit(1);
+ }
+ size_t inc = 0;
+ uint32_t c;
+ size_t actual_len = 0;
+ for (int i = 0; i < len; i++) {
+ c = u8_nextmemchar(text, &inc);
+ if (c == 0x000A) {
+ printf("newline\n");
+ } else {
+ actual_len++;
+ new[i] = c;
+ }
+ }
+ ltk_text_line_insert_utf32(tb->cur_line, tb->cursor_pos, new, actual_len);
+ free(new);
+}
+
struct ltk_text_buffer *
ltk_text_buffer_create(void) {
struct ltk_text_buffer *buf = malloc(sizeof(struct ltk_text_buffer));
@@ -864,6 +937,7 @@ ltk_text_buffer_create(void) {
}
buf->head = ltk_text_line_create();
buf->cur_line = buf->head;
+ buf->cursor_pos = 0;
buf->line_gap = 0;
}
diff --git a/text_buffer.h b/text_buffer.h
@@ -84,7 +84,6 @@ struct ltk_text_line {
int h;
int w_wrapped;
int h_wrapped;
- size_t cursor_pos;
unsigned int line_gap;
XImage *img;
};
@@ -100,7 +99,8 @@ void ltk_soft_line_destroy(struct ltk_soft_line *sl);
void ltk_text_line_render(struct ltk_text_line *tl,
Display *dpy, Window window, GC gc, Colormap colormap, XColor fg, XColor bg);
uint32_t ltk_soft_line_get_index_from_pos(int x, struct ltk_text_line *tl, struct ltk_soft_line *sl, int *found_pos);
-void ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len);
+void ltk_text_line_insert_utf32(struct ltk_text_line *tl, size_t index, uint32_t *text, size_t len);
+void ltk_text_line_insert_utf8(struct ltk_text_line *tl, size_t index, char *text);
struct ltk_text_line *ltk_text_line_create(void);
void ltk_text_line_destroy(struct ltk_text_line *tl);
diff --git a/text_edit.c b/text_edit.c
@@ -49,20 +49,7 @@ ltk_draw_text_edit(LtkTextEdit *te) {
to avoid recalculating everything when it really only has to drawn */
ltk_text_line_wrap(te->tl, rect.w);
ltk_text_line_render(te->tl, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg);
- XPutImage(ltk_global->display, window->xwindow, window->gc, te->tl->img, 0, 0, rect.x, rect.y, te->tl->img->width, te->tl->img->height);
- /*
- if (!te->soft_lines)
- te->soft_lines = ltk_render_text_line_new(te->tl, rect.w, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg);
- XSetForeground(ltk_global->display, window->gc, bg.pixel);
- XFillRectangle(ltk_global->display, window->xwindow, window->gc, rect.x, rect.y, rect.w, rect.h);
- for (int i = 0; i < te->soft_lines->len; i++) {
- XImage *img = te->soft_lines->buf[i]->img;
- int x = rect.x;
- if (te->tl->dir == HB_DIRECTION_RTL)
- x += rect.w - img->width;
- XPutImage(ltk_global->display, window->xwindow, window->gc, img, 0, 0, x, rect.y + te->tl->h * i, img->width, img->height);
- }
- */
+ XPutImage(ltk_global->display, window->xwindow, window->gc, te->tl->img, 0, 0, rect.x, rect.y, rect.w, rect.h);
}
#if 0
@@ -89,15 +76,14 @@ ltk_create_text_edit(LtkWindow *window, const char *text) {
ltk_fill_widget_defaults(&te->widget, window, <k_draw_text_edit, <k_destroy_text_edit, 1);
/*te->widget.mouse_press = <k_text_edit_tmp;*/
te->tl = ltk_text_line_create();
- ltk_text_line_insert_utf8(te->tl, text);
- te->cursor = 0;
+ ltk_text_line_insert_utf8(te->tl, 0, text);
return te;
}
void
ltk_text_edit_insert_text(LtkTextEdit *te, const char *text) {
- te->tl->cursor_pos = te->cursor;
- ltk_text_line_insert_utf8(te->tl, text);
+ /* FIXME */
+ ltk_text_line_insert_utf8(te->tl, 0, text);
/* FIXME: Need to "queue redraw" for whole window */
ltk_draw_text_edit(te);
}