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:
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;