commit f344c3f28da7995f19ec0549d90f275d3fd1715a
parent 57d85ccfe4c9ac3de63dab6979e65dbe0696f4b7
Author: lumidify <nobody@lumidify.org>
Date:   Fri,  8 May 2020 20:57:03 +0200
Move common text functions to text-common.*
Diffstat:
| M | Makefile |  |  | 4 | ++-- | 
| M | button.c |  |  | 1 | + | 
| M | gap_buffer.h |  |  | 4 | ++-- | 
| M | ltk.c |  |  | 1 | + | 
| M | ltkx.h |  |  | 1 | + | 
| A | text-common.c |  |  | 409 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | text-common.h |  |  | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| M | text-hb.c |  |  | 291 | +------------------------------------------------------------------------------ | 
| M | text-hb.h |  |  | 83 | ++----------------------------------------------------------------------------- | 
9 files changed, 544 insertions(+), 375 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
 LIBS = -lm `pkg-config --libs x11 harfbuzz fontconfig fribidi`
 STD = -std=c99
 CFLAGS = -g -w -fcommon -Wall -Werror -Wextra `pkg-config --cflags x11 harfbuzz fontconfig fribidi` -pedantic
-OBJ = stb_truetype.o text-hb.o ltk.o ini.o grid.o button.o test1.o
+OBJ = stb_truetype.o text-common.o text-hb.o ltk.o ini.o grid.o button.o test1.o
 
 test1: $(OBJ)
 	gcc $(STD) -o $@ $(OBJ) $(LIBS)
@@ -12,4 +12,4 @@ test1: $(OBJ)
 .PHONY: clean
 
 clean:
-	rm -f stb_truetype.o text-hb.o ltk.o ini.o grid.o button.o test1.o test1
+	rm -f stb_truetype.o text-common.o text-hb.o ltk.o ini.o grid.o button.o test1.o test1
diff --git a/button.c b/button.c
@@ -29,6 +29,7 @@
 #include <fribidi.h>
 #include <harfbuzz/hb.h>
 #include <fontconfig/fontconfig.h>
+#include "text-common.h"
 #include "text-hb.h"
 #include "button.h"
 
diff --git a/gap_buffer.h b/gap_buffer.h
@@ -27,7 +27,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#define LTK_INIT_GAP_BUFFER_DECL(type)						\
+#define LTK_GAP_BUFFER_INIT_DECL(type)						\
 struct ltk_gap_buffer_##type## {						\
 	type *buf;								\
 	size_t buf_size;							\
@@ -47,7 +47,7 @@ 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)						\
+#define LTK_GAP_BUFFER_INIT_IMPL(type)						\
 struct ltk_gap_buffer_##type## *						\
 ltk_gap_buffer_create_##type##(void) {						\
 	struct ltk_gap_buffer_##type## *gb =					\
diff --git a/ltk.c b/ltk.c
@@ -32,6 +32,7 @@
 #include <fribidi.h>
 #include <harfbuzz/hb.h>
 #include <fontconfig/fontconfig.h>
+#include "text-common.h"
 #include "text-hb.h"
 
 Ltk *ltk_global;
diff --git a/ltkx.h b/ltkx.h
@@ -8,6 +8,7 @@
 #include <fribidi.h>
 #include <harfbuzz/hb.h>
 #include <harfbuzz/hb-ot.h>
+#include "text-common.h"
 #include "text-hb.h"
 #include "button.h"
 #include "grid.h"
