From 2c2e0188f7dc29946483b83d088e4f35c3a9069c Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Mon, 10 Apr 2023 21:44:33 +0200 Subject: add font rendering --- drw.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 157 insertions(+), 47 deletions(-) (limited to 'drw.c') diff --git a/drw.c b/drw.c index f65f330..dc220dc 100644 --- a/drw.c +++ b/drw.c @@ -1,6 +1,9 @@ +#include #include #include #include +#include +#include #include #include "drw.h" @@ -10,6 +13,10 @@ static Color to_color(uint32_t color); static uint32_t to_uint32_t(Color color); static void draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t color); +static void init_font(Font *font); +static FontFamily *create_font_family(FontPath fontpath); +static void free_font_family(FontFamily *fontfamily); +static Font *get_font_with_charcode(FontCache *fontcache, uint_least32_t charcode); Color @@ -112,40 +119,114 @@ draw_rect(Canvas *canvas, unsigned x, unsigned y, unsigned width, unsigned heigh } } -Font * -create_font(const char *fontpath, unsigned size) + +FontCache * +create_font_cache(FontPath *fontpath, int size, unsigned fontsize) { - FT_Error error; - Font * font; + FontCache *fontcache = malloc(sizeof(FontCache)); + FontCacheElement *current; + Font *font; + int i; + + fontcache->fontsize = fontsize; + fontcache->fonttype = FONT_NORMAL; + + if (size == 0) { + die("fontcache has to contain at least one font"); + } - font = malloc(sizeof(Font)); + fontcache->first = malloc(sizeof(FontCacheElement)); + current = fontcache->first; + current->family = create_font_family(fontpath[0]); + current->next = 0; + + for (i = 1; i < size; ++i) { + current->next = malloc(sizeof(FontCacheElement)); + current = current->next; + current->family = create_font_family(fontpath[i]); + current->next = 0; + } + + font_cache_generate_box(fontcache); + + return fontcache; +} + +void +font_cache_generate_box(FontCache *fontcache) +{ + Font *font = get_font_with_charcode(fontcache, 0); + FT_Set_Pixel_Sizes(font->face, 0, fontcache->fontsize); + fprintf(stderr, "fontsize: %i\n", fontcache->fontsize); + fontcache->box.width = (font->face->bbox.xMax - font->face->bbox.xMin) >> 6; + fontcache->box.height = (font->face->size->metrics.height) >> 6; + fprintf(stderr, "width: %i, height: %i\n", fontcache->box.width, fontcache->box.height); +} + + +void +free_font_cache(FontCache *fontcache) +{ + FontCacheElement *current = fontcache->first; + FontCacheElement *next; + + for (; current; current = next) { + next = current->next; + free_font_family(current->family); + free(current); + } + + free(fontcache); +} + + +FontFamily * +create_font_family(FontPath fontpath) +{ + int i; + FontFamily *fontfamily = malloc(sizeof(FontFamily)); + + for (i = 0; i < FONT_TYPE_SIZE; ++i) { + if (fontpath[i]) { + (*fontfamily)[i].path = fontpath[i]; + (*fontfamily)[i].loaded = 0; + } + } + + return fontfamily; +} + + +void +free_font_family(FontFamily *fontfamily) +{ + int i; + for (i = 0; i < FONT_TYPE_SIZE; ++i) { + if ((*fontfamily)[i].loaded) { + FT_Done_Face((*fontfamily)[i].face); + FT_Done_FreeType((*fontfamily)[i].library); + } + } +} + + +void +init_font(Font *font) +{ + FT_Error error; error = FT_Init_FreeType(&font->library); if (error) die("cannot init library"); - error = FT_New_Face(font->library, fontpath, 0, &font->face); + error = FT_New_Face(font->library, font->path, 0, &font->face); if (error) die("cannot open face"); - error = FT_Set_Pixel_Sizes(font->face, 0, size); - if (error) - die("cannot set char size"); - error = FT_Select_Charmap(font->face, ft_encoding_unicode); if (error) die("cannot set unicode"); - - return font; -} - -void -free_font(Font *font) -{ - FT_Done_Face(font->face); - FT_Done_FreeType(font->library); - free(font); } @@ -196,69 +277,98 @@ draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t } } +Font * +get_font_with_charcode(FontCache *fontcache, uint_least32_t charcode) +{ + FT_UInt glyph_index; + FontCacheElement *element = fontcache->first; + Font *font; + + for (; element; element = element->next) { + font = &(*element->family)[fontcache->fonttype]; + if (!font->loaded) { + init_font(font); + font->loaded = 1; + } + + glyph_index = FT_Get_Char_Index(font->face, charcode); + + if (glyph_index) + return font; + } + + font = fontcache->first->family[fontcache->fonttype]; + init_font(font); + font->loaded = 1; + return font; +} + unsigned -draw_font(Canvas *canvas, Font *font, const char *text, unsigned x, unsigned y, uint32_t color) +draw_char(Canvas *canvas, FontCache *fontcache, uint_least32_t charcode, unsigned x, unsigned y, uint32_t color) { FT_GlyphSlot slot; FT_Error error; FT_UInt glyph_index; FT_UInt previous = 0; - uint_least32_t charcode; - FT_Bool has_kerning = FT_HAS_KERNING(font->face); + FT_Bool has_kerning; FT_Vector delta; + Font *current_font; - slot = font->face->glyph; - - for (; *text;) { - text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode); + current_font = get_font_with_charcode(fontcache, charcode); + FT_Set_Pixel_Sizes(current_font->face, 0, fontcache->fontsize); - glyph_index = FT_Get_Char_Index(font->face, charcode); + slot = current_font->face->glyph; + glyph_index = FT_Get_Char_Index(current_font->face, charcode); - if (has_kerning && previous && glyph_index) { - FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); - x += delta.x >> 6; - } + has_kerning = FT_HAS_KERNING(current_font->face); + if (has_kerning && previous && glyph_index) { + FT_Get_Kerning(current_font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); + x += delta.x >> 6; + } - error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); - if (error) { - fprintf(stderr, "warning: char not loaded, skipping...\n"); - continue; - } + error = FT_Load_Glyph(current_font->face, glyph_index, FT_LOAD_RENDER); + if (error) { + fprintf(stderr, "warning: char not loaded, skipping...\n"); + return x; + } - draw_bitmap(canvas, &slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, color); + draw_bitmap(canvas, &slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, color); - x += slot->advance.x >> 6; - } + x += slot->advance.x >> 6; return x; } unsigned -font_width(Font *font, const char *text) +font_width(FontCache *fontcache, const char *text) { FT_GlyphSlot slot; FT_Error error; FT_UInt glyph_index; FT_UInt previous = 0; uint_least32_t charcode; - FT_Bool has_kerning = FT_HAS_KERNING(font->face); + FT_Bool has_kerning; FT_Vector delta; unsigned x = 0; - - slot = font->face->glyph; + Font *current_font; for (; *text;) { text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode); - glyph_index = FT_Get_Char_Index(font->face, charcode); + current_font = get_font_with_charcode(fontcache, charcode); + FT_Set_Pixel_Sizes(current_font->face, 0, fontcache->fontsize); + + slot = current_font->face->glyph; + glyph_index = FT_Get_Char_Index(current_font->face, charcode); + has_kerning = FT_HAS_KERNING(current_font->face); if (has_kerning && previous && glyph_index) { - FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); + FT_Get_Kerning(current_font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); x += delta.x >> 6; } - error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER); + error = FT_Load_Glyph(current_font->face, glyph_index, FT_LOAD_RENDER); if (error) { fprintf(stderr, "warning: char not loaded, skipping...\n"); continue; -- cgit v1.2.3-70-g09d2