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;