diff --git a/Makefile b/Makefile index c6da6e3..17cc90b 100644 --- a/Makefile +++ b/Makefile @@ -200,6 +200,15 @@ $(ISO_IMAGE): $(KERNEL_ELF) limine.conf limine-setup fi \ done + mkdir -p $(ISO_DIR)/Library/Fonts/Emoji + @for f in $(SRC_DIR)/fonts/Emoji/*.ttf; do \ + if [ -f "$$f" ]; then \ + basename=$$(basename "$$f"); \ + cp "$$f" $(ISO_DIR)/Library/Fonts/Emoji/; \ + echo " module_path: boot():/Library/Fonts/Emoji/$$basename" >> $(ISO_DIR)/limine.conf; \ + fi \ + done + @if [ -f README.md ]; then \ cp README.md $(ISO_DIR)/; \ echo " module_path: boot():/README.md" >> $(ISO_DIR)/limine.conf; \ diff --git a/src/fonts/Emoji/NotoEmoji-VariableFont_wght.ttf b/src/fonts/Emoji/NotoEmoji-VariableFont_wght.ttf new file mode 100644 index 0000000..4c7d78e Binary files /dev/null and b/src/fonts/Emoji/NotoEmoji-VariableFont_wght.ttf differ diff --git a/src/sys/syscall.c b/src/sys/syscall.c index f0208ea..e5cca93 100644 --- a/src/sys/syscall.c +++ b/src/sys/syscall.c @@ -371,10 +371,9 @@ static uint64_t syscall_handler_inner(registers_t *regs) { int cur_x = ux; const char *s = kernel_str; while (*s) { - font_manager_render_char_scaled(font, cur_x, baseline, *s, color, font->pixel_height, put_pixel); - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(font, buf, font->pixel_height); - s++; + uint32_t codepoint = utf8_decode(&s); + font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, font->pixel_height, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, font->pixel_height); } } else { draw_string(ux, uy, kernel_str, color); @@ -387,10 +386,9 @@ static uint64_t syscall_handler_inner(registers_t *regs) { int cur_x = win->x + ux; const char *s = kernel_str; while (*s) { - font_manager_render_char_scaled(font, cur_x, baseline, *s, color, font->pixel_height, put_pixel); - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(font, buf, font->pixel_height); - s++; + uint32_t codepoint = utf8_decode(&s); + font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, font->pixel_height, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, font->pixel_height); } } else { draw_string(win->x + ux, win->y + uy, kernel_str, color); @@ -471,10 +469,9 @@ static uint64_t syscall_handler_inner(registers_t *regs) { int cur_x = ux; const char *s = kernel_str; while (*s) { - font_manager_render_char_scaled(font, cur_x, baseline, *s, color, scale, put_pixel); - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(font, buf, scale); - s++; + uint32_t codepoint = utf8_decode(&s); + font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, scale, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } else { draw_string_scaled(ux, uy, kernel_str, color, scale); @@ -487,10 +484,9 @@ static uint64_t syscall_handler_inner(registers_t *regs) { int cur_x = win->x + ux; const char *s = kernel_str; while (*s) { - font_manager_render_char_scaled(font, cur_x, baseline, *s, color, scale, put_pixel); - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(font, buf, scale); - s++; + uint32_t codepoint = utf8_decode(&s); + font_manager_render_char_scaled(font, cur_x, baseline, codepoint, color, scale, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } else { draw_string_scaled(win->x + ux, win->y + uy, kernel_str, color, scale); @@ -546,11 +542,10 @@ static uint64_t syscall_handler_inner(registers_t *regs) { int cur_x = ux; const char *s = kernel_str; while (*s) { - extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); - font_manager_render_char_sloped(font, cur_x, baseline, *s, color, scale, slope, put_pixel); - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(font, buf, scale); - s++; + extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); + uint32_t codepoint = utf8_decode(&s); + font_manager_render_char_sloped(font, cur_x, baseline, codepoint, color, scale, slope, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } else { draw_string_scaled_sloped(ux, uy, kernel_str, color, scale, slope); @@ -563,11 +558,10 @@ static uint64_t syscall_handler_inner(registers_t *regs) { int cur_x = win->x + ux; const char *s = kernel_str; while (*s) { - extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); - font_manager_render_char_sloped(font, cur_x, baseline, *s, color, scale, slope, put_pixel); - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(font, buf, scale); - s++; + extern void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); + uint32_t codepoint = utf8_decode(&s); + font_manager_render_char_sloped(font, cur_x, baseline, codepoint, color, scale, slope, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(font, codepoint, scale); } } else { draw_string_scaled_sloped(win->x + ux, win->y + uy, kernel_str, color, scale, slope); diff --git a/src/wm/font_manager.c b/src/wm/font_manager.c index e7fab66..0a2a5a4 100644 --- a/src/wm/font_manager.c +++ b/src/wm/font_manager.c @@ -54,6 +54,11 @@ static inline uint32_t alpha_blend(uint32_t bg, uint32_t fg, uint8_t alpha) { } static ttf_font_t *default_font = NULL; +static ttf_font_t *fallback_font = NULL; + +void font_manager_set_fallback_font(ttf_font_t *font) { + fallback_font = font; +} #define MAX_LOADED_FONTS 8 typedef struct { @@ -149,13 +154,49 @@ ttf_font_t* font_manager_load(const char *path, float size) { return font; } -void font_manager_render_char(ttf_font_t *font, int x, int y, char c, uint32_t color, void (*put_pixel_fn)(int, int, uint32_t)) { - if (!font) font = default_font; - if (!font) return; - font_manager_render_char_scaled(font, x, y, c, color, font->pixel_height, put_pixel_fn); +uint32_t utf8_decode(const char **s) { + const unsigned char *u = (const unsigned char *)*s; + if (!*u) return 0; + + if (u[0] < 0x80) { + *s = (const char *)(u + 1); + return u[0]; + } + + if ((u[0] & 0xE0) == 0xC0 && (u[1] & 0xC0) == 0x80) { + *s = (const char *)(u + 2); + return ((u[0] & 0x1F) << 6) | (u[1] & 0x3F); + } + + if ((u[0] & 0xF0) == 0xE0 && (u[1] & 0xC0) == 0x80 && (u[2] & 0xC0) == 0x80) { + *s = (const char *)(u + 3); + return ((u[0] & 0x0F) << 12) | ((u[1] & 0x3F) << 6) | (u[2] & 0x3F); + } + + if ((u[0] & 0xF8) == 0xF0 && (u[1] & 0xC0) == 0x80 && (u[2] & 0xC0) == 0x80 && (u[3] & 0xC0) == 0x80) { + *s = (const char *)(u + 4); + return ((u[0] & 0x07) << 18) | ((u[1] & 0x3F) << 12) | ((u[2] & 0x3F) << 6) | (u[3] & 0x3F); + } + + uint32_t codepoint = u[0]; + *s = (const char *)(u + 1); + if (codepoint == 128) return 0x2014; + if (codepoint == 129) return 0x2013; + if (codepoint == 130) return 0x2022; + if (codepoint == 131) return 0x2026; + if (codepoint == 132) return 0x2122; + if (codepoint == 133) return 0x20AC; + if (codepoint == 134) return 0x00B7; + return codepoint; } -void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, void (*put_pixel_fn)(int, int, uint32_t)) { +void font_manager_render_char(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, void (*put_pixel_fn)(int, int, uint32_t)) { + if (!font) font = default_font; + if (!font) return; + font_manager_render_char_scaled(font, x, y, codepoint, color, font->pixel_height, put_pixel_fn); +} + +void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, void (*put_pixel_fn)(int, int, uint32_t)) { if (!font) font = default_font; if (!font) return; @@ -166,15 +207,11 @@ void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, char c, uin float real_scale = stbtt_ScaleForPixelHeight(info, scale); - int codepoint = (unsigned char)c; - if (codepoint == 128) codepoint = 0x2014; - if (codepoint == 129) codepoint = 0x2013; - if (codepoint == 130) codepoint = 0x2022; - if (codepoint == 131) codepoint = 0x2026; - if (codepoint == 132) codepoint = 0x2122; - if (codepoint == 133) codepoint = 0x20AC; - if (codepoint == 134) codepoint = 0x00B7; - + if (stbtt_FindGlyphIndex(info, codepoint) == 0 && fallback_font) { + info = (stbtt_fontinfo *)fallback_font->info; + real_scale = stbtt_ScaleForPixelHeight(info, scale); + } + bitmap = stbtt_GetCodepointBitmap(info, 0, real_scale, codepoint, &w, &h, &xoff, &yoff); if (bitmap) { @@ -193,7 +230,7 @@ void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, char c, uin } } -void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)) { +void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)) { if (!font) font = default_font; if (!font) return; @@ -204,15 +241,11 @@ void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uin float real_scale = stbtt_ScaleForPixelHeight(info, scale); - int codepoint = (unsigned char)c; - if (codepoint == 128) codepoint = 0x2014; - if (codepoint == 129) codepoint = 0x2013; - if (codepoint == 130) codepoint = 0x2022; - if (codepoint == 131) codepoint = 0x2026; - if (codepoint == 132) codepoint = 0x2122; - if (codepoint == 133) codepoint = 0x20AC; - if (codepoint == 134) codepoint = 0x00B7; - + if (stbtt_FindGlyphIndex(info, codepoint) == 0 && fallback_font) { + info = (stbtt_fontinfo *)fallback_font->info; + real_scale = stbtt_ScaleForPixelHeight(info, scale); + } + bitmap = stbtt_GetCodepointBitmap(info, 0, real_scale, codepoint, &w, &h, &xoff, &yoff); if (bitmap) { @@ -269,17 +302,33 @@ int font_manager_get_string_width_scaled(ttf_font_t *font, const char *s, float int width = 0; while (*s) { int advance, lsb; - int codepoint = (unsigned char)*s; - if (codepoint == 128) codepoint = 0x2014; - if (codepoint == 129) codepoint = 0x2013; - if (codepoint == 130) codepoint = 0x2022; - if (codepoint == 131) codepoint = 0x2026; - if (codepoint == 132) codepoint = 0x2122; - if (codepoint == 133) codepoint = 0x20AC; - if (codepoint == 134) codepoint = 0x00B7; - stbtt_GetCodepointHMetrics(info, codepoint, &advance, &lsb); - width += (int)(advance * real_scale + 0.5f); - s++; + uint32_t codepoint = utf8_decode(&s); + stbtt_fontinfo *current_info = info; + float current_scale = real_scale; + + if (stbtt_FindGlyphIndex(current_info, codepoint) == 0 && fallback_font) { + current_info = (stbtt_fontinfo *)fallback_font->info; + current_scale = stbtt_ScaleForPixelHeight(current_info, scale); + } + + stbtt_GetCodepointHMetrics(current_info, codepoint, &advance, &lsb); + width += (int)(advance * current_scale + 0.5f); } return width; } + +int font_manager_get_codepoint_width_scaled(ttf_font_t *font, uint32_t codepoint, float scale) { + if (!font) font = default_font; + if (!font) return 0; + stbtt_fontinfo *info = (stbtt_fontinfo *)font->info; + float real_scale = stbtt_ScaleForPixelHeight(info, scale); + + if (stbtt_FindGlyphIndex(info, codepoint) == 0 && fallback_font) { + info = (stbtt_fontinfo *)fallback_font->info; + real_scale = stbtt_ScaleForPixelHeight(info, scale); + } + + int advance, lsb; + stbtt_GetCodepointHMetrics(info, codepoint, &advance, &lsb); + return (int)(advance * real_scale + 0.5f); +} diff --git a/src/wm/font_manager.h b/src/wm/font_manager.h index 6493961..9194123 100644 --- a/src/wm/font_manager.h +++ b/src/wm/font_manager.h @@ -44,11 +44,14 @@ typedef struct { bool font_manager_init(void); ttf_font_t* font_manager_load(const char *path, float size); -void font_manager_render_char(ttf_font_t *font, int x, int y, char c, uint32_t color, void (*put_pixel_fn)(int, int, uint32_t)); -void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, void (*put_pixel_fn)(int, int, uint32_t)); -void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, char c, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); +void font_manager_set_fallback_font(ttf_font_t *font); +uint32_t utf8_decode(const char **s); +void font_manager_render_char(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, void (*put_pixel_fn)(int, int, uint32_t)); +void font_manager_render_char_scaled(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, void (*put_pixel_fn)(int, int, uint32_t)); +void font_manager_render_char_sloped(ttf_font_t *font, int x, int y, uint32_t codepoint, uint32_t color, float scale, float slope, void (*put_pixel_fn)(int, int, uint32_t)); int font_manager_get_string_width(ttf_font_t *font, const char *s); int font_manager_get_string_width_scaled(ttf_font_t *font, const char *s, float scale); +int font_manager_get_codepoint_width_scaled(ttf_font_t *font, uint32_t codepoint, float scale); int font_manager_get_font_height_scaled(ttf_font_t *font, float scale); int font_manager_get_font_ascent_scaled(ttf_font_t *font, float scale); diff --git a/src/wm/graphics.c b/src/wm/graphics.c index 6034138..c3c9842 100644 --- a/src/wm/graphics.c +++ b/src/wm/graphics.c @@ -55,6 +55,7 @@ void graphics_init_fonts(void) { if (!g_current_ttf) { serial_write("[FONT] Falling back to bitmap font\n"); } + font_manager_set_fallback_font(font_manager_load("/Library/Fonts/Emoji/NotoEmoji-VariableFont_wght.ttf", 15.0f)); } void graphics_update_resolution(int width, int height, int bpp, void* fb_addr, int color_mode) { @@ -540,7 +541,10 @@ int graphics_get_string_width_scaled(const char *s, float scale) { return font_manager_get_string_width_scaled(g_current_ttf, s, scale); } int len = 0; - while (s && s[len]) len++; + while (s && *s) { + utf8_decode(&s); + len++; + } return len * 8; // Fallback bitmap width } @@ -559,30 +563,28 @@ void draw_string_scaled(int x, int y, const char *s, uint32_t color, float scale int line_height = font_manager_get_font_line_height_scaled(g_current_ttf, scale); while (*s) { - if (*s == '\n') { + uint32_t codepoint = utf8_decode(&s); + if (codepoint == '\n') { cur_x = x; baseline += line_height; } else { - font_manager_render_char_scaled(g_current_ttf, cur_x, baseline, *s, color, scale, put_pixel); - // Advance by same rounded width that font_manager_get_string_width uses - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(g_current_ttf, buf, scale); + font_manager_render_char_scaled(g_current_ttf, cur_x, baseline, codepoint, color, scale, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(g_current_ttf, codepoint, scale); } - s++; } return; } int cur_y = y; while (*s) { - if (*s == '\n') { + uint32_t codepoint = utf8_decode(&s); + if (codepoint == '\n') { cur_x = x; cur_y += 10; } else { - draw_char(cur_x, cur_y, *s, color); + draw_char(cur_x, cur_y, (codepoint < 128) ? (char)codepoint : '?', color); cur_x += 8; } - s++; } } @@ -600,15 +602,14 @@ void draw_string_scaled_sloped(int x, int y, const char *s, uint32_t color, floa int line_height = font_manager_get_font_line_height_scaled(g_current_ttf, scale); while (*s) { - if (*s == '\n') { + uint32_t codepoint = utf8_decode(&s); + if (codepoint == '\n') { cur_x = x; baseline += line_height; } else { - font_manager_render_char_sloped(g_current_ttf, cur_x, baseline, *s, color, scale, slope, put_pixel); - char buf[2] = {*s, 0}; - cur_x += font_manager_get_string_width_scaled(g_current_ttf, buf, scale); + font_manager_render_char_sloped(g_current_ttf, cur_x, baseline, codepoint, color, scale, slope, put_pixel); + cur_x += font_manager_get_codepoint_width_scaled(g_current_ttf, codepoint, scale); } - s++; } return; }