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);
 }