diff --git a/text-common.c b/text-common.c
@@ -0,0 +1,409 @@
+/*
+ * This file is part of the Lumidify ToolKit (LTK)
+ * Copyright (c) 2017, 2018, 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.
+ */
+
+#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 <fribidi.h>
+#include <harfbuzz/hb.h>
+#include <harfbuzz/hb-ot.h>
+#include "text-common.h"
+#include "ltk.h"
+
+extern Ltk *ltk_global;
+
+/* These unicode routines are taken from
+ * https://github.com/JeffBezanson/cutef8 */
+
+/* is c the start of a utf8 sequence? */
+#define isutf(c) (((c)&0xC0)!=0x80)
+
+static const uint32_t offsetsFromUTF8[6] = {
+    0x00000000UL, 0x00003080UL, 0x000E2080UL,
+    0x03C82080UL, 0xFA082080UL, 0x82082080UL
+};
+
+/* next character without NUL character terminator */
+uint32_t u8_nextmemchar(const char *s, size_t *i)
+{
+    uint32_t ch = 0;
+    size_t sz = 0;
+    do {
+        ch <<= 6;
+        ch += (unsigned char)s[(*i)++];
+        sz++;
+    } while (!isutf(s[*i]));
+    ch -= offsetsFromUTF8[sz-1];
+
+    return ch;
+}
+
+/* number of characters in NUL-terminated string */
+size_t u8_strlen(const char *s)
+{
+    size_t count = 0;
+    size_t i = 0, lasti;
+
+    while (1) {
+        lasti = i;
+        while (s[i] > 0)
+            i++;
+        count += (i-lasti);
+        if (s[i++]==0) break;
+        (void)(isutf(s[++i]) || isutf(s[++i]) || ++i);
+        count++;
+    }
+    return count;
+}
+
+size_t u8_wc_toutf8(char *dest, uint32_t ch)
+{
+    if (ch < 0x80) {
+        dest[0] = (char)ch;
+        return 1;
+    }
+    if (ch < 0x800) {
+        dest[0] = (ch>>6) | 0xC0;
+        dest[1] = (ch & 0x3F) | 0x80;
+        return 2;
+    }
+    if (ch < 0x10000) {
+        dest[0] = (ch>>12) | 0xE0;
+        dest[1] = ((ch>>6) & 0x3F) | 0x80;
+        dest[2] = (ch & 0x3F) | 0x80;
+        return 3;
+    }
+    if (ch < 0x110000) {
+        dest[0] = (ch>>18) | 0xF0;
+        dest[1] = ((ch>>12) & 0x3F) | 0x80;
+        dest[2] = ((ch>>6) & 0x3F) | 0x80;
+        dest[3] = (ch & 0x3F) | 0x80;
+        return 4;
+    }
+    return 0;
+}
+
+LtkTextManager *
+ltk_init_text(char *font_name)
+{
+	LtkTextManager *tm = malloc(sizeof(LtkTextManager));
+	if (!tm) {
+		(void)printf("Memory exhausted when trying to create text manager.");
+		exit(1);
+	}
+	tm->font_paths = kh_init(fontid);
+	tm->font_cache = kh_init(fontstruct);
+	tm->glyph_cache = kh_init(glyphcache);
+	tm->font_id_cur = 0;
+	ltk_load_default_font(tm, font_name);
+
+	return tm;
+}
+
+void
+ltk_destroy_text_manager(LtkTextManager *tm)
+{
+	int k;
+
+	kh_destroy(fontid, tm->font_paths);
+
+	for (k = kh_begin(tm->font_cache); k != kh_end(tm->font_cache); k++) {
+		if (kh_exist(tm->font_cache, k)) {
+			ltk_destroy_font(kh_value(tm->font_cache, k));
+		}
+	}
+	kh_destroy(fontstruct, tm->font_cache);
+
+	for (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);
+}
+
+LtkGlyphInfo *
+ltk_create_glyph_info(LtkFont *font, unsigned int id, float scale)
+{
+	LtkGlyphInfo *glyph = malloc(sizeof(LtkGlyphInfo));
+	if (!glyph) {
+		(void)printf("Out of memory!\n");
+		exit(1);
+	}
+
+	glyph->id = id;
+	glyph->refs = 0;
+	glyph->alphamap = stbtt_GetGlyphBitmap(
+		&font->info, scale, scale, id, &glyph->w,
+		&glyph->h, &glyph->xoff, &glyph->yoff
+	);
+
+	return glyph;
+}
+
+void
+ltk_destroy_glyph_info(LtkGlyphInfo *gi)
+{
+	free(gi->alphamap);
+	free(gi);
+}
+
+LtkGlyphInfo *
+ltk_get_glyph_info(LtkFont *font, unsigned int id, float scale, khash_t(glyphinfo) *cache)
+{
+	int ret;
+	khint_t k;
+	LtkGlyphInfo *glyph;
+	k = kh_get(glyphinfo, cache, id);
+	if (k == kh_end(cache)) {
+		glyph = ltk_create_glyph_info(font, id, scale);
+		/* FIXME: error checking with ret */
+		k = kh_put(glyphinfo, cache, id, &ret);
+		kh_value(cache, k) = glyph;
+	} else {
+		glyph = kh_value(cache, k);
+	}
+
+	return glyph;
+}
+
+khint_t
+ltk_create_glyph_cache(LtkTextManager *tm, uint16_t font_id, uint16_t font_size)
+{
+	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;
+
+	return k;
+}
+
+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)) {
+			ltk_destroy_glyph_info(kh_value(cache, k));
+		}
+	}
+	kh_destroy(glyphinfo, cache);
+}
+
+void
+ltk_load_default_font(LtkTextManager *tm, char *name)
+{
+	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);
+
+	FcPatternGetString (match, FC_FILE, 0, (FcChar8 **) &file);
+	/* FIXME: Why is index never used? This is the index within the font file,
+	   so it might be important, although I'm not sure if stb_truetype even
+	   supports it */
+	FcPatternGetInteger (match, FC_INDEX, 0, &index);
+
+	tm->default_font = ltk_get_font(tm, file);
+
+	FcPatternDestroy (match);
+}
+
+LtkFont *
+ltk_create_font(char *path, uint16_t id)
+{
+	long len;
+	LtkFont *font = malloc(sizeof(LtkFont));
+	if (!font) {
+		(void)fprintf(stderr, "Out of memory!\n");
+		exit(1);
+	}
+	char *contents = ltk_read_file(path, &len);
+	if (!stbtt_InitFont(&font->info, contents, 0))
+	{
+		(void)fprintf(stderr, "Failed to load font %s\n", path);
+		exit(1);
+	}
+	/* FIXME: make use of the destroy function (last argument to hb_blob_create - see hb-blob.cc in harfbuzz source) */
+	hb_blob_t *blob = hb_blob_create(contents, len, HB_MEMORY_MODE_READONLY, NULL, NULL);
+	hb_face_t *face = hb_face_create(blob, 0);
+	/* FIXME: need to use destroy function in order for the original file data to be freed? */
+	hb_blob_destroy(blob);
+	font->hb = hb_font_create(face);
+	hb_face_destroy(face);
+	hb_ot_font_set_funcs(font->hb);
+	font->id = id;
+	font->refs = 0;
+
+	return font;
+}
+
+void
+ltk_destroy_font(LtkFont *font)
+{
+	free(font->info.data);
+	hb_font_destroy(font->hb);
+	free(font);
+}
+
+uint16_t
+ltk_load_font(LtkTextManager *tm, char *path)
+{
+	LtkFont *font = ltk_create_font(path, tm->font_id_cur++);
+	int ret;
+	khint_t k;
+	/* FIXME: does kh_destroy also free these copied strings properly? */
+	char *key = strdup(path);
+	k = kh_put(fontid, tm->font_paths, key, &ret);
+	kh_value(tm->font_paths, k) = font->id;
+	k = kh_put(fontstruct, tm->font_cache, (khint_t) font->id, &ret);
+	kh_value(tm->font_cache, k) = font;
+	k = kh_get(fontid, tm->font_paths, path);
+
+	return font->id;
+}
+
+uint16_t
+ltk_get_font(LtkTextManager *tm, char *path)
+{
+	int ret;
+	khint_t k;
+	uint16_t id;
+	k = kh_get(fontid, tm->font_paths, path);
+	if (k == kh_end(tm->font_paths)) {
+		id = ltk_load_font(tm, path);
+	} else {
+		id = kh_value(tm->font_paths, k);
+	}
+
+	return id;
+}
+
+void
+ltk_destroy_glyph(LtkGlyph *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);
+}
+
+#if 0
+/* based on http://codemadness.org/git/dwm-font/file/drw.c.html#l315 */
+XImage *
+ltk_render_text_line(
+	LtkTextLine *tl,
+	Display *dpy,
+	Window window,
+	GC gc,
+	Colormap colormap,
+	XColor fg,
+	XColor bg)
+{
+	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);
+	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;
+		for (int j = 0; j < tl->w; j++) {
+			img->data[b++] = bg.blue / 257;
+			img->data[b++] = bg.green / 257;
+			img->data[b++] = bg.red / 257;
+			b++;
+		}
+	}
+
+	LtkTextSegment *ts = tl->start_segment;
+	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;
+		}
+	} while (ts = ts->next);
+
+	return img;
+}
+
+void
+ltk_render_text_segment(
+	LtkTextSegment *ts,
+	unsigned int start_x,
+	unsigned int start_y,
+	XImage *img,
+	XColor fg)
+{
+	LtkGlyph *glyph = ts->start_glyph;
+	int x_cur = start_x;
+	int y_cur = start_y;
+	int x, y;
+	double a;
+	int b;
+	do {
+		x = x_cur + glyph->info->xoff + glyph->x_offset;
+		y = y_cur + glyph->info->yoff - glyph->y_offset;
+		for (int i = 0; i < glyph->info->h; i++) {
+			for (int j = 0; j < glyph->info->w; j++) {
+				b = (y + i) * img->bytes_per_line + (x + j) * 4;
+				a = glyph->info->alphamap[i * glyph->info->w + j] / 255.0;
+				img->data[b] = (fg.blue * a + (1 - a) * (uint16_t)img->data[b] * 257) / 257;
+				img->data[b + 1] = (fg.green * a + (1 - a) * (uint16_t)img->data[b + 1] * 257) / 257;
+				img->data[b + 2] = (fg.red * a + (1 - a) * (uint16_t)img->data[b + 2] * 257) / 257;
+			}
+		}
+		x_cur += glyph->x_advance;
+		y_cur -= glyph->y_advance;
+	} while (glyph = glyph->next);
+}
+#endif
diff --git a/text-common.h b/text-common.h
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the Lumidify ToolKit (LTK)
+ * Copyright (c) 2017, 2018, 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 _TEXT_COMMON_H_
+#define _TEXT_COMMON_H_
+
+/*
+Requires the following includes:
+<X11/Xlib.h>, <X11/Xutil.h>, "stb_truetype.h",
+"khash.h", <harfbuzz/hb.h>, <fribidi.h>,
+<fontconfig/fontconfig.h>
+*/
+
+typedef struct {
+	stbtt_fontinfo info;
+	hb_font_t *hb;
+	uint16_t id;
+	unsigned int refs;
+} LtkFont;
+
+/* Contains general info on glyphs that doesn't change regardless of the context */
+typedef struct _LtkGlyphInfo {
+	unsigned int id;
+	unsigned char *alphamap;
+	unsigned int w;
+	unsigned int h;
+	unsigned int xoff; /* x offset from origin to top left corner of glyph */
+	unsigned int yoff; /* y offset from origin to top left corner of glyph */
+	unsigned int refs;
+	/* FIXME: does refs need to be long? It could cause problems if a
+	program tries to cache/"keep alive" a lot of pages of text. */
+} LtkGlyphInfo;
+
+/* Contains glyph info specific to one run of text */
+typedef struct _LtkGlyph {
+	LtkGlyphInfo *info;
+	int x_offset; /* additional x offset given by harfbuzz */
+	int y_offset; /* additional y offset given by harfbuzz */
+	int x_advance;
+	int y_advance;
+	int x_abs;
+	int y_abs;
+	uint32_t cluster; /* index of char in original text - from harfbuzz */
+	struct _LtkGlyph *next;
+} LtkGlyph;
+
+/* Hash definitions */
+/* glyph id -> glyph info struct */
+KHASH_MAP_INIT_INT(glyphinfo, LtkGlyphInfo*)
+/* font path, size -> glyph cache hash */
+KHASH_MAP_INIT_INT(glyphcache, khash_t(glyphinfo)*)
+/* font path -> font id */
+KHASH_MAP_INIT_STR(fontid, uint16_t)
+/* font id -> font struct */
+KHASH_MAP_INIT_INT(fontstruct, LtkFont*)
+
+typedef struct LtkTextManager {
+	khash_t(fontid) *font_paths;
+	khash_t(fontstruct) *font_cache;
+	khash_t(glyphcache) *glyph_cache;
+	FcPattern *fcpattern;
+	uint16_t default_font;
+	uint16_t font_id_cur;
+} LtkTextManager;
+
+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);
+
+LtkTextManager *ltk_init_text(char *font_name);
+
+void ltk_destroy_text_manager(LtkTextManager *tm);
+
+LtkGlyphInfo *ltk_create_glyph_info(LtkFont *font, unsigned int id, float scale);
+
+void ltk_destroy_glyph_info(LtkGlyphInfo *gi);
+
+LtkGlyphInfo *ltk_get_glyph_info(LtkFont *font, unsigned int id, float scale, khash_t(glyphinfo) *cache);
+
+khint_t ltk_create_glyph_cache(LtkTextManager *tm, uint16_t font_id, uint16_t font_size);
+
+void ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache);
+
+void ltk_load_default_font(LtkTextManager *tm, char *name);
+
+LtkFont *ltk_create_font(char *path, uint16_t id);
+
+void ltk_destroy_font(LtkFont *font);
+
+/* FIXME: need to figure out how exactly the whole font system is going to work, especially with default fonts, etc. */
+uint16_t ltk_load_font(LtkTextManager *tm, char *path);
+
+uint16_t ltk_get_font(LtkTextManager *tm, char *path);
+
+void ltk_destroy_glyph(LtkGlyph *glyph, khash_t(glyphinfo) *cache);
+
+/*
+XImage *ltk_render_text_line(LtkTextLine *tl, Display *dpy, Window window, GC gc, Colormap colormap, XColor fg, XColor bg);
+
+void ltk_render_text_segment(LtkTextSegment *ts, unsigned int start_x, unsigned int start_y, XImage *img, XColor fg);
+*/
+
+#endif /* _TEXT_COMMON_H_ */
diff --git a/text-hb.c b/text-hb.c
@@ -33,289 +33,12 @@
 #include <fribidi.h>
 #include <harfbuzz/hb.h>
 #include <harfbuzz/hb-ot.h>
