commit 30f6302a0a754c310140abbb88f467492586be68
parent e6a8ecf9116eb9cec8ed1da33d69c91988f55e86
Author: lumidify <nobody@lumidify.org>
Date:   Thu, 14 May 2020 15:35:58 +0200
Fix and add bugs
Diffstat:
7 files changed, 106 insertions(+), 63 deletions(-)
diff --git a/array.h b/array.h
@@ -58,6 +58,7 @@ ltk_array_create_##name(size_t initial_len) {						\
 	if (!ar->buf) goto error;							\
 	ar->buf_size = initial_len;							\
 	ar->len = 0;									\
+	return ar;									\
 error:											\
 	(void)fprintf(stderr, "Out of memory while trying to allocate array\n");	\
 	exit(1);									\
@@ -120,7 +121,7 @@ ltk_array_resize_##name(struct ltk_array_##name *ar, size_t len) {			\
 	} else {									\
 		return;									\
 	}										\
-	type *new = realloc(ar->buf, new_size);						\
+	type *new = realloc(ar->buf, new_size * sizeof(type));				\
 	if (!new) {									\
 		(void)fprintf(stderr, "Cannot realloc array\n");			\
 		exit(1);								\
@@ -132,7 +133,9 @@ ltk_array_resize_##name(struct ltk_array_##name *ar, size_t len) {			\
 											\
 void											\
 ltk_array_destroy_##name(struct ltk_array_##name *ar) {					\
+	printf("%p   %p   %d\n", ar->buf, ar, ar->buf_size);				\
 	free(ar->buf);									\
+	ar->buf = NULL;									\
 	free(ar);									\
 }
 
diff --git a/ltkx.h b/ltkx.h
@@ -12,3 +12,5 @@
 #include "text-hb.h"
 #include "button.h"
 #include "grid.h"
+#include "array.h"
+#include "text_edit.h"
diff --git a/test1.c b/test1.c
@@ -25,17 +25,18 @@ int main(int argc, char *argv[])
 	ltk_set_column_weight(grid1, 0, 1);
 	ltk_set_column_weight(grid1, 1, 1);
 	/* Test callback functions */
-	LtkButton *button1 = ltk_create_button(window1, "I'm a button!", &bob1);
-	ltk_grid_widget(button1, grid1, 0, 0, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_RIGHT);
+	//LtkButton *button1 = ltk_create_button(window1, "I'm a button!", &bob1);
+	//ltk_grid_widget(button1, grid1, 0, 0, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_RIGHT);
 	/* Test manual callback functions */
-	LtkButton *button2 = ltk_create_button(window1, "I'm a button!", NULL);
-	button2->widget.mouse_release = &bob2;
-	ltk_grid_widget(button2, grid1, 0, 1, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM);
-	LtkButton *button3 = ltk_create_button(window1, "I'm a button!", NULL);
-	ltk_grid_widget(button3, grid1, 1, 0, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM | LTK_STICKY_RIGHT);
+	//LtkButton *button2 = ltk_create_button(window1, "I'm a button!", NULL);
+	//button2->widget.mouse_release = &bob2;
+	//ltk_grid_widget(button2, grid1, 0, 1, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM);
+	//LtkButton *button3 = ltk_create_button(window1, "I'm a button!", NULL);
+	//ltk_grid_widget(button3, grid1, 1, 0, 1, 1, LTK_STICKY_TOP | LTK_STICKY_BOTTOM | LTK_STICKY_RIGHT);
 	//LtkButton *button4 = ltk_create_button(window1, "I'm a button!", NULL);
-	LtkButton *button4 = ltk_create_button(window1, "ہمارے بارے میں blablabla", NULL);
+	//LtkButton *button4 = ltk_create_button(window1, "ہمارے بارے میں blablabla", NULL);
 	//LtkButton *button4 = ltk_create_button(window1, "پَیدایش", NULL);
-	ltk_grid_widget(button4, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_BOTTOM);
+	LtkTextEdit *edit = ltk_create_text_edit(window1, "ہمارے بارے میں blablabla");
+	ltk_grid_widget(edit, grid1, 1, 1, 1, 1, LTK_STICKY_LEFT | LTK_STICKY_BOTTOM);
 	ltk_mainloop();
 }
