mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
better font rendering browser
This commit is contained in:
parent
3c7d36a50f
commit
4083b8a563
13 changed files with 338 additions and 27 deletions
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/graphics.o
BIN
build/graphics.o
Binary file not shown.
28
python_http.log
Normal file
28
python_http.log
Normal 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
|
||||
|
|
@ -109,6 +109,7 @@ ttf_font_t* font_manager_load(const char *path, float size) {
|
|||
font->data = buffer;
|
||||
font->size = fsize;
|
||||
font->info = info;
|
||||
font->pixel_height = size;
|
||||
font->scale = stbtt_ScaleForPixelHeight(info, size);
|
||||
|
||||
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)) {
|
||||
if (!font) font = default_font;
|
||||
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;
|
||||
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) {
|
||||
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) {
|
||||
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 || !s) return 0;
|
||||
|
||||
stbtt_fontinfo *info = (stbtt_fontinfo *)font->info;
|
||||
float real_scale = stbtt_ScaleForPixelHeight(info, scale);
|
||||
int width = 0;
|
||||
while (*s) {
|
||||
int advance, lsb;
|
||||
stbtt_GetCodepointHMetrics(info, *s, &advance, &lsb);
|
||||
// Round per-character to match draw_string's accumulation
|
||||
width += (int)(advance * font->scale + 0.5f);
|
||||
width += (int)(advance * real_scale + 0.5f);
|
||||
s++;
|
||||
}
|
||||
return width;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ typedef struct {
|
|||
size_t size;
|
||||
void *info; // stbtt_fontinfo
|
||||
float scale;
|
||||
float pixel_height;
|
||||
int ascent;
|
||||
int descent;
|
||||
int line_gap;
|
||||
|
|
@ -48,6 +49,12 @@ 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));
|
||||
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
|
||||
|
|
|
|||
|
|
@ -379,25 +379,45 @@ int graphics_get_font_height(void) {
|
|||
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) {
|
||||
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;
|
||||
int cur_x = x;
|
||||
|
||||
if (g_current_ttf) {
|
||||
float scale = g_current_ttf->scale;
|
||||
// Shift baseline up by roughly 2 pixels for better vertical centering in bars/inputs
|
||||
int baseline = y + (int)(g_current_ttf->ascent * scale) - 2;
|
||||
int line_height = (int)((g_current_ttf->ascent - g_current_ttf->descent + g_current_ttf->line_gap) * scale);
|
||||
// We let the font manager handle the stbtt scale internally to avoid bringing stb_truetype into graphics.c
|
||||
int baseline = y + font_manager_get_font_ascent_scaled(g_current_ttf, scale) - 2;
|
||||
int line_height = font_manager_get_font_line_height_scaled(g_current_ttf, scale);
|
||||
|
||||
while (*s) {
|
||||
if (*s == '\n') {
|
||||
cur_x = x;
|
||||
baseline += line_height;
|
||||
} 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
|
||||
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++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_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_scaled(int x, int y, const char *s, uint32_t color, float scale);
|
||||
void draw_desktop_background(void);
|
||||
void graphics_set_bg_color(uint32_t color);
|
||||
void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern
|
||||
|
|
@ -56,6 +57,8 @@ void graphics_clear_clipping(void);
|
|||
#include "font_manager.h"
|
||||
ttf_font_t *graphics_get_current_ttf(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);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
} 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 {
|
||||
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) {
|
||||
extern int graphics_get_font_height(void);
|
||||
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) {
|
||||
int cmd = (int)arg1;
|
||||
|
|
|
|||
|
|
@ -72,12 +72,16 @@ static long strtol(const char* nptr, char** endptr, int base) {
|
|||
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 {
|
||||
char content[1024];
|
||||
int x, y, w, h;
|
||||
HTMLTag tag;
|
||||
int tag; // Changed from HTMLTag enum to int
|
||||
char link_url[256];
|
||||
char attr_value[256];
|
||||
uint32_t color;
|
||||
|
|
@ -90,6 +94,7 @@ typedef struct {
|
|||
int form_id;
|
||||
int input_cursor;
|
||||
int input_scroll;
|
||||
float scale;
|
||||
} RenderElement;
|
||||
|
||||
#define MAX_ELEMENTS 65536
|
||||
|
|
@ -325,14 +330,36 @@ static void flush_line(bool centered) {
|
|||
if (offset_x < 10) offset_x = 10;
|
||||
|
||||
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++) {
|
||||
RenderElement *el = &elements[line_elements[i]];
|
||||
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;
|
||||
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_x = 10;
|
||||
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) {
|
||||
browser_clear();
|
||||
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] = "";
|
||||
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;
|
||||
bool skip_content = false;
|
||||
next_form_id = 1;
|
||||
|
|
@ -369,20 +417,68 @@ static void parse_html(const char *html) {
|
|||
|
||||
if (tag_name[0] == '/') {
|
||||
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")) {
|
||||
flush_line(is_centered);
|
||||
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, "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, "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, "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")) {
|
||||
flush_line(is_centered);
|
||||
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++; }
|
||||
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")) {
|
||||
RenderElement *el = &elements[element_count++];
|
||||
int idx = element_count - 1;
|
||||
|
|
@ -460,27 +566,49 @@ static void parse_html(const char *html) {
|
|||
}
|
||||
} else {
|
||||
if (!skip_content) {
|
||||
while (html[i] && (html[i] == ' ' || html[i] == '\n' || html[i] == '\r')) {
|
||||
is_space_pending = true;
|
||||
i++;
|
||||
}
|
||||
|
||||
while (html[i] && html[i] != '<') {
|
||||
while (html[i] && (html[i] == ' ' || html[i] == '\n' || html[i] == '\r')) i++;
|
||||
if (!html[i] || html[i] == '<') break;
|
||||
|
||||
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++];
|
||||
}
|
||||
|
||||
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;
|
||||
if (w_idx > 0) {
|
||||
if (element_count >= MAX_ELEMENTS) break;
|
||||
int word_w = ui_get_string_width(word);
|
||||
if (cur_line_x + word_w > WIN_W - SCROLL_BAR_W - 20) flush_line(is_centered);
|
||||
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 (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++];
|
||||
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++; }
|
||||
el->content[k++] = ' '; el->content[k] = 0;
|
||||
el->w = ui_get_string_width(el->content); el->h = 16;
|
||||
el->content[k] = 0;
|
||||
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->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; }
|
||||
|
||||
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 + el->w - 1, draw_y, 1, el->h, 0xFF888888);
|
||||
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 {
|
||||
ui_draw_string(win_browser, el->x, draw_y, el->content, el->color);
|
||||
if (el->bold) ui_draw_string(win_browser, el->x + 1, 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_scaled(win_browser, el->x + 1, draw_y, el->content, el->color, el->scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,3 +57,21 @@ uint32_t ui_get_string_width(const char *str) {
|
|||
uint32_t ui_get_font_height(void) {
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@
|
|||
#define GUI_CMD_GET_STRING_WIDTH 8
|
||||
#define GUI_CMD_GET_FONT_HEIGHT 9
|
||||
#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
|
||||
#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);
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in a new issue