+#include "text-common.h"
 #include "text-hb.h"
 #include "ltk.h"
 
 extern Ltk *ltk_global;
 
-/* These unicode routines are taken from
- * https://github.com/JeffBezanson/cutef8 */
-
-/* is c the start of a utf8 sequence? */
-#define isutf(c) (((c)&0xC0)!=0x80)
-
-static const uint32_t offsetsFromUTF8[6] = {
-    0x00000000UL, 0x00003080UL, 0x000E2080UL,
-    0x03C82080UL, 0xFA082080UL, 0x82082080UL
-};
-
-/* next character without NUL character terminator */
-uint32_t u8_nextmemchar(const char *s, size_t *i)
-{
-    uint32_t ch = 0;
-    size_t sz = 0;
-    do {
-        ch <<= 6;
-        ch += (unsigned char)s[(*i)++];
-        sz++;
-    } while (!isutf(s[*i]));
-    ch -= offsetsFromUTF8[sz-1];
-
-    return ch;
-}
-
-/* number of characters in NUL-terminated string */
-size_t u8_strlen(const char *s)
-{
-    size_t count = 0;
-    size_t i = 0, lasti;
-
-    while (1) {
-        lasti = i;
-        while (s[i] > 0)
-            i++;
-        count += (i-lasti);
-        if (s[i++]==0) break;
-        (void)(isutf(s[++i]) || isutf(s[++i]) || ++i);
-        count++;
-    }
-    return count;
-}
-
-size_t u8_wc_toutf8(char *dest, uint32_t ch)
-{
-    if (ch < 0x80) {
-        dest[0] = (char)ch;
-        return 1;
-    }
-    if (ch < 0x800) {
-        dest[0] = (ch>>6) | 0xC0;
-        dest[1] = (ch & 0x3F) | 0x80;
-        return 2;
-    }
-    if (ch < 0x10000) {
-        dest[0] = (ch>>12) | 0xE0;
-        dest[1] = ((ch>>6) & 0x3F) | 0x80;
-        dest[2] = (ch & 0x3F) | 0x80;
-        return 3;
-    }
-    if (ch < 0x110000) {
-        dest[0] = (ch>>18) | 0xF0;
-        dest[1] = ((ch>>12) & 0x3F) | 0x80;
-        dest[2] = ((ch>>6) & 0x3F) | 0x80;
-        dest[3] = (ch & 0x3F) | 0x80;
-        return 4;
-    }
-    return 0;
-}
-
-LtkTextManager *
-ltk_init_text(char *font_name)
-{
-	LtkTextManager *tm = malloc(sizeof(LtkTextManager));
-	if (!tm) {
-		(void)printf("Memory exhausted when trying to create text manager.");
-		exit(1);
-	}
-	tm->font_paths = kh_init(fontid);
-	tm->font_cache = kh_init(fontstruct);
-	tm->glyph_cache = kh_init(glyphcache);
-	tm->font_id_cur = 0;
-	ltk_load_default_font(tm, font_name);
-
-	return tm;
-}
-
-void
-ltk_destroy_text_manager(LtkTextManager *tm)
-{
-	int k;
-
-	kh_destroy(fontid, tm->font_paths);
-
-	for (k = kh_begin(tm->font_cache); k != kh_end(tm->font_cache); k++) {
-		if (kh_exist(tm->font_cache, k)) {
-			ltk_destroy_font(kh_value(tm->font_cache, k));
-		}
-	}
-	kh_destroy(fontstruct, tm->font_cache);
-
-	for (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);
-}
-
-LtkGlyphInfo *
-ltk_create_glyph_info(LtkFont *font, unsigned int id, float scale)
-{
-	LtkGlyphInfo *glyph = malloc(sizeof(LtkGlyphInfo));
-	if (!glyph) {
-		(void)printf("Out of memory!\n");
-		exit(1);
-	}
-	
-	glyph->id = id;
-	glyph->refs = 0;
-	glyph->alphamap = stbtt_GetGlyphBitmap(
-		&font->info, scale, scale, id, &glyph->w,
-		&glyph->h, &glyph->xoff, &glyph->yoff
-	);
-
-	return glyph;
-}
-
-void
-ltk_destroy_glyph_info(LtkGlyphInfo *gi)
-{
-	free(gi->alphamap);
-	free(gi);
-}
-
-LtkGlyphInfo *
-ltk_get_glyph_info(LtkFont *font, unsigned int id, float scale, khash_t(glyphinfo) *cache)
-{
-	int ret;
-	khint_t k;
-	LtkGlyphInfo *glyph;
-	k = kh_get(glyphinfo, cache, id);
-	if (k == kh_end(cache)) {
-		glyph = ltk_create_glyph_info(font, id, scale);
-		/* FIXME: error checking with ret */
-		k = kh_put(glyphinfo, cache, id, &ret);
-		kh_value(cache, k) = glyph;
-	} else {
-		glyph = kh_value(cache, k);
-	}
-
-	return glyph;
-}
-
-khint_t
-ltk_create_glyph_cache(LtkTextManager *tm, uint16_t font_id, uint16_t font_size)
-{
-	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;
-
-	return k;
-}
-
-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)) {
-			ltk_destroy_glyph_info(kh_value(cache, k));
-		}
-	}
-	kh_destroy(glyphinfo, cache);
-}
-
-void
-ltk_load_default_font(LtkTextManager *tm, char *name)
-{
-	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);
-
-	FcPatternGetString (match, FC_FILE, 0, (FcChar8 **) &file);
-	/* FIXME: Why is index never used? This is the index within the font file,
-	   so it might be important, although I'm not sure if stb_truetype even
-	   supports it */
-	FcPatternGetInteger (match, FC_INDEX, 0, &index);
-
-	tm->default_font = ltk_get_font(tm, file);
-
-	FcPatternDestroy (match);
-}
-
-LtkFont *
-ltk_create_font(char *path, uint16_t id)
-{
-	long len;
-	LtkFont *font = malloc(sizeof(LtkFont));
-	if (!font) {
-		(void)fprintf(stderr, "Out of memory!\n");
-		exit(1);
-	}
-	char *contents = ltk_read_file(path, &len);
-	if (!stbtt_InitFont(&font->info, contents, 0))
-	{
-		(void)fprintf(stderr, "Failed to load font %s\n", path);
-		exit(1);
-	}
-	/* FIXME: make use of the destroy function (last argument to hb_blob_create - see hb-blob.cc in harfbuzz source) */
-	hb_blob_t *blob = hb_blob_create(contents, len, HB_MEMORY_MODE_READONLY, NULL, NULL);
-	hb_face_t *face = hb_face_create(blob, 0);
-	/* FIXME: need to use destroy function in order for the original file data to be freed? */
-	hb_blob_destroy(blob);
-	font->hb = hb_font_create(face);
-	hb_face_destroy(face);
-	hb_ot_font_set_funcs(font->hb);
-	font->id = id;
-	font->refs = 0;
-
-	return font;
-}
-
-void
-ltk_destroy_font(LtkFont *font)
-{
-	free(font->info.data);
-	hb_font_destroy(font->hb);
-	free(font);
-}
-
-uint16_t
-ltk_load_font(LtkTextManager *tm, char *path)
-{
-	LtkFont *font = ltk_create_font(path, tm->font_id_cur++);
-	int ret;
-	khint_t k;
-	/* FIXME: does kh_destroy also free these copied strings properly? */
-	char *key = strdup(path);
-	k = kh_put(fontid, tm->font_paths, key, &ret);
-	kh_value(tm->font_paths, k) = font->id;
-	k = kh_put(fontstruct, tm->font_cache, (khint_t) font->id, &ret);
-	kh_value(tm->font_cache, k) = font;
-	k = kh_get(fontid, tm->font_paths, path);
-
-	return font->id;
-}
-
-uint16_t
-ltk_get_font(LtkTextManager *tm, char *path)
-{
-	int ret;
-	khint_t k;
-	uint16_t id;
-	k = kh_get(fontid, tm->font_paths, path);
-	if (k == kh_end(tm->font_paths)) {
-		id = ltk_load_font(tm, path);
-	} else {
-		id = kh_value(tm->font_paths, k);
-	}
-
-	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 *
@@ -586,18 +309,6 @@ ltk_create_text_segment(LtkTextManager *tm, uint32_t *text, unsigned int len, ui
 }
 
 void
-ltk_destroy_glyph(LtkGlyph *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_destroy_text_segment(LtkTextSegment *ts)
 {
 	LtkGlyph *glyph, *next_glyph;
diff --git a/text-hb.h b/text-hb.h
@@ -28,42 +28,9 @@
 Requires the following includes:
 <X11/Xlib.h>, <X11/Xutil.h>, "stb_truetype.h",
 "khash.h", <harfbuzz/hb.h>, <fribidi.h>,
-<fontconfig/fontconfig.h>
+<fontconfig/fontconfig.h>, "text-common.h"
 */
 
-typedef struct {
-	stbtt_fontinfo info;
-	hb_font_t *hb;
-	uint16_t id;
-	unsigned int refs;
-} LtkFont;
-
-/* Contains general info on glyphs that doesn't change regardless of the context */
-typedef struct _LtkGlyphInfo {
-	unsigned int id;
-	unsigned char *alphamap;
-	unsigned int w;
-	unsigned int h;
-	unsigned int xoff; /* x offset from origin to top left corner of glyph */
-	unsigned int yoff; /* y offset from origin to top left corner of glyph */
-	unsigned int refs;
-	/* FIXME: does refs need to be long? It could cause problems if a
-	program tries to cache/"keep alive" a lot of pages of text. */
-} LtkGlyphInfo;
-
-/* Contains glyph info specific to one run of text */
-typedef struct _LtkGlyph {
-	LtkGlyphInfo *info;
-	int x_offset; /* additional x offset given by harfbuzz */
-	int y_offset; /* additional y offset given by harfbuzz */
-	int x_advance;
-	int y_advance;
-	int x_abs;
-	int y_abs;
-	uint32_t cluster; /* index of char in original text - from harfbuzz */
-	struct _LtkGlyph *next;
-} LtkGlyph;
-
 /* Single segment of text with same font */
 typedef struct LtkTextSegment {
 	uint16_t font_id;
@@ -94,50 +61,6 @@ typedef struct {
 	LtkTextSegment *start_segment;
 } LtkTextLine;
 
-/* Hash definitions */
-/* glyph id -> glyph info struct */
-KHASH_MAP_INIT_INT(glyphinfo, LtkGlyphInfo*)
-/* font path, size -> glyph cache hash */
-KHASH_MAP_INIT_INT(glyphcache, khash_t(glyphinfo)*)
-/* font path -> font id */
-KHASH_MAP_INIT_STR(fontid, uint16_t)
-/* font id -> font struct */
-KHASH_MAP_INIT_INT(fontstruct, LtkFont*)
-
-typedef struct LtkTextManager {
-	khash_t(fontid) *font_paths;
-	khash_t(fontstruct) *font_cache;
-	khash_t(glyphcache) *glyph_cache;
-	FcPattern *fcpattern;
-	uint16_t default_font;
-	uint16_t font_id_cur;
-} LtkTextManager;
-
-LtkTextManager *ltk_init_text(char *font_name);
-
-void ltk_destroy_text_manager(LtkTextManager *tm);
-
-LtkGlyphInfo *ltk_create_glyph_info(LtkFont *font, unsigned int id, float scale);
-
-void ltk_destroy_glyph_info(LtkGlyphInfo *gi);
-
-LtkGlyphInfo *ltk_get_glyph_info(LtkFont *font, unsigned int id, float scale, khash_t(glyphinfo) *cache);
-
-khint_t ltk_create_glyph_cache(LtkTextManager *tm, uint16_t font_id, uint16_t font_size);
-
-void ltk_destroy_glyph_cache(khash_t(glyphinfo) *cache);
-
-void ltk_load_default_font(LtkTextManager *tm, char *name);
-
-LtkFont *ltk_create_font(char *path, uint16_t id);
-
-void ltk_destroy_font(LtkFont *font);
-
-/* FIXME: need to figure out how exactly the whole font system is going to work, especially with default fonts, etc. */
-uint16_t ltk_load_font(LtkTextManager *tm, char *path);
-
-uint16_t ltk_get_font(LtkTextManager *tm, char *path);
-
 /* TODO: different sizes, colors, styles, etc. */
 LtkTextLine *ltk_create_text_line(LtkTextManager *tm, char *text, uint16_t fontid, uint16_t size);
 
@@ -145,8 +68,6 @@ LtkTextLine *ltk_create_text_line(LtkTextManager *tm, char *text, uint16_t fonti
    -> in case I want to get rid of uint_16_t, etc. */
 LtkTextSegment *ltk_create_text_segment(LtkTextManager *tm, uint32_t *text, unsigned int text_len, uint16_t fontid, uint16_t size, hb_script_t script);
 
-void ltk_destroy_glyph(LtkGlyph *glyph, khash_t(glyphinfo) *cache);
-
 void ltk_destroy_text_segment(LtkTextSegment *ts);
 
 XImage *ltk_render_text_line(LtkTextLine *tl, Display *dpy, Window window, GC gc, Colormap colormap, XColor fg, XColor bg);
@@ -154,4 +75,4 @@ XImage *ltk_render_text_line(LtkTextLine *tl, Display *dpy, Window window, GC gc
 void ltk_render_text_segment(LtkTextSegment *ts, unsigned int start_x, unsigned int start_y, XImage *img, XColor fg);
 
 
-#endif
+#endif /* _TEXT_HB_H_ */