commit 16e9709ac835f46a608c339a632806923465e956
parent cd31b2005fde2440d4277709a0c6efb114718822
Author: lumidify <nobody@lumidify.org>
Date:   Mon, 11 May 2020 21:22:42 +0200
Calculate number of required lines before rendering
Diffstat:
2 files changed, 46 insertions(+), 27 deletions(-)
diff --git a/textedit_wip.c b/textedit_wip.c
@@ -44,14 +44,14 @@ extern Ltk *ltk_global;
 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(char_type, FriBidiCharType)
 LTK_ARRAY_INIT_IMPL(level, FriBidiLevel)
 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 */
 XImage *
 ltk_render_text_line(
-	LtkTextLine *tl,
+	struct ltk_text_line *tl,
+	int max_width,
 	Display *dpy,
 	Window window,
 	GC gc,
@@ -59,10 +59,31 @@ ltk_render_text_line(
 	XColor fg,
 	XColor bg)
 {
+	int lines = 0;
+	int cur_x = 0, cur_y = 0;
+	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) {
+				int j = 0;
+				for (j = i; j >= 0; j--) {
+					if (glyphs[j]->cluster != glyphs[i]->cluster) {
+						/* must increase one again so the actual
+						   next character is used */
+						j++;
+						break;
+					}
+				}
+				i = j;
+				lines++;
+			}
+		}
+	} while (cur = cur->next);
 	XWindowAttributes attrs;
 	XGetWindowAttributes(dpy, window, &attrs);
 	int depth = attrs.depth;
-	XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, tl->w, tl->h, 32, 0);
+	XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, max_width, tl->h * lines, 32, 0);
 	img->data = calloc(img->bytes_per_line, img->height);
 	XInitImage(img);
 	int b;
@@ -76,7 +97,7 @@ ltk_render_text_line(
 		}
 	}
 
-	LtkTextSegment *ts = tl->start_segment;
+	cur = tl->runs;
 	int x = 0;
 	int y = 0;
 	int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir);
@@ -290,6 +311,7 @@ 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;
 }
 
@@ -323,12 +345,14 @@ ltk_text_line_itemize(struct ltk_text_line *tl) {
 		if (!first_run) {
 			first_run = cur_run = new;
 		} else {
-			cur->next = new;
-			cur = new;
+			cur_run->next = new;
+			new->last = cur_run;
+			cur_run = new;
 		}
 		start_index = end_index;
 	}
-	tl->runs = tl->cur_run = first_run;
+	tl->first_run = tl->cur_run = first_run;
+	tl->last_run = cur_run;
 }
 
 static void
@@ -348,7 +372,7 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
 	hb_buffer_t *buf;
 	hb_glyph_info_t *ginf, *gi;
 	hb_glyph_position_t *gpos, *gp;
-	unsigned int num_glyphs = 0;
+	tr->num_glyphs = 0;
 
 	buf = hb_buffer_create();
 	hb_buffer_set_direction(buf, run->dir);
@@ -359,24 +383,23 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
 	 * this should be level 1 clustering instead of level 0 */
 	hb_buffer_set_cluster_level(buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
 	hb_shape(font->hb, buf, NULL, 0);
-	ginf = hb_buffer_get_glyph_infos(buf, &num_glyphs);
-	gpos = hb_buffer_get_glyph_positions(buf, &num_glyphs);
+	ginf = hb_buffer_get_glyph_infos(buf, &tr->num_glyphs);
+	gpos = hb_buffer_get_glyph_positions(buf, &tr->num_glyphs);
 	float scale = stbtt_ScaleForMappingEmToPixels(&tr->font->info, font_size);
-	LtkGlyph *last_glyph = NULL;
 
 	int x_min = INT_MAX, x_max = INT_MIN, y_min = INT_MAX, y_max = INT_MIN;
 	int x_abs = 0, y_abs = 0, x1_abs, y1_abs, x2_abs, y2_abs;
 	/* magic, do not touch */
-	/* FIXME: array instead of linked list */
+	tr->glyphs = malloc(sizeof(LtkGlyph) * num_glyph);
+	if (!tr->glyphs) {
+		(void)fprintf("Cannot allocate space for glyphs.\n");
+		exit(1);
+	}
 	LtkGlyph *glyph;
-	for (int i = 0; i < num_glyphs; i++) {
+	for (int i = 0; i < tr->num_glyphs; i++) {
 		gi = &ginf[i];
 		gp = &gpos[i];
-		glyph = malloc(sizeof(LtkGlyph));
-		if (!glyph) {
-			(void)fprintf(stderr, "Cannot allocate glyph.\n");
-			exit(1);
-		}
+		glyph = tr->glyphs[i];
 		glyph->cluster = gi->cluster;
 		glyph->info = ltk_get_glyph_info(tr->font, gi->codepoint, scale, glyph_cache);
 		glyph->info->refs++;
@@ -385,13 +408,6 @@ ltk_text_run_shape(LtkTextManager *tm, struct ltk_text_run *tr,
 		glyph->y_offset = (int)(gp->y_offset * scale);
 		glyph->x_advance = (int)(gp->x_advance * scale);
 		glyph->y_advance = (int)(gp->y_advance * scale);
-		glyph->next = NULL;
-		if (i == 0) {
-			tr->start_glyph = glyph;
-		} else {
-			last_glyph->next = glyph;
-		}
-		last_glyph = glyph;
 
 		/* Calculate position in order to determine full size of text segment */
 		x1_abs = x_abs + glyph->info->xoff + glyph->x_offset;
diff --git a/textedit_wip.h b/textedit_wip.h
@@ -42,8 +42,10 @@ LTK_ARRAY_INIT_DECL(level, FriBidiLevel)
 LTK_STACK_INIT_DECL(script, int, hb_script_t, pair_index, script);
 
 struct ltk_text_run {
-	struct ltk_glyph *start_glyph;
+	LtkGlyph *glyphs;
+	size_t num_glyphs;
 	struct ltk_text_run *next;
+	struct ltk_text_run *last;
 	size_t start_index;
 	size_t len;
 	LtkFont *font;
@@ -66,7 +68,8 @@ struct ltk_text_line {
 	struct ltk_gap_buffer_int *log2vis;
 	struct ltk_gap_buffer_int *vis2log;
 	struct ltk_array_level *bidi_levels;
-	struct ltk_text_run *runs; /* first node in the linked list of runs */
+	struct ltk_text_run *first_run; /* first node in the linked list of runs */
+	struct ltk_text_run *last_run; /* last node in the linked list of runs */
 	struct ltk_text_run *cur_run; /* current node in the linked list of runs */
 	struct ltk_text_line *next; /* next text line in the buffer */
 	unsigned int height; /* height of the line (including wrapping) */