aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2023-04-10 21:44:33 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2023-04-10 21:44:33 +0200
commit2c2e0188f7dc29946483b83d088e4f35c3a9069c (patch)
tree5f6c72677ea972bbaaafff06317526432bba611a
parentc301a55b88a131f081a844552327c0ab85db017c (diff)
add font rendering
-rw-r--r--config.h19
-rw-r--r--drw.c204
-rw-r--r--drw.h38
-rw-r--r--swt.c77
4 files changed, 269 insertions, 69 deletions
diff --git a/config.h b/config.h
index ec469be..d279ed3 100644
--- a/config.h
+++ b/config.h
@@ -1,12 +1,27 @@
/* See LICENSE file for copyright and license details. */
+#include "drw.h"
+
/*
* appearance
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
-static char *font = "/usr/share/fonts/TTF/Sauce Code Pro Bold Nerd Font Complete.ttf";
-static int fontsize = 12;
+static FontPath fonts[] = {
+ {
+ "/usr/share/fonts/TTF/Sauce Code Pro Nerd Font Complete.ttf", /* Normal */
+ "/usr/share/fonts/TTF/Sauce Code Pro Italic Nerd Font Complete.ttf", /* Italic */
+ "/usr/share/fonts/TTF/Sauce Code Pro Bold Nerd Font Complete.ttf", /* Bold */
+ "/usr/share/fonts/TTF/Sauce Code Pro Bold Italic Nerd Font Complete.ttf", /* Bold-Italic */
+ },
+ {
+ "/usr/share/fonts/gnu-free/FreeMono.otf", /* Normal */
+ "/usr/share/fonts/gnu-free/FreeMonoOblique.otf", /* Italic */
+ "/usr/share/fonts/gnu-free/FreeMonoBold.otf", /* Bold */
+ "/usr/share/fonts/gnu-free/FreeMonoBoldOblique.otf" /* Bold-Italic */
+ },
+};
+static int fontsize = 32;
static int borderpx = 2;
/*
diff --git a/drw.c b/drw.c
index f65f330..dc220dc 100644
--- a/drw.c
+++ b/drw.c
@@ -1,6 +1,9 @@
+#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <math.h>
+#include <memory.h>
+#include <stdlib.h>
#include <grapheme.h>
#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");
+ }
+
+ 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;
- font = malloc(sizeof(Font));
+ 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;
diff --git a/drw.h b/drw.h
index 84bec3b..578fd2a 100644
--- a/drw.h
+++ b/drw.h
@@ -18,10 +18,39 @@ typedef struct {
} Canvas;
typedef struct {
+ const char *path;
+ int loaded;
FT_Library library;
FT_Face face;
} Font;
+enum FontType {
+ FONT_NORMAL,
+ FONT_ITALIC,
+ FONT_BOLD,
+ FONT_BOLD_ITALIC,
+ FONT_TYPE_SIZE
+};
+
+typedef Font FontFamily[FONT_TYPE_SIZE];
+typedef char *FontPath[FONT_TYPE_SIZE];
+
+struct FontCacheElement_;
+typedef struct FontCacheElement_ {
+ FontFamily *family;
+ struct FontCacheElement_ *next;
+} FontCacheElement;
+
+typedef struct {
+ FontCacheElement *first;
+ unsigned fontsize;
+ unsigned fonttype;
+ struct {
+ unsigned width;
+ unsigned height;
+ } box;
+} FontCache;
+
typedef struct {
uint8_t r;
uint8_t g;
@@ -36,9 +65,10 @@ void free_drw(Canvas *canvas);
void draw_rect(Canvas *canvas, unsigned x, unsigned y, unsigned width, unsigned height, uint32_t color);
void draw_point(Canvas *canvas, unsigned x, unsigned y, uint32_t color);
-Font* create_font(const char *fontpath, unsigned size);
-void free_font(Font *font);
-unsigned draw_font(Canvas *canvas, Font *font, const char *text, unsigned x, unsigned y, uint32_t color);
-unsigned font_width(Font *font, const char *text);
+FontCache *create_font_cache(FontPath *fontpath, int size, unsigned fontsize);
+void font_cache_generate_box(FontCache *fontcache);
+void free_font_cache(FontCache *fontcache);
+unsigned draw_char(Canvas *canvas, FontCache *fontcache, uint_least32_t charcode, unsigned x, unsigned y, uint32_t color);
+unsigned font_width(FontCache *fontcache, const char *text);
#endif
diff --git a/swt.c b/swt.c
index 4dff47c..860a85e 100644
--- a/swt.c
+++ b/swt.c
@@ -34,18 +34,15 @@ char *argv0;
typedef struct {
unsigned width;
unsigned height;
+ int geometry_changed;
struct {
struct wl_surface *wl;
struct xdg_surface *xdg;
struct xdg_toplevel *toplevel;
} surface;
Canvas *canvas;
- Font *font;
+ FontCache *fontcache;
int mode;
- struct {
- int x;
- int y;
- } cursor;
} Window;
@@ -156,10 +153,31 @@ void wclipcopy() {
void wdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) {
fprintf(stderr, "DRAW CURSOR: cx: %i, cy: %i, ox: %i, oy: %i\n", cx, cy, ox, oy);
- draw_rect(win.canvas, win.cursor.x * fontsize, win.cursor.y * fontsize, fontsize, fontsize, 0x0);
- draw_rect(win.canvas, cx * fontsize, cy * fontsize, fontsize, fontsize, 0xffffffff);
- win.cursor.x = cx;
- win.cursor.y = cy;
+
+ draw_rect(
+ win.canvas,
+ ox * win.fontcache->box.width,
+ oy * win.fontcache->box.height,
+ win.fontcache->box.width,
+ win.fontcache->box.height,
+ 0x0
+ );
+ draw_char(
+ win.canvas,
+ win.fontcache,
+ og.u,
+ ox * win.fontcache->box.width,
+ oy * win.fontcache->box.height + win.fontcache->fontsize,
+ 0xffffffff
+ );
+ draw_rect(
+ win.canvas,
+ cx * win.fontcache->box.width,
+ cy * win.fontcache->box.height,
+ win.fontcache->box.width,
+ win.fontcache->box.height,
+ 0xffffffff
+ );
}
@@ -167,9 +185,26 @@ void wdrawline(Line line, int x1, int y1, int x2) {
int x;
fprintf(stderr, "DRAW LINE: x1: %i, y1: %i, x2: %i\n");
- /*for (x = x1; x < x2; x++) {
- fprintf(stderr, " line: %s\n", line[x]);
- }*/
+ draw_rect(
+ win.canvas,
+ x1 * win.fontcache->box.width,
+ y1 * win.fontcache->box.height,
+ (x2 - x1) * win.fontcache->box.width,
+ win.fontcache->box.height,
+ 0
+ );
+
+ fprintf(stderr, " line: ");
+ for (x = x1; x < x2; x++) {
+ draw_char(
+ win.canvas,
+ win.fontcache,
+ line[x].u,
+ x * win.fontcache->box.width,
+ y1 * win.fontcache->box.height + win.fontcache->fontsize,
+ 0xffffffff
+ );
+ }
}
@@ -262,14 +297,20 @@ commit_surface()
void
surface_configure(void *data, struct xdg_surface *surface, uint32_t serial)
{
+ int first_canvas = win.canvas == 0;
xdg_surface_ack_configure(surface, serial);
- if (win.canvas != 0) {
- free_drw(win.canvas);
+ if (win.geometry_changed || first_canvas) {
+ if (win.canvas != 0) {
+ free_drw(win.canvas);
+ }
+ win.canvas = create_drw(client.shm, win.width, win.height);
+ draw();
+ win.geometry_changed = 0;
}
- win.canvas = create_drw(client.shm, win.width, win.height);
- draw_frame();
+ if (first_canvas)
+ draw_frame();
commit_surface();
}
@@ -277,6 +318,9 @@ surface_configure(void *data, struct xdg_surface *surface, uint32_t serial)
void
toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *clients)
{
+ if (width != win.width && height != win.height)
+ win.geometry_changed = 1;
+
if (width == 0 || height == 0) {
win.width = 800;
win.height = 600;
@@ -471,6 +515,7 @@ pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axi
void
setup()
{
+ win.fontcache = create_font_cache(fonts, sizeof(fonts) / sizeof(FontPath), fontsize);
client.kb.repeat.timer = timerfd_create(CLOCK_MONOTONIC, 0);
client.kb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
client.display = wl_display_connect(0);