URI: 
       tMove common text functions to text-common.* - ltkx - GUI toolkit for X11 (WIP)
  HTML git clone git://lumidify.org/ltkx.git
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit f344c3f28da7995f19ec0549d90f275d3fd1715a
   DIR parent 57d85ccfe4c9ac3de63dab6979e65dbe0696f4b7
  HTML 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(-)
       ---
   DIR diff --git a/Makefile b/Makefile
       t@@ -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)
       t@@ -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
   DIR diff --git a/button.c b/button.c
       t@@ -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"
        
   DIR diff --git a/gap_buffer.h b/gap_buffer.h
       t@@ -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;                                                        \
       t@@ -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 =                                        \
   DIR diff --git a/ltk.c b/ltk.c
       t@@ -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;
   DIR diff --git a/ltkx.h b/ltkx.h
       t@@ -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"
   DIR diff --git a/text-common.c b/text-common.c
       t@@ -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
   DIR diff --git a/text-common.h b/text-common.h
       t@@ -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_ */
   DIR diff --git a/text-hb.c b/text-hb.c
       t@@ -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 *
       t@@ -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;
   DIR diff --git a/text-hb.h b/text-hb.h
       t@@ -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;
       t@@ -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);
        
       t@@ -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);
       t@@ -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_ */