commit 57d85ccfe4c9ac3de63dab6979e65dbe0696f4b7
parent 05e4c9d086c3db2ad726f789cee1b9f8d7ea07b9
Author: lumidify <nobody@lumidify.org>
Date: Fri, 8 May 2020 20:36:38 +0200
Refactor gap buffer
Diffstat:
6 files changed, 364 insertions(+), 158 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1 +1,3 @@
test
+*.o
+test1
diff --git a/gap_buffer.h b/gap_buffer.h
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the Lumidify ToolKit (LTK)
+ * Copyright (c) 2020 lumidify <nobody@lumidify.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _LTK_GAP_BUFFER_H_
+#define _LTK_GAP_BUFFER_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LTK_INIT_GAP_BUFFER_DECL(type) \
+struct ltk_gap_buffer_##type## { \
+ type *buf; \
+ size_t buf_size; \
+ size_t gap_left; \
+ size_t gap_size; \
+}; \
+ \
+struct ltk_gap_buffer_##type## * ltk_gap_buffer_create_##type##(void); \
+struct ltk_gap_buffer_##type## * \
+ltk_gap_buffer_create_from_data_##type##(type *data, size_t len); \
+void ltk_gap_buffer_resize_gap_##type##(struct ltk_gap_buffer *gb, int len); \
+void ltk_gap_buffer_insert_##type##(struct ltk_gap_buffer_##type## *gb, \
+ type *new, size_t start, size_t len); \
+void ltk_gap_buffer_insert_single_##type##( \
+ struct ltk_gap_buffer_##type## *gb, type new); \
+void ltk_gap_buffer_move_gap_##type##( \
+ struct ltk_gap_buffer_##type## *gb, size_t pos); \
+void ltk_gap_buffer_destroy_##type##(struct ltk_gap_buffer_##type## *gb);
+
+#define LTK_INIT_GAP_BUFFER_IMPL(type) \
+struct ltk_gap_buffer_##type## * \
+ltk_gap_buffer_create_##type##(void) { \
+ struct ltk_gap_buffer_##type## *gb = \
+ malloc(sizeof(struct ltk_gap_buffer)); \
+ if (!gb) \
+ goto error; \
+ gb->buf = malloc(8 * sizeof(type)); \
+ if (!gb->buf) \
+ goto error; \
+ gb->buf_size = 8; \
+ gb->gap_left = 0; \
+ gb->gap_size = 8; \
+ return gb; \
+error: \
+ (void)fprintf(stderr, "Out of memory while trying to" \
+ "allocate gap buffer\n"); \
+ exit(1); \
+} \
+ \
+struct ltk_gap_buffer_##type## * \
+ltk_gap_buffer_create_from_data_##type##(type *data, size_t len) { \
+ struct ltk_gap_buffer_##type## *gb = \
+ malloc(sizeof(struct ltk_gap_buffer)); \
+ if (!gb) { \
+ (void)fprintf(stderr, "Out of memory while trying to" \
+ "allocate gap buffer\n"); \
+ exit(1); \
+ } \
+ gb->buf = data; \
+ gb->buf_size = len; \
+ gb->gap_left = 0; \
+ gb->gap_size = 0; \
+ return gb; \
+} \
+ \
+void \
+ltk_gap_buffer_resize_gap_##type##(struct ltk_gap_buffer *gb, int len) { \
+ /* FIXME: Should this use realloc? It's usually more efficient, but \
+ in this case, I would still need to copy the part after the gap \
+ manually, so it could potentially be copied twice, which really \
+ wouldn't be good. Maybe use realloc if only a small part is after \
+ the gap and just regular malloc otherwise? */ \
+ int new_size = gb->buf_size - gb->gap-size + len; \
+ struct ltk_gap_buffer_##type## *new = malloc(new_size * sizeof(type)); \
+ if (!new) { \
+ (void)fprintf(stderr, "Out of memory while trying to" \
+ "resize gap buffer\n"); \
+ exit(1); \
+ } \
+ for (int i = 0; i < gb->gap_left; i++) { \
+ new[i] = gb->buf[i]; \
+ } \
+ for (int i = gb->gap_left + gb->gap_size; i < gb->buf_size) { \
+ new[i - gb->gap_size + len] = gb->buf[i]; \
+ } \
+ free(gb->buf); \
+ gb->buf = new; \
+} \
+ \
+void \
+ltk_gap_buffer_insert_##type##(struct ltk_gap_buffer_##type## *gb, \
+ type *new, size_t start, size_t len) { \
+ if (gb->gap_size < len) \
+ ltk_gap_buffer_resize_gap_##type##(gb, len + 8); \
+ for (int i = 0; i < len; i++) { \
+ gb->buf[gb->gap_left + i] = new[start + i]; \
+ } \
+ gb->gap_left = gb->gap_left + len; \
+ gb->gap_size -= len; \
+} \
+ \
+void \
+ltk_gap_buffer_insert_single_##type##( \
+ struct ltk_gap_buffer_##type## *gb, type new) { \
+ ltk_gap_buffer_insert_##type##(gb, &new, 0, 1); \
+} \
+ \
+void \
+ltk_gap_buffer_move_gap_##type##( \
+ struct ltk_gap_buffer_##type## *gb, size_t pos) { \
+ if (pos == gb->gap_left) \
+ return; \
+ if (pos < 0 || pos > gb->buf_size - gb->gap_size) { \
+ (void)fprintf(stderr, "Index out of range while moving" \
+ "gap buffer gap\n"); \
+ return; \
+ } \
+ if (pos >= gb->gap_left) { \
+ for (int i = gb->gap_left; i < pos) { \
+ gb->buf[i] = gb->buf[i + gb->gap_size]; \
+ } \
+ } else { \
+ for (int i = gb->gap_left - 1; i >= pos; i--) { \
+ gb->buf[i + gb->gap_size] = gb->buf[i]; \
+ } \
+ } \
+ gb->gap_left = pos; \
+} \
+ \
+void \
+ltk_gap_buffer_destroy_##type##(struct ltk_gap_buffer_##type## *gb) { \
+ free(gb->buf); \
+ free(gb); \
+}
+
+#endif /* _LTK_GAP_BUFFER_H_ */
diff --git a/test1.c b/test1.c
@@ -34,8 +34,8 @@ int main(int argc, char *argv[])
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, "پَیدایش", 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);
ltk_mainloop();
}
diff --git a/text-hb.c b/text-hb.c
@@ -338,11 +338,17 @@ ltk_create_text_line(LtkTextManager *tm, char *text, uint16_t fontid, uint16_t s
}
FriBidiCharType *pbase_dir = malloc(sizeof(FriBidiCharType) * ulen);
for (int i = 0; i < ulen; i++) {
- pbase_dir[i] = FRIBIDI_TYPE_ON;
+ pbase_dir[i] = i;
}
+ FriBidiCharType pbase_dir1 = FRIBIDI_TYPE_ON;
FriBidiChar *vis_str = malloc(sizeof(FriBidiChar) * ulen);
ulen = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, strlen(text), log_str);
- fribidi_log2vis(log_str, ulen, pbase_dir, vis_str, NULL, NULL, NULL);
+ fribidi_log2vis(log_str, ulen, &pbase_dir1, vis_str, pbase_dir, NULL, NULL);
+ printf("%d\n", pbase_dir1);
+ for (int i = 0; i < ulen; i++) {
+ printf("%d ", pbase_dir[i]);
+ }
+ printf("\n");
hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default();
hb_script_t cur_script = hb_unicode_script(ufuncs, vis_str[0]);
@@ -500,7 +506,7 @@ ltk_create_text_segment(LtkTextManager *tm, uint32_t *text, unsigned int len, ui
hb_direction_t dir = hb_script_get_horizontal_direction(script);
hb_buffer_set_direction(buf, dir);
hb_buffer_set_script(buf, script);
- hb_buffer_add_codepoints(buf, ts->str, len, 1, len-1);
+ hb_buffer_add_codepoints(buf, ts->str, len, 0, 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);
@@ -518,9 +524,6 @@ ltk_create_text_segment(LtkTextManager *tm, uint32_t *text, unsigned int len, ui
/* magic, do not touch */
LtkGlyph *glyph;
for (int i = 0; i < text_len; i++) {
- if (len == 7) {
- printf("%d\n", ginf[i].cluster);
- }
gi = &ginf[i];
gp = &gpos[i];
glyph = malloc(sizeof(LtkGlyph));
diff --git a/textedit_wip.c b/textedit_wip.c
@@ -316,143 +316,6 @@ ltk_get_font(LtkTextManager *tm, char *path)
return id;
}
-/* FIXME: allow to either use fribidi for basic shaping and don't use harfbuzz then,
- or just use harfbuzz (then fribidi doesn't need to do any shaping) */
-LtkTextLine *
-ltk_create_text_line(LtkTextManager *tm, char *text, uint16_t fontid, uint16_t size)
-{
- /* NOTE: This doesn't actually take fontid into account right now - should it? */
- LtkTextLine *tl = malloc(sizeof(LtkTextLine));
- tl->start_segment = NULL;
- LtkTextSegment *cur_ts = NULL;
- LtkTextSegment *new_ts = NULL;
- uint16_t cur_font_id = fontid;
- int k;
- LtkFont *font;
-
- unsigned int ulen = u8_strlen(text);
- FriBidiChar *log_str = malloc(sizeof(FriBidiChar) * ulen);
- size_t inc = 0;
- for (int i = 0; i < ulen; i++) {
- log_str[i] = u8_nextmemchar(text, &inc);
- }
- FriBidiCharType *pbase_dir = malloc(sizeof(FriBidiCharType) * ulen);
- for (int i = 0; i < ulen; i++) {
- pbase_dir[i] = FRIBIDI_TYPE_ON;
- }
- FriBidiChar *vis_str = malloc(sizeof(FriBidiChar) * ulen);
- ulen = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, strlen(text), log_str);
- fribidi_log2vis(log_str, ulen, pbase_dir, vis_str, NULL, NULL, NULL);
-
- hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default();
- hb_script_t cur_script = hb_unicode_script(ufuncs, vis_str[0]);
- hb_script_t last_script = cur_script;
- size_t pos = 0;
- size_t last_pos = 0;
- size_t start_pos = 0;
- uint32_t ch;
-
- for (int p = 0; p <= ulen; p++) {
- cur_script = hb_unicode_script(ufuncs, vis_str[p]);
- if (p == ulen ||
- (last_script != cur_script &&
- cur_script != HB_SCRIPT_INHERITED &&
- cur_script != HB_SCRIPT_COMMON)) {
- FcPattern *pat = FcPatternDuplicate(tm->fcpattern);
- FcPattern *match;
- FcResult result;
- FcPatternAddBool(pat, FC_SCALABLE, 1);
- FcConfigSubstitute(NULL, pat, FcMatchPattern);
- FcDefaultSubstitute(pat);
- FcCharSet *cs = FcCharSetCreate();
- for (int i = start_pos; i < p; i++) {
- FcCharSetAddChar(cs, vis_str[i]);
- }
- FcPatternAddCharSet(pat, FC_CHARSET, cs);
- match = FcFontMatch(NULL, pat, &result);
- char *file;
- FcPatternGetString(match, FC_FILE, 0, &file);
- cur_font_id = ltk_get_font(tm, file);
- k = kh_get(fontstruct, tm->font_cache, cur_font_id);
- font = kh_value(tm->font_cache, k);
- FcPatternDestroy(match);
- FcPatternDestroy(pat);
- // handle case that this is the last character
- if (p == ulen) {
- last_script = cur_script;
- }
- /* FIXME: There should be better handling for cases
- where an error occurs while creating the segment */
- new_ts = ltk_create_text_segment(
- tm, vis_str + start_pos,
- p - start_pos, cur_font_id,
- size, last_script
- );
- if (!new_ts) continue;
- new_ts->next = NULL;
- if (!tl->start_segment) tl->start_segment = new_ts;
- if (cur_ts) cur_ts->next = new_ts;
- cur_ts = new_ts;
-
- start_pos = p;
- last_script = cur_script;
- }
- }
-
- free(vis_str);
- free(log_str);
- free(pbase_dir);
-
- /* calculate width of text line
- NOTE: doesn't work with mixed horizontal and vertical text */
- LtkTextSegment *ts = tl->start_segment;
- int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir);
- tl->y_max = tl->x_max = INT_MIN;
- tl->y_min = tl->x_min = INT_MAX;
- tl->w = tl->h = 0;
- while (ts) {
- if (HB_DIRECTION_IS_HORIZONTAL(ts->dir) != is_hor) {
- (void)fprintf(stderr, "WARNING: mixed horizontal/vertical text is not supported; ignoring\n");
- continue;
- }
- if (is_hor) {
- if (tl->y_max < ts->y_max) {
- tl->y_max = ts->y_max;
- }
- if (tl->y_min > ts->y_min) {
- tl->y_min = ts->y_min;
- }
- tl->w += ts->w;
- } else {
- if (tl->x_max < ts->x_max) {
- tl->x_max = ts->x_max;
- }
- if (tl->x_min > ts->x_min) {
- tl->x_min = ts->x_min;
- }
- tl->h += ts->h;
- }
- ts = ts->next;
- }
- if (is_hor) {
- tl->h = tl->y_max - tl->y_min;
- } else {
- tl->w = tl->x_max - tl->x_min;
- }
-
- return tl;
-}
-
-void
-ltk_destroy_text_line(LtkTextLine *tl) {
- LtkTextSegment *last_ts;
- LtkTextSegment *cur_ts = tl->start_segment;
- while (cur_ts) {
- last_ts = cur_ts;
- cur_ts = cur_ts->next;
- ltk_destroy_text_segment(last_ts);
- }
-}
/* FIXME: could use unsigned int for fontid and size as long as there is code to check neither of them become too large
-> in case I want to get rid of uint_16_t, etc. */
@@ -719,19 +582,32 @@ ltk_gap_buffer_create(void) {
struct ltk_gap_buffer *gb = malloc(sizeof(struct ltk_gap_buffer));
if (!gb)
goto error;
- gb->buf = malloc(4 * sizeof(uint32_t));
+ gb->buf = malloc(8 * sizeof(uint32_t));
if (!gb->buf)
goto error;
gb->buf_size = 8;
gb->gap_left = 0;
gb->gap_size = 8;
- gb->gap_end_left = 8;
return gb;
error:
(void)fprintf(stderr, "Out of memory while trying to allocate gap buffer\n");
exit(1);
}
+struct ltk_gap_buffer *
+ltk_gap_buffer_create_from_data(uint32_t *data, size_t len) {
+ struct ltk_gap_buffer *gb = malloc(sizeof(struct ltk_gap_buffer));
+ if (!gb) {
+ (void)fprintf(stderr, "Out of memory while trying to allocate gap buffer\n");
+ exit(1);
+ }
+ gb->buf = data;
+ gb->buf_size = len;
+ gb->gap_left = 0;
+ gb->gap_size = 0;
+ return gb;
+}
+
void
ltk_gap_buffer_resize_gap(struct ltk_gap_buffer *gb, int len) {
/* FIXME: Should this use realloc? It's usually more efficient, but
@@ -748,7 +624,7 @@ ltk_gap_buffer_resize_gap(struct ltk_gap_buffer *gb, int len) {
for (int i = 0; i < gb->gap_left; i++) {
new[i] = gb->buf[i];
}
- for (int i = gb->gap_left + gb->gap_size; i < gb->gap_end_left) {
+ for (int i = gb->gap_left + gb->gap_size; i < gb->buf_size) {
new[i - gb->gap_size + len] = gb->buf[i];
}
free(gb->buf);
@@ -775,7 +651,7 @@ void
ltk_gap_buffer_move_gap(struct ltk_gap_buffer *gb, size_t pos) {
if (pos == gb->gap_left)
return;
- if (pos < 0 || pos >= gb->gap_end_left - gb->gap_size) {
+ if (pos < 0 || pos > gb->buf_size - gb->gap_size) {
(void)fprintf(stderr, "Index out of range while moving gap buffer gap\n");
return;
}
@@ -796,3 +672,149 @@ ltk_gap_buffer_destroy(struct ltk_gap_buffer *gb) {
free(gb->buf);
free(gb);
}
+
+void
+ltk_text_line_insert_text(struct ltk_text_line *tl, uint32_t *text, size_t len) {
+ /* check if any characters have a different script, only recalc then */
+}
+
+void
+ltk_text_line_delete_text(struct ltk_text_line *tl, size_t len) {
+}
+
+void
+ltk_text_line_delete_cur_cluster(struct ltk_text_line *tl) {
+}
+
+/* FIXME: allow to either use fribidi for basic shaping and don't use harfbuzz then,
+ or just use harfbuzz (then fribidi doesn't need to do any shaping) */
+LtkTextLine *
+ltk_create_text_line(LtkTextManager *tm, char *text, uint16_t fontid, uint16_t size)
+{
+ /* NOTE: This doesn't actually take fontid into account right now - should it? */
+ LtkTextLine *tl = malloc(sizeof(LtkTextLine));
+ tl->start_segment = NULL;
+ LtkTextSegment *cur_ts = NULL;
+ LtkTextSegment *new_ts = NULL;
+ uint16_t cur_font_id = fontid;
+ int k;
+ LtkFont *font;
+
+ unsigned int ulen = u8_strlen(text);
+ uint32_t *log_str = malloc(sizeof(uint32_t) * ulen);
+ size_t inc = 0;
+ for (int i = 0; i < ulen; i++) {
+ log_str[i] = u8_nextmemchar(text, &inc);
+ }
+ FriBidiChar *vis_str = malloc(sizeof(FriBidiChar) * ulen);
+ ulen = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, text, strlen(text), log_str);
+ fribidi_log2vis(log_str, ulen, pbase_dir, vis_str, NULL, NULL, NULL);
+
+ hb_unicode_funcs_t *ufuncs = hb_unicode_funcs_get_default();
+ hb_script_t cur_script = hb_unicode_script(ufuncs, vis_str[0]);
+ hb_script_t last_script = cur_script;
+ size_t pos = 0;
+ size_t last_pos = 0;
+ size_t start_pos = 0;
+ uint32_t ch;
+
+ for (int p = 0; p <= ulen; p++) {
+ cur_script = hb_unicode_script(ufuncs, vis_str[p]);
+ if (p == ulen ||
+ (last_script != cur_script &&
+ cur_script != HB_SCRIPT_INHERITED &&
+ cur_script != HB_SCRIPT_COMMON)) {
+ FcPattern *pat = FcPatternDuplicate(tm->fcpattern);
+ FcPattern *match;
+ FcResult result;
+ FcPatternAddBool(pat, FC_SCALABLE, 1);
+ FcConfigSubstitute(NULL, pat, FcMatchPattern);
+ FcDefaultSubstitute(pat);
+ FcCharSet *cs = FcCharSetCreate();
+ for (int i = start_pos; i < p; i++) {
+ FcCharSetAddChar(cs, vis_str[i]);
+ }
+ FcPatternAddCharSet(pat, FC_CHARSET, cs);
+ match = FcFontMatch(NULL, pat, &result);
+ char *file;
+ FcPatternGetString(match, FC_FILE, 0, &file);
+ cur_font_id = ltk_get_font(tm, file);
+ k = kh_get(fontstruct, tm->font_cache, cur_font_id);
+ font = kh_value(tm->font_cache, k);
+ FcPatternDestroy(match);
+ FcPatternDestroy(pat);
+ // handle case that this is the last character
+ if (p == ulen) {
+ last_script = cur_script;
+ }
+ /* FIXME: There should be better handling for cases
+ where an error occurs while creating the segment */
+ new_ts = ltk_create_text_segment(
+ tm, vis_str + start_pos,
+ p - start_pos, cur_font_id,
+ size, last_script
+ );
+ if (!new_ts) continue;
+ new_ts->next = NULL;
+ if (!tl->start_segment) tl->start_segment = new_ts;
+ if (cur_ts) cur_ts->next = new_ts;
+ cur_ts = new_ts;
+
+ start_pos = p;
+ last_script = cur_script;
+ }
+ }
+
+ free(vis_str);
+ free(log_str);
+
+ /* calculate width of text line
+ NOTE: doesn't work with mixed horizontal and vertical text */
+ LtkTextSegment *ts = tl->start_segment;
+ int is_hor = HB_DIRECTION_IS_HORIZONTAL(ts->dir);
+ tl->y_max = tl->x_max = INT_MIN;
+ tl->y_min = tl->x_min = INT_MAX;
+ tl->w = tl->h = 0;
+ while (ts) {
+ if (HB_DIRECTION_IS_HORIZONTAL(ts->dir) != is_hor) {
+ (void)fprintf(stderr, "WARNING: mixed horizontal/vertical text is not supported; ignoring\n");
+ continue;
+ }
+ if (is_hor) {
+ if (tl->y_max < ts->y_max) {
+ tl->y_max = ts->y_max;
+ }
+ if (tl->y_min > ts->y_min) {
+ tl->y_min = ts->y_min;
+ }
+ tl->w += ts->w;
+ } else {
+ if (tl->x_max < ts->x_max) {
+ tl->x_max = ts->x_max;
+ }
+ if (tl->x_min > ts->x_min) {
+ tl->x_min = ts->x_min;
+ }
+ tl->h += ts->h;
+ }
+ ts = ts->next;
+ }
+ if (is_hor) {
+ tl->h = tl->y_max - tl->y_min;
+ } else {
+ tl->w = tl->x_max - tl->x_min;
+ }
+
+ return tl;
+}
+
+void
+ltk_destroy_text_line(LtkTextLine *tl) {
+ LtkTextSegment *last_ts;
+ LtkTextSegment *cur_ts = tl->start_segment;
+ while (cur_ts) {
+ last_ts = cur_ts;
+ cur_ts = cur_ts->next;
+ ltk_destroy_text_segment(last_ts);
+ }
+}
diff --git a/textedit_wip.h b/textedit_wip.h
@@ -48,18 +48,41 @@ struct ltk_gap_buffer {
size_t buf_size;
size_t gap_left;
size_t gap_size;
- size_t gap_end_left;
+};
+
+/* FIXME: macro version of gap buffer */
+struct ltk_text_run {
+ /* maybe make gap buffer of glyphs? */
+ struct ltk_glyph *head_glyph;
+ struct ltk_glyph *cur_glyph;
+ struct ltk_text_run *next;
+ LtkFont *font;
+ unsigned int w;
+ unsigned int h;
+ int start_x;
+ int start_y;
+ int x_min;
+ int y_min;
+ int x_max;
+ int y_max;
+ hb_script_t script;
+}
+
+struct ltk_text_line {
+ struct ltk_gap_buffer *text_buf; /* buffer of the logical text */
+ struct ltk_gap_buffer *visual_text; /* buffer of visual text */
+ /* still need log2vis and vis2log */
+ struct ltk_text_run *runs; /* first 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) */
+ FribidiCharType dir; /* overall paragraph direction */
};
struct ltk_text_buffer {
- uint32_t *buffer;
- struct ltk_glyph *glyphs;
- size_t buf_size;
- size_t buf_left;
- size_t buf_gap_size;
- size_t glyphs_size;
- size_t glyphs_left;
- size_t glyphs_gap_size;
+ struct ltk_text_line *head;
+ struct ltk_text_line *cur_line;
+ unsigned int line_gap;
};
typedef struct {