ltk

Socket-based GUI for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 63762ef33368a564ca5f630cde74981c63d32cd7
parent c2f5daed6266253ce6b97e240d74fa9a51972bd4
Author: lumidify <nobody@lumidify.org>
Date:   Sun,  7 Jun 2020 14:24:21 +0200

Make text rendering standalone

Diffstat:
Mbutton.c | 6++----
Mgrid.c | 2--
Mltk.c | 6++----
Mltk.h | 1-
Mtext_common.c | 331++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mtext_common.h | 60++++++------------------------------------------------------
Mtext_line.c | 127++++++++++++++-----------------------------------------------------------------
Mtext_line.h | 12+++++-------
8 files changed, 273 insertions(+), 272 deletions(-)

diff --git a/button.c b/button.c @@ -29,8 +29,6 @@ #include <X11/Xutil.h> #include "util.h" #include "khash.h" -#include "stb_truetype.h" -#include <fontconfig/fontconfig.h> #include "text_common.h" #include "ltk.h" #include "text_line.h" @@ -160,7 +158,7 @@ ltk_button_create(ltk_window *window, const char *id, const char *text) { &ltk_button_draw, &ltk_button_destroy, 1, LTK_BUTTON); button->widget.mouse_release = &ltk_button_mouse_release; uint16_t font_size = window->theme->window->font_size; - button->tl = ltk_text_line_create(window, font_size, strdup(text)); + button->tl = ltk_text_line_create(font_size, strdup(text)); ltk_button_theme *theme = window->theme->button; button->widget.rect.w = button->tl->w + theme->border_width * 2 + theme->pad * 2; button->widget.rect.h = button->tl->h + theme->border_width * 2 + theme->pad * 2; @@ -178,7 +176,7 @@ ltk_button_destroy(ltk_button *button, int shallow) { (void)printf("WARNING: Tried to destroy NULL button.\n"); return; } - ltk_text_line_destroy(button->widget.window, button->tl); + ltk_text_line_destroy(button->tl); ltk_remove_widget(button->widget.window, button->widget.id); free(button->widget.id); free(button); diff --git a/grid.c b/grid.c @@ -31,8 +31,6 @@ #include <X11/Xutil.h> #include "util.h" #include "khash.h" -#include "stb_truetype.h" -#include <fontconfig/fontconfig.h> #include "text_common.h" #include "ltk.h" #include "grid.h" diff --git a/ltk.c b/ltk.c @@ -35,8 +35,6 @@ #include "util.h" #include "khash.h" #include "ini.h" -#include "stb_truetype.h" -#include <fontconfig/fontconfig.h> #include "text_common.h" #include "ltk.h" #include "grid.h" @@ -322,7 +320,7 @@ ltk_create_window(const char *theme_path, const char *title, int x, int y, unsig window->wm_delete_msg = XInternAtom(window->dpy, "WM_DELETE_WINDOW", False); ltk_window_theme *wtheme = window->theme->window; - window->tm = ltk_init_text(wtheme->font); + ltk_init_default_font(wtheme->font); window->xwindow = XCreateSimpleWindow(window->dpy, DefaultRootWindow(window->dpy), x, y, w, h, wtheme->border_width, @@ -371,7 +369,7 @@ ltk_destroy_window(ltk_window *window) { } } kh_destroy(widget, window->widget_hash); - ltk_destroy_text(window->tm); + ltk_cleanup_text(); free(window); } diff --git a/ltk.h b/ltk.h @@ -125,7 +125,6 @@ typedef struct ltk_window { struct ltk_event_queue *first_event; struct ltk_event_queue *last_event; khash_t(widget) *widget_hash; - ltk_text *tm; } ltk_window; char *ltk_read_file(const char *path, unsigned long *len); diff --git a/text_common.c b/text_common.c @@ -33,6 +33,73 @@ #include "text_common.h" #include "ltk.h" +typedef struct ltk_font { + stbtt_fontinfo info; + char *path; + int index; /* index in font file */ + uint16_t id; + unsigned int refs; +} ltk_font; + +/* Hash definitions */ +/* glyph id -> glyph info struct */ +KHASH_MAP_INIT_INT(glyphinfo, ltk_glyph_info*) +/* font path, size -> glyph cache hash */ +KHASH_MAP_INIT_INT(glyphcache, khash_t(glyphinfo)*) + +static struct { + khash_t(glyphcache) *glyph_cache; + ltk_font **fonts; + int num_fonts; + int fonts_bufsize; + FcPattern *fcpattern; + ltk_font *default_font; + uint16_t font_id_cur; +} tm = {NULL, NULL, 0, 0, NULL, NULL, 1}; + +static const char *default_font; + +static void err(const char *msg); +static char *read_file(const char *path, unsigned long *len); +static ltk_font *ltk_get_font(char *path, int index); +static void ltk_init_text(void); +static ltk_glyph_info *ltk_create_glyph_info(ltk_font *font, int id, + float scale); +static voidltk_destroy_glyph_info(ltk_glyph_info *gi); +static ltk_glyph_info *ltk_get_glyph_info(ltk_font *font, int id, + float scale, khash_t(glyphinfo) *cache); +static khash_t(glyphinfo) *ltk_get_glyph_cache(uint16_t font_id, + uint16_t font_size); +static khint_t ltk_create_glyph_cache(uint16_t font_id, uint16_t font_size); +static void ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache); +static void ltk_load_default_font(void); +static ltk_font *ltk_create_font(char *path, uint16_t id, int index); +static void ltk_destroy_font(ltk_font *font); +static ltk_font *ltk_load_font(char *path, int index); +static ltk_font *ltk_get_font(char *path, int index); + +static void +err(const char *msg) { + perror(msg); + exit(1); +} + +static char * +read_file(const char *path, unsigned long *len) { + FILE *f; + char *file_contents; + f = fopen(path, "rb"); + fseek(f, 0, SEEK_END); + *len = ftell(f); + fseek(f, 0, SEEK_SET); + file_contents = malloc(*len + 1); + fread(file_contents, 1, *len, f); + file_contents[*len] = '\0'; + fclose(f); + + return file_contents; +} + /* These unicode routines are taken from * https://github.com/JeffBezanson/cutef8 */ @@ -45,8 +112,7 @@ static const uint32_t offsetsFromUTF8[6] = { }; /* next character without NUL character terminator */ -uint32_t u8_nextmemchar(const char *s, size_t *i) -{ +uint32_t u8_nextmemchar(const char *s, size_t *i) { uint32_t ch = 0; size_t sz = 0; do { @@ -60,8 +126,7 @@ uint32_t u8_nextmemchar(const char *s, size_t *i) } /* number of characters in NUL-terminated string */ -size_t u8_strlen(const char *s) -{ +size_t u8_strlen(const char *s) { size_t count = 0; size_t i = 0, lasti; @@ -77,8 +142,7 @@ size_t u8_strlen(const char *s) return count; } -size_t u8_wc_toutf8(char *dest, uint32_t ch) -{ +size_t u8_wc_toutf8(char *dest, uint32_t ch) { if (ch < 0x80) { dest[0] = (char)ch; return 1; @@ -104,45 +168,40 @@ size_t u8_wc_toutf8(char *dest, uint32_t ch) return 0; } -ltk_text * -ltk_init_text(char *font_name) -{ - ltk_text *tm = malloc(sizeof(ltk_text)); - if (!tm) ltk_fatal("Memory exhausted when trying to create text manager."); - tm->fonts = NULL; - tm->num_fonts = 0; - tm->fonts_bufsize = 1; - tm->glyph_cache = kh_init(glyphcache); - /* FIXME: THIS REALLY SHOULD NOT BE UINT16_T! IT GETS MESSY WITH BIT-SHIFTING */ - tm->font_id_cur = 1; - tm->fonts = malloc(sizeof(ltk_font *)); - if (!tm->fonts) ltk_fatal("Out of memory while trying to create text manager.\n"); - ltk_load_default_font(tm, font_name); - - return tm; +void +ltk_init_default_font(const char *font_name) { + default_font = strdup(font_name); + if (!default_font) err("ltk_init_default_font"); +} + +static void +ltk_init_text(void) { + tm.fonts_bufsize = 1; + tm.glyph_cache = kh_init(glyphcache); + tm.fonts = malloc(sizeof(ltk_font *)); + if (!tm.fonts) err("ltk_init_text"); + ltk_load_default_font(); } void -ltk_destroy_text(ltk_text *tm) -{ - for (int i = 0; i < tm->num_fonts; i++) { - ltk_destroy_font(&tm->fonts[i]); +ltk_cleanup_text(void) { + if (default_font) free(default_font); + for (int i = 0; i < tm.num_fonts; i++) { + ltk_destroy_font(&tm.fonts[i]); } - for (int k = kh_begin(tm->glyph_cache); k != kh_end(tm->glyph_cache); k++) { - if (kh_exist(tm->glyph_cache, k)) { - ltk_destroy_glyph_cache(kh_value(tm->glyph_cache, k)); + if (!tm.glyph_cache) return; + for (int k = kh_begin(tm.glyph_cache); k != kh_end(tm.glyph_cache); k++) { + if (kh_exist(tm.glyph_cache, k)) { + ltk_destroy_glyph_cache(kh_value(tm.glyph_cache, k)); } } - kh_destroy(glyphcache, tm->glyph_cache); - - free(tm); + kh_destroy(glyphcache, tm.glyph_cache); } -ltk_glyph_info * -ltk_create_glyph_info(ltk_font *font, int id, float scale) -{ +static ltk_glyph_info * +ltk_create_glyph_info(ltk_font *font, int id, float scale) { ltk_glyph_info *glyph = malloc(sizeof(ltk_glyph_info)); - if (!glyph) ltk_fatal("Out of memory while trying to create glyph info.\n"); + if (!glyph) err("ltk_create_glyph_info"); glyph->id = id; glyph->refs = 0; @@ -154,16 +213,14 @@ ltk_create_glyph_info(ltk_font *font, int id, float scale) return glyph; } -void -ltk_destroy_glyph_info(ltk_glyph_info *gi) -{ +static void +ltk_destroy_glyph_info(ltk_glyph_info *gi) { free(gi->alphamap); free(gi); } -ltk_glyph_info * -ltk_get_glyph_info(ltk_font *font, int id, float scale, khash_t(glyphinfo) *cache) -{ +static ltk_glyph_info * +ltk_get_glyph_info(ltk_font *font, int id, float scale, khash_t(glyphinfo) *cache) { int ret; khint_t k; ltk_glyph_info *glyph; @@ -180,33 +237,33 @@ ltk_get_glyph_info(ltk_font *font, int id, float scale, khash_t(glyphinfo) *cach return glyph; } -khash_t(glyphinfo) * -ltk_get_glyph_cache(ltk_text *tm, uint16_t font_id, uint16_t font_size) { +static khash_t(glyphinfo) * +ltk_get_glyph_cache(uint16_t font_id, uint16_t font_size) { + if (!tm.glyph_cache) ltk_init_text(); khint_t k; uint32_t attr = (uint32_t)font_id << 16 + font_size; - k = kh_get(glyphcache, tm->glyph_cache, attr); - if (k == kh_end(tm->glyph_cache)) { - k = ltk_create_glyph_cache(tm, font_id, font_size); + k = kh_get(glyphcache, tm.glyph_cache, attr); + if (k == kh_end(tm.glyph_cache)) { + k = ltk_create_glyph_cache(font_id, font_size); } - return kh_value(tm->glyph_cache, k); + return kh_value(tm.glyph_cache, k); } -khint_t -ltk_create_glyph_cache(ltk_text *tm, uint16_t font_id, uint16_t font_size) -{ +static khint_t +ltk_create_glyph_cache(uint16_t font_id, uint16_t font_size) { + if (!tm.glyph_cache) ltk_init_text(); khash_t(glyphinfo) *cache = kh_init(glyphinfo); int ret; khint_t k; /* I guess I can just ignore ret for now */ - k = kh_put(glyphcache, tm->glyph_cache, font_id << 16 + font_size, &ret); - kh_value(tm->glyph_cache, k) = cache; + k = kh_put(glyphcache, tm.glyph_cache, font_id << 16 + font_size, &ret); + kh_value(tm.glyph_cache, k) = cache; return k; } -void -ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache) -{ +static void +ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache) { int k; for (k = kh_begin(cache); k != kh_end(cache); k++) { if (kh_exist(cache, k)) { @@ -216,36 +273,37 @@ ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache) kh_destroy(glyphinfo, cache); } -void -ltk_load_default_font(ltk_text *tm, char *name) -{ +static void +ltk_load_default_font(void) { FcPattern *match; FcResult result; char *file; int index; uint16_t font; - tm->fcpattern = FcNameParse(name); - FcPatternAddString(tm->fcpattern, FC_FONTFORMAT, "truetype"); - FcConfigSubstitute(NULL, tm->fcpattern, FcMatchPattern); - FcDefaultSubstitute(tm->fcpattern); - match = FcFontMatch(NULL, tm->fcpattern, &result); + if (default_font) + tm.fcpattern = FcNameParse(default_font); + else + tm.fcpattern = FcPatternCreate(); + FcPatternAddString(tm.fcpattern, FC_FONTFORMAT, "truetype"); + FcConfigSubstitute(NULL, tm.fcpattern, FcMatchPattern); + FcDefaultSubstitute(tm.fcpattern); + match = FcFontMatch(NULL, tm.fcpattern, &result); FcPatternGetString(match, FC_FILE, 0, (FcChar8 **) &file); FcPatternGetInteger(match, FC_INDEX, 0, &index); - tm->default_font = ltk_get_font(tm, file, index); + tm.default_font = ltk_get_font(file, index); FcPatternDestroy(match); } -ltk_font * -ltk_create_font(char *path, uint16_t id, int index) -{ +static ltk_font * +ltk_create_font(char *path, uint16_t id, int index) { long len; ltk_font *font = malloc(sizeof(ltk_font)); - if (!font) ltk_fatal("Out of memory while trying to create font.\n"); - char *contents = ltk_read_file(path, &len); + if (!font) err("ltk_create_font"); + char *contents = read_file(path, &len); /* FIXME: error checking */ int offset = stbtt_GetFontOffsetForIndex(contents, index); if (!stbtt_InitFont(&font->info, contents, offset)) { @@ -256,56 +314,139 @@ ltk_create_font(char *path, uint16_t id, int index) font->refs = 0; font->index = index; font->path = strdup(path); + if (!font->path) err("ltk_create_font"); return font; } -void -ltk_destroy_font(ltk_font *font) -{ +static void +ltk_destroy_font(ltk_font *font) { free(font->info.data); free(font); } -ltk_font * -ltk_load_font(ltk_text *tm, char *path, int index) -{ - ltk_font *font = ltk_create_font(path, tm->font_id_cur++, index); - if (tm->num_fonts == tm->fonts_bufsize) { - ltk_font *new = realloc(tm->fonts, tm->fonts_bufsize * 2 * sizeof(ltk_font *)); - if (!new) ltk_fatal("Out of memory while trying to create font.\n"); - tm->fonts = new; - tm->fonts_bufsize = tm->fonts_bufsize * 2; +static ltk_font * +ltk_load_font(char *path, int index) { + ltk_font *font = ltk_create_font(path, tm.font_id_cur++, index); + if (tm.num_fonts == tm.fonts_bufsize) { + ltk_font *new = realloc(tm.fonts, tm.fonts_bufsize * 2 * sizeof(ltk_font *)); + if (!new) err("ltk_load_font"); + tm.fonts = new; + tm.fonts_bufsize *= 2; } - tm->fonts[tm->num_fonts] = font; - tm->num_fonts++; + tm.fonts[tm.num_fonts] = font; + tm.num_fonts++; return font; } -ltk_font * -ltk_get_font(ltk_text *tm, char *path, int index) -{ +static ltk_font * +ltk_get_font(char *path, int index) { ltk_font *font = NULL; - for (int i = 0; i < tm->num_fonts; i++) { - if (tm->fonts[i]->index == index && - strcmp(tm->fonts[i]->path, path) == 0) { - font = &tm->fonts[i]; + for (int i = 0; i < tm.num_fonts; i++) { + if (tm.fonts[i]->index == index && + strcmp(tm.fonts[i]->path, path) == 0) { + font = &tm.fonts[i]; break; } } if (!font) - font = ltk_load_font(tm, path, index); + font = ltk_load_font(path, index); return font; } void -ltk_destroy_glyph(ltk_glyph *glyph, khash_t(glyphinfo) *cache) -{ +ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text, uint16_t font_size, + int *x_min, int *y_min, int *x_max, int *y_max) { + uint32_t c1, c2 = 0; + int gid; + int index; + char *file; + size_t inc = 0; + int x = 0, y, kern_advance, ax; + int x1_abs, x2_abs; + float scale; + int ascent, descent, line_gap; + *x_min = INT_MAX, *x_max = INT_MIN, *y_min = INT_MAX, *y_max = INT_MIN; + ltk_glyph_info *ginfo; + if (!tm.default_font) + ltk_init_text(); + + ltk_font *font = tm.default_font; + khash_t(glyphinfo) *glyph_cache = ltk_get_glyph_cache(font->id, font_size); + + scale = stbtt_ScaleForPixelHeight(&font->info, font_size); + stbtt_GetFontVMetrics(&font->info, &ascent, &descent, &line_gap); + ascent *= scale; + descent *= scale; + + c1 = u8_nextmemchar(text, &inc); + for (int i = 0; i < num_glyphs; i++) { + gid = stbtt_FindGlyphIndex(&font->info, c1); + if (!gid) { + /* Question: Why does this not work with FcPatternDuplicate? */ + FcPattern *pat = FcPatternCreate(); + FcPattern *match; + FcResult result; + FcPatternAddBool(pat, FC_SCALABLE, 1); + FcConfigSubstitute(NULL, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + FcCharSet *cs = FcCharSetCreate(); + FcCharSetAddChar(cs, c1); + FcPatternAddCharSet(pat, FC_CHARSET, cs); + match = FcFontMatch(NULL, pat, &result); + FcPatternGetString(match, FC_FILE, 0, &file); + FcPatternGetInteger(match, FC_INDEX, 0, &index); + font = ltk_get_font(file, index); + glyph_cache = ltk_get_glyph_cache(font->id, font_size); + FcPatternDestroy(match); + FcPatternDestroy(pat); + gid = stbtt_FindGlyphIndex(&font->info, c1); + scale = stbtt_ScaleForPixelHeight(&font->info, font_size); + stbtt_GetFontVMetrics(&font->info, &ascent, &descent, &line_gap); + ascent *= scale; + descent *= scale; + } + ginfo = ltk_get_glyph_info(font, gid, scale, glyph_cache); + ginfo->refs++; + y = ascent + ginfo->yoff; + x1_abs = x + ginfo->xoff; + + glyphs[i].x = x1_abs; + glyphs[i].y = y; + + stbtt_GetGlyphHMetrics(&font->info, gid, &ax, 0); + x += (int) (ax * scale); + x2_abs = x; + + glyphs[i].info = ginfo; + if (x1_abs < *x_min) *x_min = x1_abs; + if (y < *y_min) *y_min = y; + if (x2_abs > *x_max) *x_max = x2_abs; + if (y + ginfo->h > *y_max) *y_max = y + ginfo->h; + + if (i != num_glyphs - 1) { + c2 = u8_nextmemchar(text, &inc); + kern_advance = stbtt_GetCodepointKernAdvance(&font->info, c1, c2); + x += (int) (kern_advance * scale); + } + c1 = c2; + } +} + +/* +void +ltk_unref_glyph(ltk_glyph *glyph, khash_t(glyphinfo) *cache) { int k; if (--glyph->info->refs < 1) { k = kh_get(glyphinfo, cache, glyph->info->id); kh_del(glyphinfo, cache, k); ltk_destroy_glyph_info(glyph->info); } - free(glyph); } + +void +ltk_unref_glyphs(ltk_glyph *glyphs, int num_glyphs) { + for (int i = 0; i < num_glyphs; i++) + ltk_unref_glyph(&glyphs[i]); +} +*/ diff --git a/text_common.h b/text_common.h @@ -24,19 +24,8 @@ #ifndef _TEXT_COMMON_H_ #define _TEXT_COMMON_H_ -/* -Requires the following includes: -<X11/Xlib.h>, <X11/Xutil.h>, "stb_truetype.h", -"khash.h" -*/ - -typedef struct { - stbtt_fontinfo info; - char *path; - int index; /* index in font file */ - uint16_t id; - unsigned int refs; -} ltk_font; +typedef struct ltk_font ltk_font; +typedef struct ltk_text ltk_text; /* Contains general info on glyphs that doesn't change regardless of the context */ typedef struct { @@ -58,54 +47,17 @@ typedef struct { int y; } ltk_glyph; -/* Hash definitions */ -/* glyph id -> glyph info struct */ -KHASH_MAP_INIT_INT(glyphinfo, ltk_glyph_info*) -/* font path, size -> glyph cache hash */ -KHASH_MAP_INIT_INT(glyphcache, khash_t(glyphinfo)*) - -typedef struct { - khash_t(glyphcache) *glyph_cache; - ltk_font **fonts; - int num_fonts; - int fonts_bufsize; - FcPattern *fcpattern; - ltk_font *default_font; - uint16_t font_id_cur; -} ltk_text; - uint32_t u8_nextmemchar(const char *s, size_t *i); size_t u8_strlen(const char *s); size_t u8_wc_toutf8(char *dest, uint32_t ch); -ltk_text *ltk_init_text(char *font_name); - -void ltk_destroy_text_manager(ltk_text *tm); - -ltk_glyph_info *ltk_create_glyph_info(ltk_font *font, int id, float scale); - -void ltk_destroy_glyph_info(ltk_glyph_info *gi); - -ltk_glyph_info *ltk_get_glyph_info(ltk_font *font, int id, float scale, khash_t(glyphinfo) *cache); - -khash_t(glyphinfo) *ltk_get_glyph_cache(ltk_text *tm, uint16_t font_id, uint16_t font_size); - -khint_t ltk_create_glyph_cache(ltk_text *tm, uint16_t font_id, uint16_t font_size); - -void ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache); - -void ltk_load_default_font(ltk_text *tm, char *name); - -ltk_font *ltk_create_font(char *path, uint16_t id, int index); - -void ltk_destroy_font(ltk_font *font); - -ltk_font *ltk_load_font(ltk_text *tm, char *path, int index); +void ltk_init_default_font(const char *font_name); -ltk_font *ltk_get_font(ltk_text *tm, char *path, int index); +void ltk_cleanup_text(void); -void ltk_destroy_glyph(ltk_glyph *glyph, khash_t(glyphinfo) *cache); +void ltk_text_to_glyphs(ltk_glyph *glyphs, int num_glyphs, char *text, + uint16_t font_size, int *x_min, int *y_min, int *x_max, int *y_max); #endif /* _TEXT_COMMON_H_ */ diff --git a/text_line.c b/text_line.c @@ -24,16 +24,24 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> -#include <limits.h> #include <X11/Xlib.h> #include <X11/Xutil.h> -#include "stb_truetype.h" /* http://nothings.org/stb/stb_truetype.h */ -#include <fontconfig/fontconfig.h> -#include "khash.h" #include "text_common.h" -#include "ltk.h" #include "text_line.h" +static void err(const char *msg); +static void ltk_text_line_create_glyphs(struct ltk_text_line *tl); +static void ltk_text_line_draw_glyph(ltk_glyph *glyph, int xoff, int yoff, + XImage *img, XColor fg); +static XImage *ltk_create_ximage(Display *dpy, int w, int h, int depth, + XColor bg); + +static void +err(const char *msg) { + perror(msg); + exit(1); +} + static XImage * ltk_create_ximage(Display *dpy, int w, int h, int depth, XColor bg) { XImage *img = XCreateImage(dpy, CopyFromParent, depth, ZPixmap, 0, NULL, w, h, 32, 0); @@ -99,78 +107,10 @@ ltk_text_line_render( } static void -ltk_text_line_create_glyphs(ltk_window *window, struct ltk_text_line *tl) { - uint32_t c1, c2 = 0; - int gid; - int index; - char *file; - size_t inc = 0; - int x = 0, y, kern_advance, ax; - int x1_abs, x2_abs; - float scale; - int ascent, descent, line_gap; - int x_min = INT_MAX, x_max = INT_MIN, y_min = INT_MAX, y_max = INT_MIN; - ltk_glyph_info *ginfo; - - ltk_font *font = window->tm->default_font; - khash_t(glyphinfo) *glyph_cache = ltk_get_glyph_cache(window->tm, font->id, tl->font_size); - - scale = stbtt_ScaleForPixelHeight(&font->info, tl->font_size); - stbtt_GetFontVMetrics(&font->info, &ascent, &descent, &line_gap); - ascent *= scale; - descent *= scale; - - c1 = u8_nextmemchar(tl->text, &inc); - for (int i = 0; i < tl->glyph_len; i++) { - gid = stbtt_FindGlyphIndex(&font->info, c1); - if (!gid) { - /* Question: Why does this not work with FcPatternDuplicate? */ - FcPattern *pat = FcPatternCreate(); - FcPattern *match; - FcResult result; - FcPatternAddBool(pat, FC_SCALABLE, 1); - FcConfigSubstitute(NULL, pat, FcMatchPattern); - FcDefaultSubstitute(pat); - FcCharSet *cs = FcCharSetCreate(); - FcCharSetAddChar(cs, c1); - FcPatternAddCharSet(pat, FC_CHARSET, cs); - match = FcFontMatch(NULL, pat, &result); - FcPatternGetString(match, FC_FILE, 0, &file); - FcPatternGetInteger(match, FC_INDEX, 0, &index); - font = ltk_get_font(window->tm, file, index); - glyph_cache = ltk_get_glyph_cache(window->tm, font->id, tl->font_size); - FcPatternDestroy(match); - FcPatternDestroy(pat); - gid = stbtt_FindGlyphIndex(&font->info, c1); - scale = stbtt_ScaleForPixelHeight(&font->info, tl->font_size); - stbtt_GetFontVMetrics(&font->info, &ascent, &descent, &line_gap); - ascent *= scale; - descent *= scale; - } - ginfo = ltk_get_glyph_info(font, gid, scale, glyph_cache); - y = ascent + ginfo->yoff; - x1_abs = x + ginfo->xoff; - - tl->glyphs[i].x = x1_abs; - tl->glyphs[i].y = y; - - stbtt_GetGlyphHMetrics(&font->info, gid, &ax, 0); - x += (int) (ax * scale); - x2_abs = x; - - tl->glyphs[i].info = ginfo; - if (x1_abs < x_min) x_min = x1_abs; - if (y < y_min) y_min = y; - if (x2_abs > x_max) x_max = x2_abs; - if (y + ginfo->h > y_max) y_max = y + ginfo->h; - - if (i != tl->glyph_len - 1) { - c2 = u8_nextmemchar(tl->text, &inc); - kern_advance = stbtt_GetCodepointKernAdvance(&font->info, c1, c2); - x += (int) (kern_advance * scale); - } - c1 = c2; - }; +ltk_text_line_create_glyphs(struct ltk_text_line *tl) { + int x_min, x_max, y_min, y_max; + ltk_text_to_glyphs(tl->glyphs, tl->glyph_len, tl->text, tl->font_size, + &x_min, &y_min, &x_max, &y_max); /* for drawing the glyphs at the right position on the image */ tl->x_min = x_min; tl->y_min = y_min; @@ -179,44 +119,21 @@ ltk_text_line_create_glyphs(ltk_window *window, struct ltk_text_line *tl) { } struct ltk_text_line * -ltk_text_line_create(ltk_window *window, uint16_t font_size, char *text) { +ltk_text_line_create(uint16_t font_size, char *text) { struct ltk_text_line *line = malloc(sizeof(struct ltk_text_line)); - if (!line) goto error; + if (!line) err("ltk_text_line_create"); line->text = text; line->glyph_len = u8_strlen(text); line->glyphs = malloc(line->glyph_len * sizeof(ltk_glyph)); line->font_size = font_size; - ltk_text_line_create_glyphs(window, line); + ltk_text_line_create_glyphs(line); return line; -error: - (void)fprintf(stderr, "No memory left while creating text line\n"); - exit(1); } void -ltk_text_line_destroy(ltk_window *window, struct ltk_text_line *tl) { +ltk_text_line_destroy(struct ltk_text_line *tl) { free(tl->text); - /* FIXME: glyph reference counting */ + /* FIXME: Reference count glyph infos */ free(tl->glyphs); - /* - khint_t k; - LtkTextManager *tm = ltk_get_text_manager(); - k = kh_get(glyphinfo, tm->glyph_cache, tr->font_id << 16 + tr->font_size); - gcache = kh_value(tm->glyph_cache, k); - 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); - kh_del(glyphinfo, gcache, k); - ltk_destroy_glyph_info(glyph->info); - } - } - k = kh_get(fontstruct, tm->font_cache, tr->font_id); - font = kh_value(tm->font_cache, k); - if (--font->refs < 1) { - kh_del(fontstruct, tm->font_cache, k); - ltk_destroy_font(font); - } - */ free(tl); } diff --git a/text_line.h b/text_line.h @@ -26,9 +26,7 @@ /* Requires the following includes: -<X11/Xlib.h>, <X11/Xutil.h>, "stb_truetype.h", -"khash.h", <fontconfig/fontconfig.h>, "text_common.h", -"ltk.h" +<X11/Xlib.h>, <X11/Xutil.h>, "text_common.h", */ struct ltk_text_line { @@ -42,9 +40,9 @@ struct ltk_text_line { int y_min; }; -XImage *ltk_text_line_render(struct ltk_text_line *tl, - Display *dpy, Window window, GC gc, Colormap colormap, XColor fg, XColor bg); -struct ltk_text_line *ltk_text_line_create(ltk_window *window, uint16_t font_size, char *text); -void ltk_text_line_destroy(ltk_window *window, struct ltk_text_line *tl); +XImage *ltk_text_line_render(struct ltk_text_line *tl, Display *dpy, + Window window, GC gc, Colormap colormap, XColor fg, XColor bg); +struct ltk_text_line *ltk_text_line_create(uint16_t font_size, char *text); +void ltk_text_line_destroy(struct ltk_text_line *tl); #endif /* _TEXT_BUFFER_H_ */