diff --git a/text-hb.c b/text-hb.c
@@ -365,7 +365,6 @@ ltk_render_text_line(
 	int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir);
 	do {
 		if (is_hor) {
-			printf("%d\n", ts->start_x);
 			y = tl->h - tl->y_max;
 			ltk_render_text_segment(ts, x + ts->start_x, y, img, fg);
 			x += ts->w;
@@ -396,7 +395,6 @@ ltk_render_text_segment(
 	do {
 		x = x_cur + glyph->info->xoff + glyph->x_offset;
 		y = y_cur + glyph->info->yoff - glyph->y_offset;
-		printf("%d %d; %d %d\n", x, y, glyph->x_abs, glyph->y_abs);
 		for (int i = 0; i < glyph->info->h; i++) {
 			for (int j = 0; j < glyph->info->w; j++) {
 				b = (y + i) * img->bytes_per_line + (x + j) * 4;
diff --git a/text_buffer.c b/text_buffer.c
@@ -60,30 +60,53 @@ ltk_render_text_line_new(
 	XColor bg)
 {
 	XImage *img;
-	int cur_x = 0, cur_y = 0;
 	int par_is_rtl = FRIBIDI_IS_RTL(tl->dir);
+	int cur_y = 0;
+	int cur_x = par_is_rtl ? max_width : 0;
 	ltk_array_clear_int(tl->wrap_indeces);
 	ltk_array_append_int(tl->wrap_indeces, 0);
 
 	/* FIXME: wrap bidi text properly */
+	/* FIXME: THIS IS UGLY */
 	struct ltk_text_run *cur = tl->first_run;
 	do {
-		for (int i = 0; i < cur->num_glyphs; i++) {
-			cur_x += cur->glyphs[i].x_advance;
-			if (cur_x > max_width) {
-				int j = 0;
-				for (j = i; j >= 0; j--) {
-					if (cur->glyphs[j].cluster != cur->glyphs[i].cluster) {
-						/* must increase one again so the actual
-						   next character is used */
-						j++;
-						break;
+		if (par_is_rtl) {
+			for (int i = cur->num_glyphs - 1; i >= 0; i--) {
+				cur_x -= cur->glyphs[i].x_advance;
+				if (cur_x < 0) {
+					int j = 0;
+					for (j = i; j < cur->num_glyphs; j++) {
+						if (cur->glyphs[j].cluster != cur->glyphs[i].cluster) {
+							/* must decrease one again so the actual
+							   last character is used */
+							j--;
+							break;
+						}
 					}
+					i = j;
+					/* FIXME: handle case that this is the same as the last index */
+					ltk_array_append_int(tl->wrap_indeces, cur->glyphs[i].cluster);
+					cur_x = max_width;
+				}
+			}
+		} else {
+			for (int i = 0; i < cur->num_glyphs; i++) {
+				cur_x += cur->glyphs[i].x_advance;
+				if (cur_x > max_width) {
+					int j = 0;
+					for (j = i; j >= 0; j--) {
+						if (cur->glyphs[j].cluster != cur->glyphs[i].cluster) {
+							/* must increase one again so the actual
+							   next character is used */
+							j++;
+							break;
+						}
+					}
+					i = j;
+					/* FIXME: handle case that this is the same as the last index */
+					ltk_array_append_int(tl->wrap_indeces, cur->glyphs[i].cluster);
+					cur_x = 0;
 				}
-				i = j;
-				/* FIXME: handle case that this is the same as the last index */
-				ltk_array_append_int(tl->wrap_indeces, cur->glyphs[i].cluster);
-				cur_x = 0;
 			}
 		}
 	} while (cur = cur->next);
@@ -91,9 +114,11 @@ ltk_render_text_line_new(
 	XWindowAttributes attrs;
 	XGetWindowAttributes(dpy, window, &attrs);
 	int depth = attrs.depth;
+	printf("%d ---  %d\n", max_width, tl->h * tl->wrap_indeces->len);
 	img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, max_width, tl->h * tl->wrap_indeces->len, 32, 0);
 	img->data = calloc(img->bytes_per_line, img->height);
 	XInitImage(img);
+	printf("%d +++  %d\n", img->width, img->height);
 
 	int b;
 	for (int i = 0; i < tl->h * tl->wrap_indeces->len; i++) {
@@ -112,20 +137,33 @@ ltk_render_text_line_new(
 	int cur_line_x = 0;
 	int cur_line = 0;
 	LtkGlyph *glyph;
-	/* FIXME: Ints are compared with size_t's in various places. Maybe I should fix that. */
+	/* FIXME: ints are compared with size_t's in various places. Maybe I should fix that. */
 	/* FIXME: how should an empty line be handled? This doesn't use a do-for
 	   loop in case tl->first_run is NULL, but I should probably decide what
 	   to do in that case */
+	int index;
 	while (cur) {
-		for (int k = 0; k < cur->len; k++) {
+		for (int k = 0; k < cur->num_glyphs; k++) {
+			index = par_is_rtl ? cur->num_glyphs - k - 1 : k;
 			glyph = &cur->glyphs[k];
 			if (cur_line < tl->wrap_indeces->len - 1 &&
-			    glyph->cluster >= tl->wrap_indeces->buf[cur_line + 1]) {
+			    ((!par_is_rtl && glyph->cluster >= tl->wrap_indeces->buf[cur_line + 1]) ||
+			     (par_is_rtl && glyph->cluster <= tl->wrap_indeces->buf[cur_line + 1]))) {
 				cur_line++;
 				cur_line_x += glyph->x_abs - cur_line_x;
 			}
-			x = glyph->x_abs - cur_line_x;
+			x = par_is_rtl ? max_width - (glyph->x_abs - cur_line_x) - glyph->info->w: glyph->x_abs - cur_line_x;
 			y = glyph->y_abs + tl->h * cur_line;
+			printf("%d,%d\n", x, y);
+			fflush(stdout);
+			if (x < 0)
+				x = 0;
+			if (x > max_width - glyph->info->w)
+				x = max_width - glyph->info->w;
+			if (y < 0)
+				y = 0;
+			if (y > img->height - glyph->info->h)
+				y = img->height - glyph->info->h;
 			for (int i = 0; i < glyph->info->h; i++) {
 				for (int j = 0; j < glyph->info->w; j++) {
 					b = (y + i) * img->bytes_per_line + (x + j) * 4;
@@ -138,6 +176,7 @@ ltk_render_text_line_new(
 		}
 		cur = cur->next;
 	}
+	return img;
 }
 
 /* Begin stuff stolen from raqm */
@@ -280,8 +319,8 @@ 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;
+	return run;
 }
 
 static void
@@ -289,6 +328,7 @@ ltk_text_line_itemize(struct ltk_text_line *tl) {
 	ltk_resolve_scripts(tl);
 	struct ltk_text_run *first_run = NULL;
 	struct ltk_text_run *cur_run = NULL;
+	struct ltk_text_run *new = NULL;
 	FriBidiLevel last_level;
 	FriBidiLevel cur_level;
 	hb_script_t last_script;
@@ -310,27 +350,22 @@ ltk_text_line_itemize(struct ltk_text_line *tl) {
 		dir = HB_DIRECTION_LTR;
 		if (FRIBIDI_LEVEL_IS_RTL(last_level))
 			dir = HB_DIRECTION_RTL;
-		struct ltk_text_run *new = ltk_text_run_create(
+		new = ltk_text_run_create(
 		    start_index, end_index - start_index, last_script, dir);
 		if (!first_run) {
-			first_run = cur_run = new;
+			first_run = new;
 		} else {
-			if (par_is_rtl) {
+			if (par_is_rtl)
 				new->next = cur_run;
-				cur_run->last = new;
-			} else {
+			else
 				cur_run->next = new;
-				new->last = cur_run;
-			}
-			cur_run = new;
 		}
+		cur_run = new;
 		start_index = end_index;
 	}
-	tl->first_run = tl->cur_run = first_run;
-	tl->last_run = cur_run;
+	tl->first_run = par_is_rtl ? cur_run : first_run;
 }
 
-/* FIXME: return start_x, etc. instead of saving in struct text run */
 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) {
@@ -338,6 +373,7 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
 	khint_t k;
 
 	tr->font_id = font_id;
+	tr->font_size = font_size;
 	uint32_t attr = font_id << 16 + font_size;
 	/* FIXME: turn this into ltk_get_glyph_cache */
 	k = kh_get(glyphcache, tm->glyph_cache, attr);
@@ -355,7 +391,7 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
 	hb_buffer_set_direction(buf, tr->dir);
 	hb_buffer_set_script(buf, tr->script);
 	/* WARNING: vis_buf has to be normalized (without gap) for this! */
-	hb_buffer_add_codepoints(buf, tl->vis_buf, tl->len, tr->start_index, tr->len);
+	hb_buffer_add_codepoints(buf, tl->vis_buf->buf, tl->len, tr->start_index, tr->len);
 	/* According to https://harfbuzz.github.io/the-distinction-between-levels-0-and-1.html
 	 * this should be level 1 clustering instead of level 0 */
 	hb_buffer_set_cluster_level(buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
@@ -392,14 +428,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
 		/* Calculate position in order to determine full size of text segment */
 		x1_abs = x_abs + glyph->info->xoff + glyph->x_offset;
 		y1_abs = y_abs + glyph->info->yoff - glyph->y_offset;
-		/* Okay, wait, so should I check if the script is horizontal, and then add
-		   x_advance instead of glyph->info->w? It seems that the glyph width is
-		   usually smaller than x_advance, and spaces etc. are completely lost
-		   because their glyph width is 0. I have to distinguish between horizontal
-		   and vertical scripts, though because to calculate the maximum y position
-		   for horizontal scripts, I still need to use the glyph height since
-		   y_advance doesn't really do much there. I dunno, at least *something*
-		   works now... */
 		/* FIXME: THIS PROBABLY DOESN'T REALLY WORK */
 		if (HB_DIRECTION_IS_HORIZONTAL(tr->dir)) {
 			x2_abs = x1_abs + glyph->x_advance;
@@ -434,11 +462,12 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) {
 		FcPattern *pat = FcPatternDuplicate(tm->fcpattern);
 		FcPattern *match;
 		FcResult result;
+		printf("%p\n", pat);
 		FcPatternAddBool(pat, FC_SCALABLE, 1);
 		FcConfigSubstitute(NULL, pat, FcMatchPattern);
 		FcDefaultSubstitute(pat);
 		FcCharSet *cs = FcCharSetCreate();
-		for (int i = run->start_index; i < run->start_index + run->len; i++) {
+		for (size_t i = run->start_index; i < run->start_index + run->len; i++) {
 			FcCharSetAddChar(cs, tl->vis_buf->buf[i]);
 		}
 		FcPatternAddCharSet(pat, FC_CHARSET, cs);
@@ -448,6 +477,7 @@ ltk_text_line_shape(LtkTextManager *tm, struct ltk_text_line *tl) {
 		uint16_t font_id = ltk_get_font(tm, file);
 		khint_t k = kh_get(fontstruct, tm->font_cache, font_id);
 		run->font = kh_value(tm->font_cache, k);
+		fflush(stdout);
 		FcPatternDestroy(match);
 		FcPatternDestroy(pat);
 		ltk_text_run_shape(tm, run, tl, tl->font_size, font_id, &y_max);
@@ -488,7 +518,7 @@ ltk_text_run_destroy(struct ltk_text_run *tr) {
 	khint_t k;
 	k = kh_get(glyphinfo, ltk_global->tm->glyph_cache, tr->font_id << 16 + tr->font_size);
 	gcache = kh_value(ltk_global->tm->glyph_cache, k);
-	for (int i = 0; i < tr->len; i++) {
+	for (int i = 0; i < tr->num_glyphs; i++) {
 		glyph = &tr->glyphs[i];
 		if (--glyph->info->refs < 1) {
 			k = kh_get(glyphinfo, gcache, glyph->info->id);
@@ -508,23 +538,25 @@ ltk_text_run_destroy(struct ltk_text_run *tr) {
 
 void
 ltk_text_line_destroy_runs(struct ltk_text_run *runs) {
-	struct ltk_text_run *cur, *last;
+	struct ltk_text_run *cur, *next;
 	cur = runs;
 	while (cur) {
-		last = cur;
+		next = cur->next;
 		ltk_text_run_destroy(cur);
-		cur = last->next;
+		cur = next;
 	}
 }
 
 static void
 ltk_text_line_recalculate(LtkTextManager *tm, struct ltk_text_line *tl) {
+	printf("%d,%d,%d,%d,%d\n", tl->log_buf->buf_size, tl->vis_buf->buf_size, tl->log2vis->buf_size, tl->vis2log->buf_size, tl->bidi_levels->buf_size);
 	fribidi_log2vis(
-	    tl->log_buf, tl->log_buf->len,
-	    &tl->dir, tl->vis_buf, tl->log2vis, tl->vis2log, tl->bidi_levels
+	    tl->log_buf->buf, tl->log_buf->len,
+	    &tl->dir, tl->vis_buf->buf, tl->log2vis->buf, tl->vis2log->buf, tl->bidi_levels->buf
 	);
 	struct ltk_text_run *old_runs = tl->first_run;
 	ltk_text_line_itemize(tl);
+	struct ltk_text_run *cur = tl->first_run;
 	ltk_text_line_shape(tm, tl);
 	/* this needs to be done after shaping so the fonts, etc. aren't
 	   removed if their reference counts drop and then loaded again
@@ -547,7 +579,7 @@ ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len) 
 	tl->len += len;
 	tl->cursor_pos += len;
 	/* FIXME: Why am I passing tm? It's global anyways */
-	ltk_text_line_recalculate(tl, ltk_global->tm);
+	ltk_text_line_recalculate(ltk_global->tm, tl);
 }
 
 /* must be NULL-terminated */
@@ -584,6 +616,9 @@ ltk_text_line_create(void) {
 	line->dir = FRIBIDI_TYPE_ON;
 	line->len = 0;
 	line->cursor_pos = 0;
+	/* FIXME */
+	line->font_size = 15;
+	return line;
 error:
 	(void)fprintf(stderr, "No memory left while creating text line\n");
 	exit(1);
diff --git a/text_buffer.h b/text_buffer.h
@@ -42,7 +42,6 @@ struct ltk_text_run {
 	LtkGlyph *glyphs;
 	unsigned int num_glyphs;
 	struct ltk_text_run *next;
-	struct ltk_text_run *last;
 	size_t start_index;
 	size_t len; /* FIXME: THIS IS NOT THE NUMBER OF GLYPHS; IT IS THE ACTUAL NUMBER OF CHARACTERS REPRESENTED BY THIS RUN */
 	int start_x;
diff --git a/text_edit.c b/text_edit.c
@@ -34,6 +34,7 @@
 #include "array.h"
 #include "text_buffer.h"
 #include "text_edit.h"
+#include "grid.h"
 
 extern Ltk *ltk_global;
 
@@ -44,8 +45,11 @@ ltk_draw_text_edit(LtkTextEdit *te) {
 	LtkRect rect = te->widget.rect;
 	LtkWindow *window = te->widget.window;
 	if (!te->img)
-		ltk_render_text_line_new(te->tl, rect.w, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg);
-	XPutImage(ltk_global->display, window->xwindow, window->gc, te->img, 0, 0, rect.x, rect.y, te->tl->w, te->tl->h);
+		te->img = ltk_render_text_line_new(te->tl, rect.w, ltk_global->display, window->xwindow, window->gc, ltk_global->colormap, fg, bg);
+	printf("%p\n", te->img);
+	fflush(stdout);
+	printf("%d,%d;%d,%d;%d,%d\n", rect.x, rect.y, rect.w, rect.h, te->img->width, te->img->height);
+	XPutImage(ltk_global->display, window->xwindow, window->gc, te->img, 0, 0, rect.x, rect.y, te->img->width, te->img->height);
 }
 
 LtkTextEdit *ltk_create_text_edit(LtkWindow *window, const char *text) {
@@ -56,6 +60,7 @@ LtkTextEdit *ltk_create_text_edit(LtkWindow *window, const char *text) {
 	te->tl = ltk_text_line_create();
 	ltk_text_line_insert_utf8(te->tl, text);
 	te->img = NULL;
+	return te;
 }
 void ltk_destroy_text_edit(LtkTextEdit *te) {
 	ltk_text_line_destroy(te->tl);