aboutsummaryrefslogtreecommitdiff
path: root/libtxt
diff options
context:
space:
mode:
authorMarvin Borner2020-11-28 19:14:56 +0100
committerMarvin Borner2020-11-28 19:14:56 +0100
commit24dfdaa72a64f7b1b00f5a0e054ac359fc995c52 (patch)
tree58646ec9e3752b5c87a966921a739a4d2740ced3 /libtxt
parentbaa5c8716372f29b2e1340601282c44d7c5da7e9 (diff)
parente983cfa7f8580e39a181184fb2ae3a990597c02a (diff)
Merged HTML renderer
Diffstat (limited to 'libtxt')
-rw-r--r--libtxt/Makefile2
-rw-r--r--libtxt/html.c219
-rw-r--r--libtxt/inc/html.h19
-rw-r--r--libtxt/xml.c4
4 files changed, 234 insertions, 10 deletions
diff --git a/libtxt/Makefile b/libtxt/Makefile
index 3536250..087b54c 100644
--- a/libtxt/Makefile
+++ b/libtxt/Makefile
@@ -6,7 +6,7 @@ LD = ccache ../cross/opt/bin/i686-elf-ld
AR = ccache ../cross/opt/bin/i686-elf-ar
WARNINGS = -Wall -Wextra -pedantic-errors -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wno-long-long
-CFLAGS = $(WARNINGS) -nostdlib -nostdinc -fno-builtin -mgeneral-regs-only -std=c99 -m32 -Iinc/ -I../libc/inc/ -fPIE -Duserspace -Ofast
+CFLAGS = $(WARNINGS) -nostdlib -nostdinc -fno-builtin -mgeneral-regs-only -std=c99 -m32 -Iinc/ -I../libc/inc/ -I../libgui/inc/ -fPIE -Duserspace -Ofast
all: libtxt
diff --git a/libtxt/html.c b/libtxt/html.c
index 0c07323..b54577f 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 <assert.h>
+#include <gui.h>
+#include <html.h>
+#include <list.h>
+#include <mem.h>
#include <print.h>
#include <str.h>
+#include <xml.h>
-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,209 @@ int html_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->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;
+
+ static 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';
+ 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';
+ normalize_tag_name(name);
+ if (!current || !current->parent || strcmp(name, current->tag))
+ return NULL;
+ 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;
+ }
+
+ assert(root);
+ print("GENERATED!\n");
+ print_dom(root, 0);
+ return root;
+}
+
+static struct html_element *new_html_element(struct element *container, struct dom *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)
+#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;
+
+ assert(container);
+ 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 (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 (CMP(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 (CMP(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 (CMP(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 (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 (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);
+ container->x_offset = 0;
+ container->y_offset += 2;
+ 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;
+ }
+}
+
+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);
+ 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 dd2b59f..c1b29f2 100644
--- a/libtxt/inc/html.h
+++ b/libtxt/inc/html.h
@@ -4,6 +4,23 @@
#ifndef HTML_H
#define HTML_H
-int html_self_closing(const char *tag);
+#include <def.h>
+#include <list.h>
+
+struct dom {
+ char *tag;
+ char *content;
+ struct dom *parent;
+ 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
diff --git a/libtxt/xml.c b/libtxt/xml.c
index b92181b..f40b289 100644
--- a/libtxt/xml.c
+++ b/libtxt/xml.c
@@ -485,10 +485,6 @@ enum xml_error xml_parse(struct xml *state, const char *buffer, u32 buffer_lengt
state_commit(state, &temp);
}
- // TODO: Only for self-closing tags
- if (end - lt == 0)
- break;
-
if (end - lt < TAG_MINSIZE)
return XML_ERROR_BUFFERDRY;