FEAT: Unicode support using NotoEmoji

This commit is contained in:
boreddevnl 2026-03-17 19:46:48 +01:00
parent 72baf6506d
commit 7eb55f3a59
6 changed files with 135 additions and 79 deletions

View file

@ -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; \

Binary file not shown.

View file

@ -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);

View file

@ -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];
}
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)) {
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(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,14 +207,10 @@ 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);
@ -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,14 +241,10 @@ 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);
@ -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);
}

View file

@ -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);

View file

@ -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;
}