commit 63762ef33368a564ca5f630cde74981c63d32cd7
parent c2f5daed6266253ce6b97e240d74fa9a51972bd4
Author: lumidify <nobody@lumidify.org>
Date:   Sun,  7 Jun 2020 14:24:21 +0200
Make text rendering standalone
Diffstat:
| M | button.c |  |  | 6 | ++---- | 
| M | grid.c |  |  | 2 | -- | 
| M | ltk.c |  |  | 6 | ++---- | 
| M | ltk.h |  |  | 1 | - | 
| M | text_common.c |  |  | 331 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- | 
| M | text_common.h |  |  | 60 | ++++++------------------------------------------------------ | 
| M | text_line.c |  |  | 127 | ++++++++++++++----------------------------------------------------------------- | 
| M | text_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) {
 	    <k_button_draw, <k_button_destroy, 1, LTK_BUTTON);
 	button->widget.mouse_release = <k_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_ */