From 0bc77c8c0dbc1737e2909ff5a2d5e5af48b298f7 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Tue, 24 Nov 2020 22:28:40 +0100 Subject: Started HTML rendering --- libtxt/html.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 120 insertions(+), 4 deletions(-) (limited to 'libtxt/html.c') diff --git a/libtxt/html.c b/libtxt/html.c index 0c07323..171de78 100644 --- a/libtxt/html.c +++ b/libtxt/html.c @@ -1,14 +1,19 @@ // MIT License, Copyright (c) 2020 Marvin Borner // HTML parsing is mainly based on the XML parser +#include +#include +#include +#include +#include #include #include +#include -int html_self_closing(const char *tag) +static int is_self_closing(const char *tag) { - // TODO: Add 'meta'? - const char *void_elements[] = { "area", "base", "br", "col", "embed", "hr", "img", - "input", "link", "param", "source", "track", "wbr" }; + const char *void_elements[] = { "area", "base", "br", "col", "embed", "hr", "img", + "input", "link", "meta", "param", "source", "track", "wbr" }; for (u32 i = 0; i < sizeof(void_elements) / sizeof(void_elements[0]); ++i) { if (!strcmp(void_elements[i], tag)) @@ -16,3 +21,114 @@ int html_self_closing(const char *tag) } return 0; } + +static struct dom *new_object(const char *tag, struct dom *parent) +{ + struct dom *object = malloc(sizeof(*object)); + object->tag = strdup(tag); + object->parent = parent; + object->content = NULL; + object->children = list_new(); + return object; +} + +static void print_dom(struct dom *dom, u32 level) +{ + struct node *iterator = dom->children->head; + while (iterator != NULL) { + struct dom *obj = iterator->data; + for (u32 i = 0; i < level; i++) + print("\t"); + printf("'%s': '%s'\n", obj->tag, obj->content ? obj->content : ""); + if (obj->children->head) + print_dom(obj, level + 1); + iterator = iterator->next; + } +} + +static struct dom *generate_dom(char *data, u32 length) +{ + struct xml_token tokens[128]; + struct xml parser; + xml_init(&parser); + void *buffer = data; + enum xml_error err = xml_parse(&parser, buffer, length, tokens, 128); + + if (err != XML_SUCCESS && err != XML_ERROR_BUFFERDRY) { + printf("\nXML parse error: %d\n", err); + return 0; + } + + struct dom *root = new_object("root", NULL); + struct dom *current = root; + + char name[256] = { 0 }; + for (u32 i = 0; i < parser.ntokens; i++) { + const struct xml_token *token = tokens + i; + name[0] = '\0'; + switch (token->type) { + case XML_START_TAG: + memcpy(&name, (u8 *)buffer + token->start_pos, + token->end_pos - token->start_pos); + name[token->end_pos - token->start_pos] = '\0'; + current = new_object(name, current); + printf("Adding %s to %s\n", current->tag, current->parent->tag); + list_add(current->parent->children, current); + break; + case XML_END_TAG: + memcpy(&name, (u8 *)buffer + token->start_pos, + token->end_pos - token->start_pos); + name[token->end_pos - token->start_pos] = '\0'; + assert(current && !strcmp(name, current->tag)); + current = current->parent; + break; + case XML_CHARACTER: + if (!current) + continue; + + if (token->end_pos == token->start_pos + 2) { + const char *ptr = (char *)buffer + token->start_pos; + + if (ptr[0] == '\r' && ptr[1] == '\n') + continue; + } + memcpy(&name, (u8 *)buffer + token->start_pos, + token->end_pos - token->start_pos); + name[token->end_pos - token->start_pos] = '\0'; + char *clean_name = name; + for (u32 j = 0; j < strlen(name); j++) { + if (name[j] == ' ' || name[j] == '\n' || name[j] == '\r' || + name[j] == '\t') { + clean_name++; + } else { + break; + } + } + if (!strlen(clean_name)) + break; + current->content = strdup(clean_name); + break; + default: + break; + } + + i += token->size; + } + + print("GENERATED!\n"); + print_dom(root, 0); + return root; +} + +int html_render_dom(struct element *container, struct dom *dom) +{ + (void)container; + (void)dom; + return 1; +} + +int html_render(struct element *container, char *data, u32 length) +{ + struct dom *dom = generate_dom(data, length); + return dom && html_render_dom(container, dom); +} -- cgit v1.2.3 From 9559b77afb343998067a7ef269be3b11654d731f Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Wed, 25 Nov 2020 18:31:31 +0100 Subject: More HTML rendering... --- libtxt/html.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- libtxt/inc/html.h | 7 ++++++ 2 files changed, 76 insertions(+), 4 deletions(-) (limited to 'libtxt/html.c') diff --git a/libtxt/html.c b/libtxt/html.c index 171de78..f92e90f 100644 --- a/libtxt/html.c +++ b/libtxt/html.c @@ -120,15 +120,80 @@ static struct dom *generate_dom(char *data, u32 length) return root; } -int html_render_dom(struct element *container, struct dom *dom) +static struct html_element *new_html_element(struct element *container, struct dom *dom) { - (void)container; - (void)dom; + struct html_element *elem = malloc(sizeof(*elem)); + elem->x_offset = 0; + elem->y_offset = 0; + elem->dom = dom; + elem->obj = container; + return elem; +} + +// TODO: Better structure? +// TODO: Less code duplication (e.g. for headings) +static struct html_element *render_object(struct html_element *container, struct dom *dom) +{ + char *tag = dom->tag; + + if (!strcmp(tag, "html")) { + struct element *obj = + gui_add_container(container->obj, 0, 0, 100, 100, COLOR_WHITE); + return new_html_element(obj, dom); + } else if (!strcmp(tag, "body")) { + struct element *obj = + gui_add_container(container->obj, 0, 0, 100, 100, COLOR_WHITE); + return new_html_element(obj, dom); + } else if (!strcmp(tag, "h1")) { + struct element *obj = + gui_add_label(container->obj, container->x_offset, container->y_offset, + FONT_32, dom->content, COLOR_WHITE, COLOR_BLACK); + container->x_offset = 0; + container->y_offset += obj->ctx->height; + return new_html_element(obj, dom); + } else if (!strcmp(tag, "h2")) { + struct element *obj = + gui_add_label(container->obj, container->x_offset, container->y_offset, + FONT_24, dom->content, COLOR_WHITE, COLOR_BLACK); + container->x_offset = 0; + container->y_offset += obj->ctx->height; + return new_html_element(obj, dom); + } else if (!strcmp(tag, "h3")) { + struct element *obj = + gui_add_label(container->obj, container->x_offset, container->y_offset, + FONT_16, dom->content, COLOR_WHITE, COLOR_BLACK); + container->x_offset = 0; + container->y_offset += obj->ctx->height; + return new_html_element(obj, dom); + } else if (!strcmp(tag, "hr")) { + gfx_draw_rectangle(container->obj->ctx, container->x_offset, container->y_offset, + container->obj->ctx->width - container->x_offset, + container->y_offset + 2, COLOR_BLACK); + container->x_offset = 0; + container->y_offset += 2; + return container; + } else { + printf("UNKNOWN %s\n", tag); + return container; + } +} + +int html_render_dom(struct html_element *container, struct dom *dom) +{ + struct node *iterator = dom->children->head; + while (iterator != NULL) { + struct dom *obj = iterator->data; + struct html_element *rendered = render_object(container, obj); + if (obj->children->head && rendered) + html_render_dom(rendered, obj); + iterator = iterator->next; + } return 1; } int html_render(struct element *container, char *data, u32 length) { struct dom *dom = generate_dom(data, length); - return dom && html_render_dom(container, dom); + struct html_element *obj = new_html_element(container, dom); + return dom && obj && html_render_dom(obj, dom); } diff --git a/libtxt/inc/html.h b/libtxt/inc/html.h index 4eaca0b..c1b29f2 100644 --- a/libtxt/inc/html.h +++ b/libtxt/inc/html.h @@ -14,6 +14,13 @@ struct dom { struct list *children; }; +struct html_element { + u32 x_offset; + u32 y_offset; + struct dom *dom; + struct element *obj; +}; + int html_render(struct element *container, char *data, u32 length); #endif -- cgit v1.2.3 From 05d7a42fa5f848f6ddc1e4018af82cd6a0e31d86 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Thu, 26 Nov 2020 14:04:07 +0100 Subject: Some changes --- libtxt/html.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'libtxt/html.c') diff --git a/libtxt/html.c b/libtxt/html.c index f92e90f..1d736b7 100644 --- a/libtxt/html.c +++ b/libtxt/html.c @@ -22,10 +22,17 @@ static int is_self_closing(const char *tag) return 0; } +static char *normalize_tag_name(char *tag) +{ + for (char *p = tag; *p; ++p) + *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p; + return tag; +} + static struct dom *new_object(const char *tag, struct dom *parent) { struct dom *object = malloc(sizeof(*object)); - object->tag = strdup(tag); + object->tag = normalize_tag_name(strdup(tag)); object->parent = parent; object->content = NULL; object->children = list_new(); @@ -132,40 +139,48 @@ static struct html_element *new_html_element(struct element *container, struct d // TODO: Better structure? // TODO: Less code duplication (e.g. for headings) +#define CMP(tag, tag_string) (!strcmp((tag), (tag_string))) static struct html_element *render_object(struct html_element *container, struct dom *dom) { char *tag = dom->tag; - if (!strcmp(tag, "html")) { + if (CMP(tag, "html")) { struct element *obj = gui_add_container(container->obj, 0, 0, 100, 100, COLOR_WHITE); return new_html_element(obj, dom); - } else if (!strcmp(tag, "body")) { + } else if (CMP(tag, "body")) { struct element *obj = gui_add_container(container->obj, 0, 0, 100, 100, COLOR_WHITE); return new_html_element(obj, dom); - } else if (!strcmp(tag, "h1")) { + } else if (CMP(tag, "h1")) { + struct element *obj = + gui_add_label(container->obj, container->x_offset, container->y_offset, + FONT_64, dom->content, COLOR_WHITE, COLOR_BLACK); + container->x_offset = 0; + container->y_offset += obj->ctx->height; + return new_html_element(obj, dom); + } else if (CMP(tag, "h2")) { struct element *obj = gui_add_label(container->obj, container->x_offset, container->y_offset, FONT_32, dom->content, COLOR_WHITE, COLOR_BLACK); container->x_offset = 0; container->y_offset += obj->ctx->height; return new_html_element(obj, dom); - } else if (!strcmp(tag, "h2")) { + } else if (CMP(tag, "h3")) { struct element *obj = gui_add_label(container->obj, container->x_offset, container->y_offset, FONT_24, dom->content, COLOR_WHITE, COLOR_BLACK); container->x_offset = 0; container->y_offset += obj->ctx->height; return new_html_element(obj, dom); - } else if (!strcmp(tag, "h3")) { + } else if (CMP(tag, "p")) { struct element *obj = gui_add_label(container->obj, container->x_offset, container->y_offset, FONT_16, dom->content, COLOR_WHITE, COLOR_BLACK); container->x_offset = 0; container->y_offset += obj->ctx->height; return new_html_element(obj, dom); - } else if (!strcmp(tag, "hr")) { + } else if (CMP(tag, "hr")) { gfx_draw_rectangle(container->obj->ctx, container->x_offset, container->y_offset, container->obj->ctx->width - container->x_offset, container->y_offset + 2, COLOR_BLACK); -- cgit v1.2.3 From c2306a5b346abc4b1d778f0071f90caec3c264ac Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Sat, 28 Nov 2020 16:15:19 +0100 Subject: Fixed tag case normalizing --- libtxt/html.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libtxt/html.c') diff --git a/libtxt/html.c b/libtxt/html.c index 1d736b7..ae50ed2 100644 --- a/libtxt/html.c +++ b/libtxt/html.c @@ -86,7 +86,7 @@ static struct dom *generate_dom(char *data, u32 length) memcpy(&name, (u8 *)buffer + token->start_pos, token->end_pos - token->start_pos); name[token->end_pos - token->start_pos] = '\0'; - assert(current && !strcmp(name, current->tag)); + assert(current && !strcmp(normalize_tag_name(name), current->tag)); current = current->parent; break; case XML_CHARACTER: -- cgit v1.2.3 From e983cfa7f8580e39a181184fb2ae3a990597c02a Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Sat, 28 Nov 2020 19:13:32 +0100 Subject: Kinda-working renderer --- apps/browser.c | 6 +++++- libtxt/html.c | 27 +++++++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'libtxt/html.c') diff --git a/apps/browser.c b/apps/browser.c index 160b626..0c2a430 100644 --- a/apps/browser.c +++ b/apps/browser.c @@ -92,6 +92,8 @@ void on_submit(void *event, struct element *box) c->color_fg = status_color(c->text); } else { /* l->text = strdup("Can't connect to server."); */ + gui_add_label(output, 0, 0, FONT_16, "Can't connect to server.", COLOR_WHITE, + COLOR_BLACK); c->text = strdup("000"); c->color_fg = COLOR_RED; } @@ -107,7 +109,9 @@ int main() code_label = gui_add_label(root, 0, 0, FONT_24, "000", COLOR_BLACK, COLOR_WHITE); struct element *text_input = gui_add_text_input(root, LABEL_WIDTH, 0, 100, FONT_24, COLOR_WHITE, COLOR_BLACK); - output = gui_add_container(root, 0, FONT_HEIGHT + 2, 100, 100, COLOR_GREEN); + output = gui_add_container(root, 0, FONT_HEIGHT + 2, 100, 100, COLOR_WHITE); + gui_add_label(output, 0, 0, FONT_16, "Enter URL and press Enter :)", COLOR_WHITE, + COLOR_BLACK); text_input->event.on_submit = on_submit; diff --git a/libtxt/html.c b/libtxt/html.c index ae50ed2..b54577f 100644 --- a/libtxt/html.c +++ b/libtxt/html.c @@ -32,7 +32,7 @@ static char *normalize_tag_name(char *tag) static struct dom *new_object(const char *tag, struct dom *parent) { struct dom *object = malloc(sizeof(*object)); - object->tag = normalize_tag_name(strdup(tag)); + object->tag = strdup(tag); object->parent = parent; object->content = NULL; object->children = list_new(); @@ -69,7 +69,7 @@ static struct dom *generate_dom(char *data, u32 length) struct dom *root = new_object("root", NULL); struct dom *current = root; - char name[256] = { 0 }; + static char name[256] = { 0 }; for (u32 i = 0; i < parser.ntokens; i++) { const struct xml_token *token = tokens + i; name[0] = '\0'; @@ -78,15 +78,20 @@ static struct dom *generate_dom(char *data, u32 length) memcpy(&name, (u8 *)buffer + token->start_pos, token->end_pos - token->start_pos); name[token->end_pos - token->start_pos] = '\0'; + normalize_tag_name(name); current = new_object(name, current); printf("Adding %s to %s\n", current->tag, current->parent->tag); list_add(current->parent->children, current); + if (is_self_closing(name)) + current = current->parent; break; case XML_END_TAG: memcpy(&name, (u8 *)buffer + token->start_pos, token->end_pos - token->start_pos); name[token->end_pos - token->start_pos] = '\0'; - assert(current && !strcmp(normalize_tag_name(name), current->tag)); + normalize_tag_name(name); + if (!current || !current->parent || strcmp(name, current->tag)) + return NULL; current = current->parent; break; case XML_CHARACTER: @@ -122,6 +127,7 @@ static struct dom *generate_dom(char *data, u32 length) i += token->size; } + assert(root); print("GENERATED!\n"); print_dom(root, 0); return root; @@ -144,6 +150,7 @@ static struct html_element *render_object(struct html_element *container, struct { char *tag = dom->tag; + assert(container); if (CMP(tag, "html")) { struct element *obj = gui_add_container(container->obj, 0, 0, 100, 100, COLOR_WHITE); @@ -155,21 +162,21 @@ static struct html_element *render_object(struct html_element *container, struct } else if (CMP(tag, "h1")) { struct element *obj = gui_add_label(container->obj, container->x_offset, container->y_offset, - FONT_64, dom->content, COLOR_WHITE, COLOR_BLACK); + FONT_32, dom->content, COLOR_WHITE, COLOR_BLACK); container->x_offset = 0; container->y_offset += obj->ctx->height; return new_html_element(obj, dom); } else if (CMP(tag, "h2")) { struct element *obj = gui_add_label(container->obj, container->x_offset, container->y_offset, - FONT_32, dom->content, COLOR_WHITE, COLOR_BLACK); + FONT_24, dom->content, COLOR_WHITE, COLOR_BLACK); container->x_offset = 0; container->y_offset += obj->ctx->height; return new_html_element(obj, dom); } else if (CMP(tag, "h3")) { struct element *obj = gui_add_label(container->obj, container->x_offset, container->y_offset, - FONT_24, dom->content, COLOR_WHITE, COLOR_BLACK); + FONT_16, dom->content, COLOR_WHITE, COLOR_BLACK); container->x_offset = 0; container->y_offset += obj->ctx->height; return new_html_element(obj, dom); @@ -189,6 +196,14 @@ static struct html_element *render_object(struct html_element *container, struct return container; } else { printf("UNKNOWN %s\n", tag); + if (dom->content && strlen(dom->content) > 0) { + struct element *obj = gui_add_label(container->obj, container->x_offset, + container->y_offset, FONT_16, + dom->content, COLOR_WHITE, COLOR_BLACK); + container->x_offset = 0; + container->y_offset += obj->ctx->height; + return new_html_element(obj, dom); + } return container; } } -- cgit v1.2.3