better font rendering browser

This commit is contained in:
boreddevnl 2026-03-03 21:22:05 +01:00
parent 3c7d36a50f
commit 4083b8a563
13 changed files with 338 additions and 27 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

28
python_http.log Normal file
View file

@ -0,0 +1,28 @@
Traceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "/opt/homebrew/Cellar/python@3.14/3.14.2/Frameworks/Python.framework/Versions/3.14/lib/python3.14/http/server.py", line 1432, in <module>
test(
~~~~^
HandlerClass=handler_class,
^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<6 lines>...
tls_password=tls_key_password,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/opt/homebrew/Cellar/python@3.14/3.14.2/Frameworks/Python.framework/Versions/3.14/lib/python3.14/http/server.py", line 1348, in test
server = ServerClass(addr, HandlerClass)
File "/opt/homebrew/Cellar/python@3.14/3.14.2/Frameworks/Python.framework/Versions/3.14/lib/python3.14/socketserver.py", line 457, in __init__
self.server_bind()
~~~~~~~~~~~~~~~~^^
File "/opt/homebrew/Cellar/python@3.14/3.14.2/Frameworks/Python.framework/Versions/3.14/lib/python3.14/http/server.py", line 1419, in server_bind
return super().server_bind()
~~~~~~~~~~~~~~~~~~~^^
File "/opt/homebrew/Cellar/python@3.14/3.14.2/Frameworks/Python.framework/Versions/3.14/lib/python3.14/http/server.py", line 148, in server_bind
socketserver.TCPServer.server_bind(self)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/opt/homebrew/Cellar/python@3.14/3.14.2/Frameworks/Python.framework/Versions/3.14/lib/python3.14/socketserver.py", line 478, in server_bind
self.socket.bind(self.server_address)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^
OSError: [Errno 48] Address already in use

View file

@ -109,6 +109,7 @@ ttf_font_t* font_manager_load(const char *path, float size) {
font->data = buffer; font->data = buffer;
font->size = fsize; font->size = fsize;
font->info = info; font->info = info;
font->pixel_height = size;
font->scale = stbtt_ScaleForPixelHeight(info, size); font->scale = stbtt_ScaleForPixelHeight(info, size);
stbtt_GetFontVMetrics(info, &font->ascent, &font->descent, &font->line_gap); stbtt_GetFontVMetrics(info, &font->ascent, &font->descent, &font->line_gap);
@ -121,10 +122,17 @@ 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(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) font = default_font;
if (!font) return; if (!font) return;
font_manager_render_char_scaled(font, x, y, c, color, font->pixel_height, put_pixel_fn);
}
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 (!font) font = default_font;
if (!font) return;
stbtt_fontinfo *info = (stbtt_fontinfo *)font->info; stbtt_fontinfo *info = (stbtt_fontinfo *)font->info;
int w, h, xoff, yoff; int w, h, xoff, yoff;
unsigned char *bitmap = stbtt_GetCodepointBitmap(info, 0, font->scale, c, &w, &h, &xoff, &yoff); float real_scale = stbtt_ScaleForPixelHeight(info, scale); // Convert pixel size back to stbtt scale
unsigned char *bitmap = stbtt_GetCodepointBitmap(info, 0, real_scale, c, &w, &h, &xoff, &yoff);
if (bitmap) { if (bitmap) {
for (int row = 0; row < h; row++) { for (int row = 0; row < h; row++) {
@ -143,16 +151,44 @@ void font_manager_render_char(ttf_font_t *font, int x, int y, char c, uint32_t c
} }
int font_manager_get_string_width(ttf_font_t *font, const char *s) { int font_manager_get_string_width(ttf_font_t *font, const char *s) {
if (!font) font = default_font;
if (!font) return 0;
return font_manager_get_string_width_scaled(font, s, font->pixel_height);
}
int font_manager_get_font_height_scaled(ttf_font_t *font, float scale) {
if (!font) font = default_font;
if (!font) return 0;
float real_scale = stbtt_ScaleForPixelHeight((stbtt_fontinfo *)font->info, scale);
return (int)((font->ascent - font->descent) * real_scale);
}
int font_manager_get_font_ascent_scaled(ttf_font_t *font, float scale) {
if (!font) font = default_font;
if (!font) return 0;
float real_scale = stbtt_ScaleForPixelHeight((stbtt_fontinfo *)font->info, scale);
return (int)(font->ascent * real_scale);
}
int font_manager_get_font_line_height_scaled(ttf_font_t *font, float scale) {
if (!font) font = default_font;
if (!font) return 0;
float real_scale = stbtt_ScaleForPixelHeight((stbtt_fontinfo *)font->info, scale);
return (int)((font->ascent - font->descent + font->line_gap) * real_scale);
}
int font_manager_get_string_width_scaled(ttf_font_t *font, const char *s, float scale) {
if (!font) font = default_font; if (!font) font = default_font;
if (!font || !s) return 0; if (!font || !s) return 0;
stbtt_fontinfo *info = (stbtt_fontinfo *)font->info; stbtt_fontinfo *info = (stbtt_fontinfo *)font->info;
float real_scale = stbtt_ScaleForPixelHeight(info, scale);
int width = 0; int width = 0;
while (*s) { while (*s) {
int advance, lsb; int advance, lsb;
stbtt_GetCodepointHMetrics(info, *s, &advance, &lsb); stbtt_GetCodepointHMetrics(info, *s, &advance, &lsb);
// Round per-character to match draw_string's accumulation // Round per-character to match draw_string's accumulation
width += (int)(advance * font->scale + 0.5f); width += (int)(advance * real_scale + 0.5f);
s++; s++;
} }
return width; return width;

View file

@ -40,6 +40,7 @@ typedef struct {
size_t size; size_t size;
void *info; // stbtt_fontinfo void *info; // stbtt_fontinfo
float scale; float scale;
float pixel_height;
int ascent; int ascent;
int descent; int descent;
int line_gap; int line_gap;
@ -48,6 +49,12 @@ typedef struct {
bool font_manager_init(void); bool font_manager_init(void);
ttf_font_t* font_manager_load(const char *path, float size); 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(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));
int font_manager_get_string_width(ttf_font_t *font, const char *s); 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_font_height_scaled(ttf_font_t *font, float scale);
int font_manager_get_font_ascent_scaled(ttf_font_t *font, float scale);
int font_manager_get_font_line_height_scaled(ttf_font_t *font, float scale);
#endif #endif

View file

@ -379,25 +379,45 @@ int graphics_get_font_height(void) {
return 10; // Fallback bitmap height return 10; // Fallback bitmap height
} }
int graphics_get_font_height_scaled(float scale) {
if (g_current_ttf) {
return font_manager_get_font_height_scaled(g_current_ttf, scale);
}
return 10; // Fallback bitmap height
}
int graphics_get_string_width_scaled(const char *s, float scale) {
if (g_current_ttf) {
return font_manager_get_string_width_scaled(g_current_ttf, s, scale);
}
int len = 0;
while (s && s[len]) len++;
return len * 8; // Fallback bitmap width
}
void draw_string(int x, int y, const char *s, uint32_t color) { void draw_string(int x, int y, const char *s, uint32_t color) {
if (g_current_ttf) draw_string_scaled(x, y, s, color, g_current_ttf->pixel_height);
else draw_string_scaled(x, y, s, color, 15.0f);
}
void draw_string_scaled(int x, int y, const char *s, uint32_t color, float scale) {
if (!s) return; if (!s) return;
int cur_x = x; int cur_x = x;
if (g_current_ttf) { if (g_current_ttf) {
float scale = g_current_ttf->scale; // We let the font manager handle the stbtt scale internally to avoid bringing stb_truetype into graphics.c
// Shift baseline up by roughly 2 pixels for better vertical centering in bars/inputs int baseline = y + font_manager_get_font_ascent_scaled(g_current_ttf, scale) - 2;
int baseline = y + (int)(g_current_ttf->ascent * scale) - 2; int line_height = font_manager_get_font_line_height_scaled(g_current_ttf, scale);
int line_height = (int)((g_current_ttf->ascent - g_current_ttf->descent + g_current_ttf->line_gap) * scale);
while (*s) { while (*s) {
if (*s == '\n') { if (*s == '\n') {
cur_x = x; cur_x = x;
baseline += line_height; baseline += line_height;
} else { } else {
font_manager_render_char(g_current_ttf, cur_x, baseline, *s, color, put_pixel); 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 // Advance by same rounded width that font_manager_get_string_width uses
char buf[2] = {*s, 0}; char buf[2] = {*s, 0};
cur_x += font_manager_get_string_width(g_current_ttf, buf); cur_x += font_manager_get_string_width_scaled(g_current_ttf, buf, scale);
} }
s++; s++;
} }

View file

@ -24,6 +24,7 @@ void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t c
void draw_char(int x, int y, char c, uint32_t color); void draw_char(int x, int y, char c, uint32_t color);
void draw_char_bitmap(int x, int y, char c, uint32_t color); void draw_char_bitmap(int x, int y, char c, uint32_t color);
void draw_string(int x, int y, const char *s, uint32_t color); void draw_string(int x, int y, const char *s, uint32_t color);
void draw_string_scaled(int x, int y, const char *s, uint32_t color, float scale);
void draw_desktop_background(void); void draw_desktop_background(void);
void graphics_set_bg_color(uint32_t color); void graphics_set_bg_color(uint32_t color);
void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern
@ -56,6 +57,8 @@ void graphics_clear_clipping(void);
#include "font_manager.h" #include "font_manager.h"
ttf_font_t *graphics_get_current_ttf(void); ttf_font_t *graphics_get_current_ttf(void);
int graphics_get_font_height(void); int graphics_get_font_height(void);
int graphics_get_font_height_scaled(float scale);
int graphics_get_string_width_scaled(const char *s, float scale);
void graphics_set_font(const char *path); void graphics_set_font(const char *path);
#endif #endif

View file

@ -385,6 +385,45 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
draw_string_bitmap(win->x + ux, win->y + uy, kernel_str, color); draw_string_bitmap(win->x + ux, win->y + uy, kernel_str, color);
} }
asm volatile("push %0; popfq" : : "r"(rflags));
}
} else if (cmd == 11) { // GUI_CMD_DRAW_STRING_SCALED
Window *win = (Window *)arg2;
uint64_t coords = arg3;
int ux = coords & 0xFFFFFFFF;
int uy = coords >> 32;
const char *user_str = (const char *)arg4;
uint64_t packed = arg5;
uint32_t color = packed & 0xFFFFFFFF;
uint32_t scale_bits = packed >> 32;
float scale = *(float*)&scale_bits;
if (win && user_str) {
extern void draw_string_scaled(int x, int y, const char *str, uint32_t color, float scale);
extern void graphics_set_render_target(uint32_t *buffer, int w, int h);
// Copy string safely to kernel stack buffer
char kernel_str[256];
int i = 0;
while (i < 255 && user_str[i]) {
kernel_str[i] = user_str[i];
i++;
}
kernel_str[i] = 0;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (win->pixels) {
if (ux >= -100 && ux < win->w && uy >= -100 && uy < (win->h - 20)) {
graphics_set_render_target(win->pixels, win->w, win->h - 20);
draw_string_scaled(ux, uy, kernel_str, color, scale);
graphics_set_render_target(NULL, 0, 0);
}
} else {
draw_string_scaled(win->x + ux, win->y + uy, kernel_str, color, scale);
}
asm volatile("push %0; popfq" : : "r"(rflags)); asm volatile("push %0; popfq" : : "r"(rflags));
} }
} else if (cmd == GUI_CMD_DRAW_IMAGE) { } else if (cmd == GUI_CMD_DRAW_IMAGE) {
@ -464,9 +503,31 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
} else { } else {
return (uint64_t)i * 8; // Fallback bitmap width return (uint64_t)i * 8; // Fallback bitmap width
} }
} else if (cmd == 12) { // GUI_CMD_GET_STRING_WIDTH_SCALED
const char *user_str = (const char *)arg2;
uint32_t scale_bits = (uint32_t)arg3;
float scale = *(float*)&scale_bits;
if (!user_str) return 0;
char kernel_str[256];
int i = 0;
while (i < 255 && user_str[i]) {
kernel_str[i] = user_str[i];
i++;
}
kernel_str[i] = 0;
extern int graphics_get_string_width_scaled(const char *s, float scale);
return (uint64_t)graphics_get_string_width_scaled(kernel_str, scale);
} else if (cmd == GUI_CMD_GET_FONT_HEIGHT) { } else if (cmd == GUI_CMD_GET_FONT_HEIGHT) {
extern int graphics_get_font_height(void); extern int graphics_get_font_height(void);
return (uint64_t)graphics_get_font_height(); return (uint64_t)graphics_get_font_height();
} else if (cmd == 13) { // GUI_CMD_GET_FONT_HEIGHT_SCALED
uint32_t scale_bits = (uint32_t)arg2;
float scale = *(float*)&scale_bits;
extern int graphics_get_font_height_scaled(float scale);
return (uint64_t)graphics_get_font_height_scaled(scale);
} }
} else if (syscall_num == SYS_FS) { } else if (syscall_num == SYS_FS) {
int cmd = (int)arg1; int cmd = (int)arg1;

View file

@ -72,12 +72,16 @@ static long strtol(const char* nptr, char** endptr, int base) {
return neg ? -res : res; return neg ? -res : res;
} }
typedef enum { TAG_NONE, TAG_IMG, TAG_INPUT, TAG_BUTTON } HTMLTag; #define TAG_NONE 0
#define TAG_IMG 1
#define TAG_INPUT 2
#define TAG_BUTTON 3
#define TAG_HR 4
typedef struct { typedef struct {
char content[1024]; char content[1024];
int x, y, w, h; int x, y, w, h;
HTMLTag tag; int tag; // Changed from HTMLTag enum to int
char link_url[256]; char link_url[256];
char attr_value[256]; char attr_value[256];
uint32_t color; uint32_t color;
@ -90,6 +94,7 @@ typedef struct {
int form_id; int form_id;
int input_cursor; int input_cursor;
int input_scroll; int input_scroll;
float scale;
} RenderElement; } RenderElement;
#define MAX_ELEMENTS 65536 #define MAX_ELEMENTS 65536
@ -325,14 +330,36 @@ static void flush_line(bool centered) {
if (offset_x < 10) offset_x = 10; if (offset_x < 10) offset_x = 10;
int max_h = 16; int max_h = 16;
int max_baseline = 16;
// First pass: find maximum height and maximum baseline
for (int i = 0; i < line_element_count; i++) {
RenderElement *el = &elements[line_elements[i]];
if (el->tag == TAG_IMG && el->img_h + 10 > max_h) max_h = el->img_h + 10;
if ((el->tag == TAG_INPUT || el->tag == TAG_BUTTON) && 20 + 10 > max_h) max_h = 20 + 10;
if (el->tag == TAG_NONE) {
int fh = ui_get_font_height_scaled(el->scale);
if (fh + 4 > max_h) max_h = fh + 4;
if (fh > max_baseline) max_baseline = fh;
}
}
// Second pass: apply coordinates with baseline alignment
for (int i = 0; i < line_element_count; i++) { for (int i = 0; i < line_element_count; i++) {
RenderElement *el = &elements[line_elements[i]]; RenderElement *el = &elements[line_elements[i]];
el->x = offset_x; el->x = offset_x;
el->y = cur_line_y;
// Align text to the baseline of the largest text on this line
if (el->tag == TAG_NONE) {
int fh = ui_get_font_height_scaled(el->scale);
el->y = cur_line_y + (max_baseline - fh);
} else {
el->y = cur_line_y; // Keep images/inputs at the top for now
}
offset_x += el->w; offset_x += el->w;
if (el->tag == TAG_IMG && el->img_h + 10 > max_h) max_h = el->img_h + 10;
if ((el->tag == TAG_INPUT || el->tag == TAG_BUTTON) && 20 + 10 > max_h) max_h = 20 + 10;
} }
cur_line_y += max_h; cur_line_y += max_h;
cur_line_x = 10; cur_line_x = 10;
line_element_count = 0; line_element_count = 0;
@ -340,10 +367,31 @@ static void flush_line(bool centered) {
} }
static uint32_t parse_html_color(const char *str) {
if (!str) return COLOR_TEXT;
while (*str == ' ' || *str == '\"' || *str == '\'') str++;
if (*str == '#') {
char *end;
uint32_t val = (uint32_t)strtol(str + 1, &end, 16);
return 0xFF000000 | val; // Assumes RRGGBB
}
if (str_istarts_with(str, "red")) return 0xFFFF0000;
if (str_istarts_with(str, "green")) return 0xFF008000;
if (str_istarts_with(str, "blue")) return 0xFF0000FF;
if (str_istarts_with(str, "white")) return 0xFFFFFFFF;
if (str_istarts_with(str, "black")) return 0xFF000000;
if (str_istarts_with(str, "yellow")) return 0xFFFFFF00;
if (str_istarts_with(str, "gray")) return 0xFF808080;
if (str_istarts_with(str, "purple")) return 0xFF800080;
return COLOR_TEXT;
}
static void parse_html(const char *html) { static void parse_html(const char *html) {
browser_clear(); browser_clear();
cur_line_y = 10; cur_line_y = 10; cur_line_x = 10; line_element_count = 0; cur_line_y = 10; cur_line_y = 10; cur_line_x = 10; line_element_count = 0;
int i = 0; bool is_centered = false; bool is_bold = false; uint32_t current_color = COLOR_TEXT; char current_link[256] = ""; int i = 0; bool is_centered = false; bool is_bold = false; uint32_t current_color = COLOR_TEXT; char current_link[256] = "";
float current_scale = 15.0f; float base_scale = 15.0f;
bool is_space_pending = false;
char current_form_action[256] = ""; int current_form_id = 0; char current_form_action[256] = ""; int current_form_id = 0;
bool skip_content = false; bool skip_content = false;
next_form_id = 1; next_form_id = 1;
@ -369,20 +417,68 @@ static void parse_html(const char *html) {
if (tag_name[0] == '/') { if (tag_name[0] == '/') {
if (str_istarts_with(tag_name+1, "center")) { flush_line(is_centered); is_centered = false; } if (str_istarts_with(tag_name+1, "center")) { flush_line(is_centered); is_centered = false; }
else if (tag_name[1] == 'h' && tag_name[2] >= '1' && tag_name[2] <= '6') { flush_line(is_centered); cur_line_y += 10; is_bold = false; } else if (tag_name[1] == 'h' && tag_name[2] >= '1' && tag_name[2] <= '6') { flush_line(is_centered); cur_line_y += 10; is_bold = false; base_scale = 15.0f; current_scale = 15.0f; }
else if (str_istarts_with(tag_name+1, "form")) { else if (str_istarts_with(tag_name+1, "form")) {
flush_line(is_centered); flush_line(is_centered);
current_form_id = 0; current_form_action[0] = 0; current_form_id = 0; current_form_action[0] = 0;
} }
else if (str_istarts_with(tag_name+1, "a")) current_link[0] = 0; else if (str_istarts_with(tag_name+1, "a")) current_link[0] = 0;
else if (str_istarts_with(tag_name+1, "p") || str_istarts_with(tag_name+1, "li") || str_istarts_with(tag_name+1, "ol") || str_istarts_with(tag_name+1, "div")) flush_line(is_centered); else if (str_istarts_with(tag_name+1, "p") || str_istarts_with(tag_name+1, "li") || str_istarts_with(tag_name+1, "ol") || str_istarts_with(tag_name+1, "div")) flush_line(is_centered);
else if (str_istarts_with(tag_name+1, "font")) current_color = COLOR_TEXT; else if (str_istarts_with(tag_name+1, "font")) { current_color = COLOR_TEXT; current_scale = base_scale; }
else if (str_istarts_with(tag_name+1, "head") || (tag_name[1] == 's' && tag_name[2] == 'c') || (tag_name[1] == 's' && tag_name[2] == 'i') || (tag_name[1] == 's' && tag_name[2] == 't') || str_istarts_with(tag_name+1, "title") || str_istarts_with(tag_name+1, "noscript") || str_istarts_with(tag_name+1, "style")) skip_content = false; else if (str_istarts_with(tag_name+1, "head") || (tag_name[1] == 's' && tag_name[2] == 'c') || (tag_name[1] == 's' && tag_name[2] == 'i') || (tag_name[1] == 's' && tag_name[2] == 't') || str_istarts_with(tag_name+1, "title") || str_istarts_with(tag_name+1, "noscript") || str_istarts_with(tag_name+1, "style")) skip_content = false;
} else { } else {
if (str_istarts_with(tag_name, "center")) { flush_line(is_centered); is_centered = true; } if (str_istarts_with(tag_name, "center")) { flush_line(is_centered); is_centered = true; }
else if (tag_name[0] == 'h' && tag_name[1] >= '1' && tag_name[1] <= '6') { flush_line(is_centered); cur_line_y += 10; is_bold = true; } else if (tag_name[0] == 'h' && tag_name[1] >= '1' && tag_name[1] <= '6') {
flush_line(is_centered); cur_line_y += 10; is_bold = true;
if (tag_name[1] == '1') base_scale = 32.0f;
else if (tag_name[1] == '2') base_scale = 24.0f;
else if (tag_name[1] == '3') base_scale = 20.0f;
else base_scale = 18.0f;
current_scale = base_scale;
}
else if (str_istarts_with(tag_name, "font")) {
char *color_str = str_istrstr(attr_buf, "color=\"");
if (color_str) {
current_color = parse_html_color(color_str + 7);
} else {
color_str = str_istrstr(attr_buf, "color=");
if (color_str) current_color = parse_html_color(color_str + 6);
}
char *size_str = str_istrstr(attr_buf, "size=\"");
int offset = 0;
if (size_str) {
offset = 6;
} else {
size_str = str_istrstr(attr_buf, "size=");
if (size_str) offset = 5;
}
if (size_str) {
char s_char = size_str[offset];
if (s_char == '+') {
int inc = size_str[offset+1] - '0';
int new_sz = 3 + inc;
if (new_sz > 7) new_sz = 7;
if (new_sz < 1) new_sz = 1;
s_char = '0' + new_sz;
} else if (s_char == '-') {
int dec = size_str[offset+1] - '0';
int new_sz = 3 - dec;
if (new_sz > 7) new_sz = 7;
if (new_sz < 1) new_sz = 1;
s_char = '0' + new_sz;
}
if (s_char == '1') current_scale = 10.0f;
else if (s_char == '2') current_scale = 13.0f;
else if (s_char == '3') current_scale = 15.0f;
else if (s_char == '4') current_scale = 18.0f;
else if (s_char == '5') current_scale = 24.0f;
else if (s_char == '6') current_scale = 32.0f;
else if (s_char >= '7' && s_char <= '9') current_scale = 48.0f;
}
}
else if (str_istarts_with(tag_name, "br")) flush_line(is_centered); else if (str_istarts_with(tag_name, "br")) flush_line(is_centered);
else if (str_istarts_with(tag_name, "h") || str_istarts_with(tag_name, "p") || str_istarts_with(tag_name, "hr") || str_istarts_with(tag_name, "li") || str_istarts_with(tag_name, "ol") || str_istarts_with(tag_name, "div")) flush_line(is_centered); else if (str_istarts_with(tag_name, "p") || str_istarts_with(tag_name, "li") || str_istarts_with(tag_name, "ol") || str_istarts_with(tag_name, "div")) flush_line(is_centered);
else if (str_istarts_with(tag_name, "form")) { else if (str_istarts_with(tag_name, "form")) {
flush_line(is_centered); flush_line(is_centered);
current_form_id = next_form_id++; current_form_id = next_form_id++;
@ -402,6 +498,16 @@ static void parse_html(const char *html) {
while(href[l] && href[l] != '\"' && l < 255) { current_link[l] = href[l]; l++; } while(href[l] && href[l] != '\"' && l < 255) { current_link[l] = href[l]; l++; }
current_link[l] = 0; current_link[l] = 0;
} }
} else if (str_istarts_with(tag_name, "hr")) {
flush_line(is_centered);
RenderElement *el = &elements[element_count++];
for (int k=0; k<(int)sizeof(RenderElement); k++) ((char*)el)[k] = 0;
el->tag = TAG_HR;
el->w = WIN_W - SCROLL_BAR_W - 40;
el->h = 10; // Extra padding
el->centered = true;
line_elements[line_element_count++] = element_count - 1;
flush_line(is_centered);
} else if (str_istarts_with(tag_name, "img")) { } else if (str_istarts_with(tag_name, "img")) {
RenderElement *el = &elements[element_count++]; RenderElement *el = &elements[element_count++];
int idx = element_count - 1; int idx = element_count - 1;
@ -460,27 +566,49 @@ static void parse_html(const char *html) {
} }
} else { } else {
if (!skip_content) { if (!skip_content) {
while (html[i] && html[i] != '<') { while (html[i] && (html[i] == ' ' || html[i] == '\n' || html[i] == '\r')) {
while (html[i] && (html[i] == ' ' || html[i] == '\n' || html[i] == '\r')) i++; is_space_pending = true;
if (!html[i] || html[i] == '<') break; i++;
}
while (html[i] && html[i] != '<') {
char word[256]; int w_idx = 0; char word[256]; int w_idx = 0;
while (html[i] && html[i] != '<' && html[i] != ' ' && html[i] != '\n' && html[i] != '\r' && w_idx < 255) { if (is_space_pending) {
if (cur_line_x > 10) word[w_idx++] = ' ';
is_space_pending = false;
}
while (html[i] && html[i] != '<' && html[i] != ' ' && html[i] != '\n' && html[i] != '\r' && w_idx < 254) {
word[w_idx++] = html[i++]; word[w_idx++] = html[i++];
} }
if (html[i] == ' ' || html[i] == '\n' || html[i] == '\r') {
is_space_pending = true;
while (html[i] && (html[i] == ' ' || html[i] == '\n' || html[i] == '\r')) i++;
}
word[w_idx] = 0; word[w_idx] = 0;
if (w_idx > 0) { if (w_idx > 0) {
if (element_count >= MAX_ELEMENTS) break; if (element_count >= MAX_ELEMENTS) break;
int word_w = ui_get_string_width(word); int word_w = ui_get_string_width_scaled(word, current_scale);
if (cur_line_x + word_w > WIN_W - SCROLL_BAR_W - 20) flush_line(is_centered); if (cur_line_x + word_w > WIN_W - SCROLL_BAR_W - 20) {
flush_line(is_centered);
if (word[0] == ' ') {
for (int k=0; k<w_idx; k++) word[k] = word[k+1];
word_w = ui_get_string_width_scaled(word, current_scale);
if (word[0] == 0) continue;
}
}
RenderElement *el = &elements[element_count++]; RenderElement *el = &elements[element_count++];
for (int k=0; k<(int)sizeof(RenderElement); k++) ((char*)el)[k] = 0; for (int k=0; k<(int)sizeof(RenderElement); k++) ((char*)el)[k] = 0;
int k=0; while(word[k]) { el->content[k] = word[k]; k++; } int k=0; while(word[k]) { el->content[k] = word[k]; k++; }
el->content[k++] = ' '; el->content[k] = 0; el->content[k] = 0;
el->w = ui_get_string_width(el->content); el->h = 16; el->w = word_w;
el->h = ui_get_font_height_scaled(current_scale);
el->tag = TAG_NONE; el->color = current_link[0] ? COLOR_LINK : current_color; el->tag = TAG_NONE; el->color = current_link[0] ? COLOR_LINK : current_color;
el->centered = is_centered; el->bold = is_bold; el->centered = is_centered; el->bold = is_bold;
el->scale = current_scale;
if (current_link[0]) { int k=0; while(current_link[k]) { el->link_url[k] = current_link[k]; k++; } el->link_url[k] = 0; } if (current_link[0]) { int k=0; while(current_link[k]) { el->link_url[k] = current_link[k]; k++; } el->link_url[k] = 0; }
line_elements[line_element_count++] = element_count - 1; line_elements[line_element_count++] = element_count - 1;
@ -541,9 +669,12 @@ static void browser_paint(void) {
ui_draw_rect(win_browser, el->x, draw_y, 1, el->h, 0xFFFFFFFF); ui_draw_rect(win_browser, el->x, draw_y, 1, el->h, 0xFFFFFFFF);
ui_draw_rect(win_browser, el->x + el->w - 1, draw_y, 1, el->h, 0xFF888888); ui_draw_rect(win_browser, el->x + el->w - 1, draw_y, 1, el->h, 0xFF888888);
ui_draw_string(win_browser, el->x + 10, draw_y + 4, el->attr_value, 0xFF000000); ui_draw_string(win_browser, el->x + 10, draw_y + 4, el->attr_value, 0xFF000000);
} else if (el->tag == TAG_HR) {
ui_draw_rect(win_browser, el->x, draw_y + el->h / 2, el->w, 2, 0xFF888888);
ui_draw_rect(win_browser, el->x, draw_y + (el->h / 2) + 2, el->w, 1, 0xFFFFFFFF);
} else { } else {
ui_draw_string(win_browser, el->x, draw_y, el->content, el->color); ui_draw_string_scaled(win_browser, el->x, draw_y, el->content, el->color, el->scale);
if (el->bold) ui_draw_string(win_browser, el->x + 1, draw_y, el->content, el->color); if (el->bold) ui_draw_string_scaled(win_browser, el->x + 1, draw_y, el->content, el->color, el->scale);
} }
} }

View file

@ -57,3 +57,21 @@ uint32_t ui_get_string_width(const char *str) {
uint32_t ui_get_font_height(void) { uint32_t ui_get_font_height(void) {
return (uint32_t)syscall3(SYS_GUI, GUI_CMD_GET_FONT_HEIGHT, 0, 0); return (uint32_t)syscall3(SYS_GUI, GUI_CMD_GET_FONT_HEIGHT, 0, 0);
} }
void ui_draw_string_scaled(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale) {
uint64_t coords = ((uint64_t)x & 0xFFFFFFFF) | ((uint64_t)y << 32);
// Pack color into lower 32, scale (as uint32_t representation) into upper 32
uint32_t scale_bits = *(uint32_t*)&scale;
uint64_t packed_arg5 = ((uint64_t)scale_bits << 32) | (color & 0xFFFFFFFF);
syscall5(SYS_GUI, GUI_CMD_DRAW_STRING_SCALED, (uint64_t)win, coords, (uint64_t)str, packed_arg5);
}
uint32_t ui_get_string_width_scaled(const char *str, float scale) {
uint32_t scale_bits = *(uint32_t*)&scale;
return (uint32_t)syscall4(SYS_GUI, GUI_CMD_GET_STRING_WIDTH_SCALED, (uint64_t)str, (uint64_t)scale_bits, 0);
}
uint32_t ui_get_font_height_scaled(float scale) {
uint32_t scale_bits = *(uint32_t*)&scale;
return (uint32_t)syscall3(SYS_GUI, GUI_CMD_GET_FONT_HEIGHT_SCALED, (uint64_t)scale_bits, 0);
}

View file

@ -15,6 +15,9 @@
#define GUI_CMD_GET_STRING_WIDTH 8 #define GUI_CMD_GET_STRING_WIDTH 8
#define GUI_CMD_GET_FONT_HEIGHT 9 #define GUI_CMD_GET_FONT_HEIGHT 9
#define GUI_CMD_DRAW_STRING_BITMAP 10 #define GUI_CMD_DRAW_STRING_BITMAP 10
#define GUI_CMD_DRAW_STRING_SCALED 11
#define GUI_CMD_GET_STRING_WIDTH_SCALED 12
#define GUI_CMD_GET_FONT_HEIGHT_SCALED 13
// Event Types // Event Types
#define GUI_EVENT_NONE 0 #define GUI_EVENT_NONE 0
@ -52,4 +55,8 @@ uint32_t ui_get_string_width(const char *str);
uint32_t ui_get_font_height(void); uint32_t ui_get_font_height(void);
void ui_draw_string_bitmap(ui_window_t win, int x, int y, const char *str, uint32_t color); void ui_draw_string_bitmap(ui_window_t win, int x, int y, const char *str, uint32_t color);
void ui_draw_string_scaled(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale);
uint32_t ui_get_string_width_scaled(const char *str, float scale);
uint32_t ui_get_font_height_scaled(float scale);
#endif #endif