http post with a simple HTML <form> content ok master
authoryu.dongliang <18588496441@163.com>
Tue, 19 Nov 2024 04:05:15 +0000 (12:05 +0800)
committeryu.dongliang <18588496441@163.com>
Tue, 19 Nov 2024 04:05:15 +0000 (12:05 +0800)
18 files changed:
html/abc_html.c
html/abc_html.h
html/abc_io_http.c
html/abc_obj.c
html/abc_obj.h
net/ngx_http_abc.h
net/ngx_http_abc_module.c
ui/Makefile
ui/abc_layout.c
ui/abc_layout_h1.c
ui/abc_layout_td.c [new file with mode: 0644]
ui/abc_render.c
ui/abc_render_h1.c
ui/abc_render_meta.c [new file with mode: 0644]
ui/abc_render_table.c [new file with mode: 0644]
ui/abc_render_td.c [new file with mode: 0644]
ui/abc_render_tr.c [new file with mode: 0644]
ui/main.c

index 3f3485983c8b948a436cfa4661c70c738d247566..0dd2cd48b8360cc5e7386a4bac467a72326a5768 100644 (file)
@@ -28,6 +28,7 @@ static abc_io_t*  abc_io_array[ABC_PROTO_NB] =
        [ABC_PROTO_HTTP] = &abc_io_http,
 };
 
        [ABC_PROTO_HTTP] = &abc_io_http,
 };
 
+// HTML attrs
 static char* src_keys[]        = {"src",        "源",       NULL};
 static char* href_keys[]       = {"href",       "地址",     NULL};
 
 static char* src_keys[]        = {"src",        "源",       NULL};
 static char* href_keys[]       = {"href",       "地址",     NULL};
 
@@ -47,6 +48,17 @@ static char* value_keys[]      = {"value",      "值",       NULL};
 static char* action_keys[]     = {"action",     "动作",     NULL};
 static char* method_keys[]     = {"method",     "方法",     NULL};
 
 static char* action_keys[]     = {"action",     "动作",     NULL};
 static char* method_keys[]     = {"method",     "方法",     NULL};
 
+static char* xmlns_keys[]      = {"xmlns",      NULL};
+static char* xmlang_keys[]     = {"xml:lang",   NULL};
+static char* lang_keys[]       = {"lang",       "语言",     NULL};
+
+static char* http_equiv_keys[] = {"http-equiv", NULL};
+static char* content_keys[]    = {"content",    "正文类型", NULL};
+static char* charset_keys[]    = {"charset",    "字符集",   NULL};
+
+static char* enctype_keys[]    = {"enctype",    NULL};
+
+// HTML labels
 static char* html_keys[]       = {"html",       "网页",     NULL};
 static char* head_keys[]       = {"head",       "头部",     NULL};
 static char* body_keys[]       = {"body",       "主体",     NULL};
 static char* html_keys[]       = {"html",       "网页",     NULL};
 static char* head_keys[]       = {"head",       "头部",     NULL};
 static char* body_keys[]       = {"body",       "主体",     NULL};
@@ -54,13 +66,20 @@ static char* form_keys[]       = {"form",       "表单",     NULL};
 static char* div_keys[]        = {"div",        "分区",     NULL};
 static char* img_keys[]        = {"img",        "图片",     NULL};
 
 static char* div_keys[]        = {"div",        "分区",     NULL};
 static char* img_keys[]        = {"img",        "图片",     NULL};
 
+static char* meta_keys[]       = {"meta",       NULL};
+
+static char* center_keys[]     = {"center",     "居中",     NULL};
 static char* title_keys[]      = {"title",      "标题",     NULL};
 static char* input_keys[]      = {"input",      "输入",     NULL};
 static char* label_keys[]      = {"label",      "标签",     NULL};
 static char* title_keys[]      = {"title",      "标题",     NULL};
 static char* input_keys[]      = {"input",      "输入",     NULL};
 static char* label_keys[]      = {"label",      "标签",     NULL};
-static char* center_keys[]     = {"center",     "居中",     NULL};
+
+static char* table_keys[]      = {"table",      "表格",     NULL};
+static char* tr_keys[]         = {"tr",         "行",       NULL};
+static char* td_keys[]         = {"td",         "列",       NULL};
 
 static char* br_keys[]         = {"br",         "换行",     NULL};
 static char* hr_keys[]         = {"hr",         "标题换行", NULL};
 
 static char* br_keys[]         = {"br",         "换行",     NULL};
 static char* hr_keys[]         = {"hr",         "标题换行", NULL};
+
 static char* h1_keys[]         = {"h1",         "标题1",    NULL};
 static char* h2_keys[]         = {"h2",         "标题2",    NULL};
 static char* h3_keys[]         = {"h3",         "标题3",    NULL};
 static char* h1_keys[]         = {"h1",         "标题1",    NULL};
 static char* h2_keys[]         = {"h2",         "标题2",    NULL};
 static char* h3_keys[]         = {"h3",         "标题3",    NULL};
@@ -70,6 +89,19 @@ static char* h6_keys[]         = {"h6",         "标题6",    NULL};
 static char* p_keys[]          = {"p",          "段落",     NULL};
 static char* a_keys[]          = {"a",          "超链接",   NULL};
 
 static char* p_keys[]          = {"p",          "段落",     NULL};
 static char* a_keys[]          = {"a",          "超链接",   NULL};
 
+static html_attr_t  html_attrs[] =
+{
+       {xmlns_keys,       "",           ABC_HTML_ATTR_XMLNS,     0},
+       {xmlang_keys,      "",           ABC_HTML_ATTR_XMLANG,    0},
+       {lang_keys,        "",           ABC_HTML_ATTR_LANG,      0},
+};
+
+static html_attr_t  meta_attrs[] =
+{
+       {http_equiv_keys,  "",           ABC_HTML_ATTR_HTTP_EQUIV, ABC_HTML_FLAG_SHOW},
+       {content_keys,     "",           ABC_HTML_ATTR_CONTENT,    ABC_HTML_FLAG_SHOW},
+//     {charset_keys,     "",           ABC_HTML_ATTR_CHARSET,    ABC_HTML_FLAG_SHOW},
+};
 
 static html_attr_t  h1_attrs[] =
 {
 
 static html_attr_t  h1_attrs[] =
 {
@@ -154,11 +186,15 @@ static html_attr_t  form_attrs[] =
 
        {font_keys,        "SimSong",    ABC_HTML_ATTR_FONT,       0},
        {font_size_keys,   "16",         ABC_HTML_ATTR_FONT_SIZE,  0},
 
        {font_keys,        "SimSong",    ABC_HTML_ATTR_FONT,       0},
        {font_size_keys,   "16",         ABC_HTML_ATTR_FONT_SIZE,  0},
+
+       {enctype_keys,     "",           ABC_HTML_ATTR_ENCTYPE,    0},
 };
 
 static html_label_t  html_labels[] =
 {
 };
 
 static html_label_t  html_labels[] =
 {
-       {html_keys,   ABC_HTML,        0, NULL, ABC_HTML_FLAG_CLOSE},
+       {html_keys,   ABC_HTML,        abc_number_of(html_attrs), html_attrs,   ABC_HTML_FLAG_CLOSE},
+       {meta_keys,   ABC_HTML_META,   abc_number_of(meta_attrs), meta_attrs,   ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SINGLE},
+
        {title_keys,  ABC_HTML_TITLE,  0, NULL, ABC_HTML_FLAG_CLOSE},
        {head_keys,   ABC_HTML_HEAD,   0, NULL, ABC_HTML_FLAG_CLOSE},
        {body_keys,   ABC_HTML_BODY,   0, NULL, ABC_HTML_FLAG_CLOSE},
        {title_keys,  ABC_HTML_TITLE,  0, NULL, ABC_HTML_FLAG_CLOSE},
        {head_keys,   ABC_HTML_HEAD,   0, NULL, ABC_HTML_FLAG_CLOSE},
        {body_keys,   ABC_HTML_BODY,   0, NULL, ABC_HTML_FLAG_CLOSE},
@@ -183,6 +219,10 @@ static html_label_t  html_labels[] =
        {input_keys,  ABC_HTML_INPUT,  abc_number_of(input_attrs), input_attrs, ABC_HTML_FLAG_OPEN},
        {label_keys,  ABC_HTML_LABEL,  abc_number_of(label_attrs), label_attrs, ABC_HTML_FLAG_CLOSE},
        {center_keys, ABC_HTML_CENTER, 0,                          NULL,        ABC_HTML_FLAG_CLOSE},
        {input_keys,  ABC_HTML_INPUT,  abc_number_of(input_attrs), input_attrs, ABC_HTML_FLAG_OPEN},
        {label_keys,  ABC_HTML_LABEL,  abc_number_of(label_attrs), label_attrs, ABC_HTML_FLAG_CLOSE},
        {center_keys, ABC_HTML_CENTER, 0,                          NULL,        ABC_HTML_FLAG_CLOSE},
+
+       {table_keys,  ABC_HTML_TABLE,  0,                          NULL,        ABC_HTML_FLAG_CLOSE},
+       {tr_keys,     ABC_HTML_TR,     0,                          NULL,        ABC_HTML_FLAG_CLOSE},
+       {td_keys,     ABC_HTML_TD,     0,                          NULL,        ABC_HTML_FLAG_CLOSE},
 };
 
 static int __html_parse_obj(abc_html_t* html, abc_char_t* c);
 };
 
 static int __html_parse_obj(abc_html_t* html, abc_char_t* c);
@@ -258,6 +298,86 @@ static int __html_load_attrs(abc_obj_t* obj, html_attr_t* attrs, int n_attrs)
        return 0;
 }
 
        return 0;
 }
 
+int    abc_html_post(abc_html_t** pp, abc_html_t* form, abc_obj_t* submit)
+{
+       if (!pp || !form || !form->file || !submit)
+               return -EINVAL;
+
+       scf_string_t* url;
+       scf_string_t* content;
+       abc_html_t*   html;
+       abc_obj_t*    action;
+       abc_io_t*     io;
+       int n;
+
+       if (!strncmp(form->file->data, "http://", 7)) {
+               n  = 7;
+               io = abc_io_array[ABC_PROTO_HTTP];
+       } else {
+               scf_loge("proto of '%s' NOT support\n", form->file->data);
+               return -EINVAL;
+       }
+
+       action = abc_obj_find_attr(submit, ABC_HTML_ATTR_ACTION);
+       if (!action) {
+               scf_loge("'post' should have an 'action'\n");
+               return -EINVAL;
+       }
+
+       url = scf_string_clone(form->file);
+       if (!url)
+               return -ENOMEM;
+
+       int ret = scf_string_cat_cstr_len(url, "/", 1);
+       if (ret < 0) {
+               scf_string_free(url);
+               return ret;
+       }
+
+       ret = scf_string_cat(url, action->value);
+       if (ret < 0) {
+               scf_string_free(url);
+               return ret;
+       }
+
+       scf_logi("post: %s\n", url->data);
+
+       content = abc_obj_to_string(form->root);
+       if (!content) {
+               scf_string_free(url);
+               return -ENOMEM;
+       }
+
+       html = calloc(1, sizeof(abc_html_t));
+       if (!html) {
+               scf_string_free(url);
+               scf_string_free(content);
+               return -ENOMEM;
+       }
+
+       html->io.proto = io->proto;
+       html->io.priv  = NULL;
+       html->io.open  = io->open;
+       html->io.close = io->close;
+       html->io.popc  = io->popc;
+       html->io.post  = io->post;
+
+       ret = io->post(html, url->data + n, content);
+       if (ret < 0) {
+               scf_string_free(url);
+               scf_string_free(content);
+               free(html);
+               return ret;
+       }
+
+       html->file = url;
+
+       html->n_lines = 1;
+
+       *pp = html;
+       return 0;
+}
+
 int    abc_html_open(abc_html_t** pp, const char* path)
 {
        if (!pp || !path)
 int    abc_html_open(abc_html_t** pp, const char* path)
 {
        if (!pp || !path)
@@ -571,9 +691,13 @@ static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_
 
                if ('_' == c->c
                                || '-' == c->c
 
                if ('_' == c->c
                                || '-' == c->c
-                               || ('a' <= c->c && 'z' >= c->c))
+                               || ':' == c->c
+                               || ('a' <= c->c && 'z' >= c->c)) {
                        scf_string_cat_cstr_len(key, c->utf8, c->len);
                        scf_string_cat_cstr_len(key, c->utf8, c->len);
-               else {
+
+               } else if (' ' == c->c) {
+
+               } else {
                        scf_loge("invalid char '%c' in HTML attribute, file: %s, line: %d\n",
                                        c->c, html->file->data, html->n_lines);
                        free(c);
                        scf_loge("invalid char '%c' in HTML attribute, file: %s, line: %d\n",
                                        c->c, html->file->data, html->n_lines);
                        free(c);
@@ -807,9 +931,9 @@ int abc_html_parse(abc_html_t* html)
                                if ('>' == tmp)
                                        break;
 
                                if ('>' == tmp)
                                        break;
 
-                               if ('\n' == tmp) {
-                                       scf_loge("%c:%#x, html->n_lines: %d, pos: %d\n", tmp, tmp, html->n_lines, html->pos);
-                                       return -1;
+                               if ('\n' == tmp || '\r' == tmp) {
+                                       scf_logw("%#x, html->n_lines: %d, pos: %d\n", tmp, html->n_lines, html->pos);
+                                       continue;
                                }
                        }
 
                                }
                        }
 
index 48aa1674e1d7db6d0483ee3140768a4d33dc4f03..f235163c50d8daf0df27b3a0da07f66e096b1946 100644 (file)
@@ -34,7 +34,7 @@ struct abc_io_s
        void          (*close)(abc_html_t* html);
 
        int           (*popc )(abc_html_t* html);
        void          (*close)(abc_html_t* html);
 
        int           (*popc )(abc_html_t* html);
-       int           (*post )(abc_html_t* html);
+       int           (*post )(abc_html_t* html, const char* path, scf_string_t* content);
 };
 
 struct abc_html_s
 };
 
 struct abc_html_s
@@ -56,7 +56,8 @@ struct abc_html_s
 };
 
 int     abc_html_open (abc_html_t** pp, const char* path);
 };
 
 int     abc_html_open (abc_html_t** pp, const char* path);
-void abc_html_close(abc_html_t* html);
+int     abc_html_post (abc_html_t** pp, abc_html_t* form, abc_obj_t* submit);
+void abc_html_close(abc_html_t*  html);
 
 int  abc_html_parse(abc_html_t* html);
 
 
 int  abc_html_parse(abc_html_t* html);
 
index d62afd5000e0d144fbd4c21d4982ac809eced81c..1d6b246eba82dea2faf0742404733cb6a3a415d1 100644 (file)
@@ -14,6 +14,9 @@ typedef struct {
 
        int              content_length;
 
 
        int              content_length;
 
+       int              cpos;
+       uint32_t         chunk_flag:1;
+
        int              exit;
        pthread_t        tid;
        pthread_mutex_t  mutex;
        int              exit;
        pthread_t        tid;
        pthread_mutex_t  mutex;
@@ -34,13 +37,22 @@ static void http_parse_head(abc_http_t* http)
                        continue;
                }
 
                        continue;
                }
 
-               size_t n = strlen("Content-Length: ");
+               size_t i = strlen("Content-Length: ");
+               size_t j = strlen("Transfer-Encoding: chunked");
 
 
-               if (!strncmp(p0, "Content-Length: ", n)) {
-                       http->content_length = atoi(p0 + n);
+               if (!strncmp(p0, "Content-Length: ", i)) {
+                       http->content_length = atoi(p0 + i);
+                       http->chunk_flag = 0;
 
                        scf_logi("Content-Length: %d\n", http->content_length);
                        break;
 
                        scf_logi("Content-Length: %d\n", http->content_length);
                        break;
+
+               } else if (!strncmp(p0, "Transfer-Encoding: chunked", j)) {
+                       http->content_length = 0;
+                       http->chunk_flag = 1;
+
+                       scf_logi("Transfer-Encoding: chunked\n");
+                       break;
                }
 
                p1 += 2;
                }
 
                p1 += 2;
@@ -48,6 +60,78 @@ static void http_parse_head(abc_http_t* http)
        }
 }
 
        }
 }
 
+static void http_chunk_size(abc_http_t* http)
+{
+       while (http->cpos < http->rbuf->len) {
+
+               uint8_t* p = http->rbuf->data + http->cpos;
+
+               if ('0' <= *p && *p <= '9') {
+
+                       http->content_length <<= 4;
+                       http->content_length  += *p - '0';
+
+               } else if ('a' <= *p && *p <= 'f') {
+
+                       http->content_length <<= 4;
+                       http->content_length  += *p - 'a' + 10;
+
+               } else if ('A' <= *p && *p <= 'F') {
+
+                       http->content_length <<= 4;
+                       http->content_length  += *p - 'A' + 10;
+               } else
+                       break;
+
+               *p = '\n';
+
+               http->cpos++;
+       }
+}
+
+static int http_filter_chunk(abc_html_t* html)
+{
+       abc_http_t* http = html->io.priv;
+
+       if (html->download)
+               return 0;
+
+       while (http->cpos < http->rbuf->len) {
+
+               http_chunk_size(http);
+
+               if (strncmp(http->rbuf->data + http->cpos, "\r\n", 2))
+                       return 0;
+
+               scf_logi("rbuf->len: %ld, http->cpos: %d, http->content_length: %#x\n", http->rbuf->len, http->cpos, http->content_length);
+
+               http->cpos += 2;
+
+               if (0 == http->content_length) {
+                       html->download = 1;
+                       return 0;
+               }
+
+               if (http->cpos +  http->content_length + 2 <= http->rbuf->len) {
+
+                       http->cpos += http->content_length;
+                       http->content_length = 0;
+
+                       uint8_t* p = http->rbuf->data + http->cpos;
+
+                       if (strncmp(p, "\r\n", 2)) {
+                               scf_loge("*p: %d\n", *p);
+                               return -1;
+                       }
+
+                       http->cpos += 2;
+               } else
+                       break;
+       }
+
+       return 0;
+}
+
 static void* http_thread(void* arg)
 {
        abc_html_t* html = arg;
 static void* http_thread(void* arg)
 {
        abc_html_t* html = arg;
@@ -98,6 +182,7 @@ static void* http_thread(void* arg)
 
                                                if (!strncmp(http->rbuf->data + i, "\r\n\r\n", 4)) {
                                                        http->rpos = i + 4;
 
                                                if (!strncmp(http->rbuf->data + i, "\r\n\r\n", 4)) {
                                                        http->rpos = i + 4;
+                                                       http->cpos = http->rpos;
 
                                                        http_parse_head(http);
                                                        break;
 
                                                        http_parse_head(http);
                                                        break;
@@ -106,13 +191,17 @@ static void* http_thread(void* arg)
                                }
 
                                if (http->rpos > 0) {
                                }
 
                                if (http->rpos > 0) {
-                                       if (http->content_length >= 0) {
+                                       if (!http->chunk_flag) {
                                                if (http->content_length == http->rbuf->len - http->rpos) {
                                                        html->download = 1;
 
                                                        scf_logi("http response: %s\n", http->rbuf->data);
                                                }
                                        } else {
                                                if (http->content_length == http->rbuf->len - http->rpos) {
                                                        html->download = 1;
 
                                                        scf_logi("http response: %s\n", http->rbuf->data);
                                                }
                                        } else {
+                                               http_filter_chunk(html);
+
+                                               if (html->download)
+                                                       scf_logi("http response: %s\n", http->rbuf->data);
                                        }
                                }
 
                                        }
                                }
 
@@ -213,9 +302,9 @@ static int __http_parse(abc_http_t* http, const char* path)
        return 0;
 }
 
        return 0;
 }
 
-static int __http_open(abc_html_t* html, const char* path)
+static int __http_open2(abc_http_t** pp, const char* path)
 {
 {
-       if (!html || !path)
+       if (!path)
                return -EINVAL;
 
        scf_logw("\n");
                return -EINVAL;
 
        scf_logw("\n");
@@ -286,6 +375,23 @@ static int __http_open(abc_html_t* html, const char* path)
                return -ENOMEM;
        }
 
                return -ENOMEM;
        }
 
+       *pp = http;
+       return 0;
+}
+
+static int __http_open(abc_html_t* html, const char* path)
+{
+       if (!html || !path)
+               return -EINVAL;
+
+       abc_http_t* http = NULL;
+
+       int ret = __http_open2(&http, path);
+       if (ret < 0) {
+               scf_loge("open http url '%s' failed\n", path);
+               return ret;
+       }
+
 #define ABC_HTTP_FILL(str) \
        do { \
                ret = scf_string_cat_cstr(http->wbuf, str); \
 #define ABC_HTTP_FILL(str) \
        do { \
                ret = scf_string_cat_cstr(http->wbuf, str); \
@@ -319,6 +425,52 @@ static int __http_open(abc_html_t* html, const char* path)
        return 0;
 }
 
        return 0;
 }
 
+static int __http_post(abc_html_t* html, const char* path, scf_string_t* content)
+{
+       if (!html || !path || !content)
+               return -EINVAL;
+
+       abc_http_t* http = NULL;
+
+       int ret = __http_open2(&http, path);
+       if (ret < 0) {
+               scf_loge("open http url '%s' failed\n", path);
+               return ret;
+       }
+
+       ABC_HTTP_FILL("POST ");
+       ABC_HTTP_FILL(http->uri->data);
+       ABC_HTTP_FILL(" HTTP/1.1\r\n");
+
+       ABC_HTTP_FILL("Host: ");
+       ABC_HTTP_FILL(http->host->data);
+       ABC_HTTP_FILL("\r\n");
+
+       char buf[128];
+       snprintf(buf, sizeof(buf) - 1, "%ld", content->len);
+
+       ABC_HTTP_FILL("Content-Length: ");
+       ABC_HTTP_FILL(buf);
+       ABC_HTTP_FILL("\r\n");
+
+       ABC_HTTP_FILL("User-Agent: advanced-browser-core\r\n");
+       ABC_HTTP_FILL("Accept: */*\r\n");
+       ABC_HTTP_FILL("\r\n");
+
+       ABC_HTTP_FILL(content->data);
+
+       html->io.priv = http;
+
+       if (pthread_create(&http->tid, NULL, http_thread, html)) {
+               abc_http_close(http);
+               html->io.priv = NULL;
+               return -1;
+       }
+
+       scf_logw("\n");
+       return 0;
+}
+
 static void __http_close(abc_html_t* html)
 {
        if (html)
 static void __http_close(abc_html_t* html)
 {
        if (html)
@@ -350,12 +502,6 @@ static int __http_popc(abc_html_t* html)
        return EOF;
 }
 
        return EOF;
 }
 
-static int __http_post(abc_html_t* html)
-{
-       scf_loge("\n");
-       return -1;
-}
-
 abc_io_t  abc_io_http =
 {
        .proto = "http://",
 abc_io_t  abc_io_http =
 {
        .proto = "http://",
index f268cba6c226ce16bcd2f88a605241a78c39eb0a..8c493289dc59c562e9bb5dd14b4f5cf21e6f3345 100644 (file)
@@ -165,3 +165,122 @@ void abc_obj_print(abc_obj_t* obj)
                        printf("</%s>\n", obj->keys[0]);
        }
 }
                        printf("</%s>\n", obj->keys[0]);
        }
 }
+
+static int __abc_obj_to_string(abc_obj_t* obj, scf_string_t* s)
+{
+       scf_list_t*   l;
+       abc_obj_t*    attr;
+       abc_obj_t*    child;
+
+       int ret;
+
+       if (!obj)
+               return 0;
+
+       if (obj->value) {
+               ret = scf_string_cat_cstr(s, " ");
+               if (ret < 0)
+                       return ret;
+
+               ret = scf_string_cat_cstr(s, obj->keys[0]);
+               if (ret < 0)
+                       return ret;
+
+               ret = scf_string_cat_cstr(s, "=\"");
+               if (ret < 0)
+                       return ret;
+
+               ret = scf_string_cat(s, obj->value);
+               if (ret < 0)
+                       return ret;
+
+               ret = scf_string_cat_cstr(s, "\"");
+               if (ret < 0)
+                       return ret;
+
+       } else if (obj->keys) {
+               ret = scf_string_cat_cstr(s, "<");
+               if (ret < 0)
+                       return ret;
+
+               ret = scf_string_cat_cstr(s, obj->keys[0]);
+               if (ret < 0)
+                       return ret;
+       }
+
+       for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
+               attr = scf_list_data(l, abc_obj_t, list);
+
+               if (ABC_HTML_FLAG_SHOW & attr->flags) {
+                       ret = __abc_obj_to_string(attr, s);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       if (!obj->value) {
+               if (obj->flags & ABC_HTML_FLAG_SINGLE) {
+
+                       ret = scf_string_cat_cstr(s, " />\n");
+                       if (ret < 0)
+                               return ret;
+
+               } else if (obj->keys) {
+                       ret = scf_string_cat_cstr(s, ">\n");
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       if (obj->text) {
+               ret = scf_string_cat(s, obj->text);
+               if (ret < 0)
+                       return ret;
+
+               ret = scf_string_cat_cstr(s, "\n");
+               if (ret < 0)
+                       return ret;
+       }
+
+       for (l = scf_list_head(&obj->childs); l != scf_list_sentinel(&obj->childs); l = scf_list_next(l)) {
+               child = scf_list_data(l, abc_obj_t, list);
+
+               ret = __abc_obj_to_string(child, s);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (ABC_HTML_FLAG_CLOSE == (obj->flags & (ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SINGLE))) {
+               if (obj->keys) {
+                       ret = scf_string_cat_cstr(s, "</");
+                       if (ret < 0)
+                               return ret;
+
+                       ret = scf_string_cat_cstr(s, obj->keys[0]);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = scf_string_cat_cstr(s, ">\n");
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+scf_string_t* abc_obj_to_string(abc_obj_t* obj)
+{
+       scf_string_t*  s = scf_string_alloc();
+       if (!s)
+               return NULL;
+
+       int ret = __abc_obj_to_string(obj, s);
+       if (ret < 0) {
+               scf_string_free(s);
+               return NULL;
+       }
+
+       scf_logi("%s\n", s->data);
+       return s;
+}
index ac7b04ca69b2801537f4edc0aeb97590568ebc36..4780ca0f47555acbe5cbce31292486f569854be9 100644 (file)
@@ -32,7 +32,7 @@ enum abc_objs
        ABC_HTML_A,
        ABC_HTML_A_HREF,
 
        ABC_HTML_A,
        ABC_HTML_A_HREF,
 
-       // 15
+       // 16
        ABC_HTML_IMG,
 
        ABC_HTML_FORM,
        ABC_HTML_IMG,
 
        ABC_HTML_FORM,
@@ -40,6 +40,12 @@ enum abc_objs
        ABC_HTML_INPUT,
        ABC_HTML_CENTER,
 
        ABC_HTML_INPUT,
        ABC_HTML_CENTER,
 
+       ABC_HTML_META,
+
+       ABC_HTML_TABLE,
+       ABC_HTML_TR,
+       ABC_HTML_TD,
+
        ABC_HTML_NB, // total HTML objects
 
        ABC_HTML_ATTR_ID,
        ABC_HTML_NB, // total HTML objects
 
        ABC_HTML_ATTR_ID,
@@ -61,6 +67,16 @@ enum abc_objs
 
        ABC_HTML_ATTR_WIDTH,
        ABC_HTML_ATTR_HEIGHT,
 
        ABC_HTML_ATTR_WIDTH,
        ABC_HTML_ATTR_HEIGHT,
+
+       ABC_HTML_ATTR_XMLNS,
+       ABC_HTML_ATTR_XMLANG,
+       ABC_HTML_ATTR_LANG,
+
+       ABC_HTML_ATTR_HTTP_EQUIV,
+       ABC_HTML_ATTR_CONTENT,
+       ABC_HTML_ATTR_CHARSET,
+
+       ABC_HTML_ATTR_ENCTYPE,
 };
 
 struct abc_obj_s
 };
 
 struct abc_obj_s
@@ -101,13 +117,15 @@ struct abc_obj_s
        uint32_t        clicked:1;
 };
 
        uint32_t        clicked:1;
 };
 
-abc_obj_t*  abc_obj_alloc(scf_string_t* file, int line, int pos, int type);
-void        abc_obj_free (abc_obj_t*    obj);
-abc_obj_t*  abc_obj_find (abc_obj_t*    root, int x, int y);
-void        abc_obj_print(abc_obj_t*    obj);
+abc_obj_t*     abc_obj_alloc(scf_string_t* file, int line, int pos, int type);
+void           abc_obj_free (abc_obj_t*    obj);
+abc_obj_t*     abc_obj_find (abc_obj_t*    root, int x, int y);
+void           abc_obj_print(abc_obj_t*    obj);
+
+int            abc_obj_set_attr (abc_obj_t* obj, int key, const char* value);
+abc_obj_t*     abc_obj_get_attr (abc_obj_t* obj, int key);
+abc_obj_t*     abc_obj_find_attr(abc_obj_t* obj, int key);
 
 
-int         abc_obj_set_attr (abc_obj_t* obj, int key, const char* value);
-abc_obj_t*  abc_obj_get_attr (abc_obj_t* obj, int key);
-abc_obj_t*  abc_obj_find_attr(abc_obj_t* obj, int key);
+scf_string_t*  abc_obj_to_string(abc_obj_t* obj);
 
 #endif
 
 #endif
index e7bce377068559c95a885130b09bddbedc2e96de..151157060b7d4a745665101e97afa55b91c5f3a4 100644 (file)
@@ -13,6 +13,11 @@ typedef struct {
 
 typedef struct {
        ngx_http_status_t  status;
 
 typedef struct {
        ngx_http_status_t  status;
+
+       ngx_int_t          chunk_CRLF;
+       ngx_int_t          chunk_size;
+       ngx_int_t          chunk_pos;
+       ngx_int_t          chunked;
 } ngx_http_abc_ctx_t;
 
 #endif
 } ngx_http_abc_ctx_t;
 
 #endif
index 14ad489edb6b842c2eb0cf30667e72f20ffcab48..fc8a509c82eba6a5f6b94b5af7de9977ff07ecee 100644 (file)
@@ -2,69 +2,56 @@
 #include <ngx_core.h>
 #include <ngx_http.h>
 #include "ngx_http_abc.h"
 #include <ngx_core.h>
 #include <ngx_http.h>
 #include "ngx_http_abc.h"
-#if 0
+
 static void ngx_http_abc_body_handler(ngx_http_request_t *r)
 {
 static void ngx_http_abc_body_handler(ngx_http_request_t *r)
 {
-       ngx_chain_t  out;
-       ngx_buf_t*   b;
-       ngx_int_t    rc;
-
-       ngx_str_t    type = ngx_string("text/html");
-       ngx_str_t    body = ngx_string("<html><head><title>hello</title></head><body><h1>hello world</h1></body></html>");
-
-       r->headers_out.status           = NGX_HTTP_OK;
-       r->headers_out.content_length_n = body.len;
-       r->headers_out.content_type     = type;
-
-       rc = ngx_http_send_header(r);
-
-       printf("%s(),%d, rc: %ld\n", __func__, __LINE__, rc);
-
-       if (NGX_ERROR == rc || rc > NGX_OK || r->header_only) {
-               ngx_http_finalize_request(r, rc);
-               return;
-       }
-
-       b = ngx_create_temp_buf(r->pool, body.len);
-       if (!b) {
-               ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-               return;
-       }
-
-       ngx_memcpy(b->pos, body.data, body.len);
-
-       b->last     = b->pos + body.len;
-       b->last_buf = 1;
-
-       out.buf  = b;
-       out.next = NULL;
-
-       rc = ngx_http_output_filter(r, &out);
-
-       ngx_http_finalize_request(r, rc);
+       printf("%s(),%d\n", __func__, __LINE__);
 }
 }
-#endif
+
 static ngx_int_t abc_upstream_create_request(ngx_http_request_t *r)
 {
 static ngx_int_t abc_upstream_create_request(ngx_http_request_t *r)
 {
-       printf("%s(),%d\n", __func__, __LINE__);
-       ngx_buf_t*  b;
-       size_t      len;
+       ngx_chain_t* cl;
+       ngx_buf_t*   b;
+       size_t       len;
 
 
-       len  = strlen("GET ") + r->uri.len + strlen(" HTTP/1.1\r\n");
+       len  = r->method_name.len + 1 + r->uri.len + strlen(" HTTP/1.1\r\n");
        len += strlen("Host: localhost\r\n");
        len += strlen("User-Agent: nginx/1.20.0\r\n");
        len += strlen("Accept: */*\r\n");
        len += strlen("Connection: close\r\n\r\n");
 
        len += strlen("Host: localhost\r\n");
        len += strlen("User-Agent: nginx/1.20.0\r\n");
        len += strlen("Accept: */*\r\n");
        len += strlen("Connection: close\r\n\r\n");
 
+       if (r->request_body) {
+               len += strlen("Content-Length: \r\n") + r->headers_in.content_length->value.len;
+
+               for (cl = r->request_body->bufs; cl; cl = cl->next) {
+
+                       len += (size_t)(cl->buf->last - cl->buf->pos);
+               }
+       }
+
+       printf("%s(),%d, len: %ld\n", __func__, __LINE__, len);
+
        b = ngx_create_temp_buf(r->pool, len);
        if (!b)
                return NGX_ERROR;
 
        b->last = b->pos + len;
 
        b = ngx_create_temp_buf(r->pool, len);
        if (!b)
                return NGX_ERROR;
 
        b->last = b->pos + len;
 
-       printf("%s(),%d, len: %ld\n", __func__, __LINE__, len);
+       u_char* p = ngx_snprintf(b->pos, len, "%V %V HTTP/1.1\r\nHost: localhost\r\nUser-Agent: nginx/1.20.0\r\nAccept: */*\r\nConnection: close\r\n\r\n", &r->method_name, &r->uri);
+
+       if (r->request_body) {
+               p = ngx_snprintf(p - 2, len, "Content-Length: %V\r\n\r\n", &r->headers_in.content_length->value);
+
+               for (cl = r->request_body->bufs; cl; cl = cl->next) {
+
+                       len = (size_t)(cl->buf->last - cl->buf->pos);
 
 
-       ngx_snprintf(b->pos, len, "GET %V HTTP/1.1\r\nHost: localhost\r\nUser-Agent: nginx/1.20.0\r\nAccept: */*\r\nConnection: close\r\n\r\n", &r->uri);
+                       printf("%s(),%d, cl->buf->len: %ld\n", __func__, __LINE__, len);
+
+                       ngx_memcpy(p, cl->buf->pos, len);
+                       p += len;
+               }
+       }
 
        r->upstream->request_bufs = ngx_alloc_chain_link(r->pool);
        if (!r->upstream->request_bufs)
 
        r->upstream->request_bufs = ngx_alloc_chain_link(r->pool);
        if (!r->upstream->request_bufs)
@@ -73,6 +60,7 @@ static ngx_int_t abc_upstream_create_request(ngx_http_request_t *r)
        r->upstream->request_bufs->buf  = b;
        r->upstream->request_bufs->next = NULL;
 
        r->upstream->request_bufs->buf  = b;
        r->upstream->request_bufs->next = NULL;
 
+       r->upstream->request_body_sent = 0;
        r->upstream->request_sent = 0;
        r->upstream->header_sent  = 0;
        r->header_hash = 1;
        r->upstream->request_sent = 0;
        r->upstream->header_sent  = 0;
        r->header_hash = 1;
@@ -87,6 +75,7 @@ static ngx_int_t abc_upstream_process_header(ngx_http_request_t *r)
        ngx_http_upstream_main_conf_t*  umcf;
        ngx_http_upstream_header_t*     uh;
        ngx_http_upstream_t*            u;
        ngx_http_upstream_main_conf_t*  umcf;
        ngx_http_upstream_header_t*     uh;
        ngx_http_upstream_t*            u;
+       ngx_http_abc_ctx_t*             ctx;
        ngx_table_elt_t*                h;
        ngx_int_t                       rc;
 
        ngx_table_elt_t*                h;
        ngx_int_t                       rc;
 
@@ -117,6 +106,11 @@ static ngx_int_t abc_upstream_process_header(ngx_http_request_t *r)
                        ngx_memcpy(h->value.data,  r->header_start,      h->value.len);
                        ngx_strlow(h->lowcase_key, h->key.data,          h->key.len);
 
                        ngx_memcpy(h->value.data,  r->header_start,      h->value.len);
                        ngx_strlow(h->lowcase_key, h->key.data,          h->key.len);
 
+                       if (!ngx_strcmp(h->key.data, "Transfer-Encoding") && !ngx_strcmp(h->value.data, "chunked")) {
+                               ctx = ngx_http_get_module_ctx(r, ngx_http_abc_module);
+                               ctx->chunked = 1;
+                       }
+
                        uint8_t buf[1024] = {0};
                        ngx_snprintf(buf, 1023, "%V: %V\n", &h->key, &h->value);
                        printf("%s(),%d, %s\n", __func__, __LINE__, buf);
                        uint8_t buf[1024] = {0};
                        ngx_snprintf(buf, 1023, "%V: %V\n", &h->key, &h->value);
                        printf("%s(),%d, %s\n", __func__, __LINE__, buf);
@@ -207,6 +201,168 @@ static ngx_int_t abc_upstream_process_status(ngx_http_request_t *r)
 static void abc_upstream_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
 {
        printf("%s(),%d\n\n", __func__, __LINE__);
 static void abc_upstream_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
 {
        printf("%s(),%d\n\n", __func__, __LINE__);
+
+       if (NGX_HTTP_POST & r->method)
+               ngx_http_finalize_request(r, rc);
+}
+
+static ngx_int_t abc_input_filter_init(void *data)
+{
+       return NGX_OK;
+}
+
+static ngx_int_t abc_input_filter(void *data, ssize_t bytes)
+{
+    ngx_http_request_t  *r = data;
+
+    ngx_buf_t            *b;
+    ngx_chain_t          *cl, **ll;
+    ngx_chain_t          *cl2;
+    ngx_http_upstream_t  *u;
+       ngx_http_abc_ctx_t   *ctx;
+
+       ctx = ngx_http_get_module_ctx(r, ngx_http_abc_module);
+
+    u = r->upstream;
+
+    if (u->length == 0) {
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "upstream sent more data than specified in "
+                      "\"Content-Length\" header");
+        return NGX_OK;
+    }
+
+    for (cl = u->out_bufs, ll = &u->out_bufs; cl; cl = cl->next) {
+        ll = &cl->next;
+    }
+
+    cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
+    if (cl == NULL) {
+        return NGX_ERROR;
+    }
+
+    *ll = cl;
+
+    cl->buf->flush = 1;
+    cl->buf->memory = 1;
+
+    b = &u->buffer;
+
+    cl->buf->pos = b->last;
+    b->last += bytes;
+    cl->buf->last = b->last;
+    cl->buf->tag = u->output.tag;
+
+       if (u->length == -1) {
+
+               if (!ctx->chunked)
+                       return NGX_OK;
+
+               u_char* p = cl->buf->pos;
+               u_char  ch;
+
+               while (p < b->last) {
+                       if (ctx->chunk_CRLF < 2) {
+
+                               ch = *p++;
+                               cl->buf->pos = p;
+
+                               printf("%s(),%d, ctx->chunk_size: %ld,%#lx, ch: %d,%c\n", __func__, __LINE__, ctx->chunk_size, ctx->chunk_size, ch, ch);
+
+                               if ('0' <= ch && ch <= '9') {
+
+                                       ctx->chunk_size <<= 4;
+                                       ctx->chunk_size  += ch - '0';
+
+                               } else if ('a' <= ch && ch <= 'f') {
+
+                                       ctx->chunk_size <<= 4;
+                                       ctx->chunk_size  += ch - 'a' + 10;
+
+                               } else if ('A' <= ch && ch <= 'F') {
+
+                                       ctx->chunk_size <<= 4;
+                                       ctx->chunk_size  += ch - 'A' + 10;
+                               } else {
+                                       if ('\r' == ch || '\n' == ch)
+                                               ctx->chunk_CRLF++;
+                               }
+                       } else {
+                               ngx_int_t len = (size_t)(b->last - p);
+
+                               if (ctx->chunk_pos +  len <= ctx->chunk_size) {
+                                       printf("%s(),%d, ctx->chunk_size: %ld,%#lx, len: %ld\n", __func__, __LINE__, ctx->chunk_size, ctx->chunk_size, len);
+                                       ctx->chunk_pos += len;
+                                       p += len;
+                               } else if (ctx->chunk_CRLF < 3) {
+                                       ctx->chunk_CRLF++;
+
+                                       len = ctx->chunk_size - ctx->chunk_pos;
+                                       p  += len;
+
+                                       ctx->chunk_pos += len;
+                                       printf("%s(),%d, ctx->chunk_size: %ld,%#lx, len: %ld\n", __func__, __LINE__, ctx->chunk_size, ctx->chunk_size, len);
+
+                                       if (len > 0) {
+                                               cl->buf->last = p;
+
+                                               cl2 = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
+                                               if (NULL == cl2)
+                                                       return NGX_ERROR;
+
+                                               cl2->buf->flush = 1;
+                                               cl2->buf->memory = 1;
+
+                                               cl2->buf->pos  = p;
+                                               cl2->buf->last = b->last;
+                                               cl2->buf->tag  = u->output.tag;
+
+                                               ll  = &cl->next;
+                                               *ll = cl2;
+                                               cl  = cl2;
+                                       }
+                               } else {
+                                       ch = *p++;
+
+                                       cl->buf->pos++;
+                                       ctx->chunk_CRLF++;
+
+                                       printf("%s(),%d, ctx->chunk_size: %ld,%#lx, len: %ld, ch: %d\n", __func__, __LINE__, ctx->chunk_size, ctx->chunk_size, len, ch);
+
+                                       if (ctx->chunk_CRLF >= 5) {
+                                               ctx->chunk_CRLF  = 0;
+                                               ctx->chunk_size  = 0;
+                                               ctx->chunk_pos   = 0;
+                                       }
+
+                                       if (cl->buf->pos == cl->buf->last) {
+                                               //printf("%s(),%d, 0 size buf: %p, p == b->last: %d\n", __func__, __LINE__, cl, p == b->last);
+                                               *ll = NULL;
+                                               ngx_free_chain(r->pool, cl);
+                                               cl = NULL;
+                                       }
+                               }
+                       }
+               }
+
+        return NGX_OK;
+    }
+
+    if (bytes > u->length) {
+
+        ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+                      "upstream sent more data than specified in "
+                      "\"Content-Length\" header");
+
+        cl->buf->last = cl->buf->pos + u->length;
+        u->length = 0;
+
+        return NGX_OK;
+    }
+
+    u->length -= bytes;
+
+    return NGX_OK;
 }
 
 static ngx_int_t ngx_http_abc_handler(ngx_http_request_t *r)
 }
 
 static ngx_int_t ngx_http_abc_handler(ngx_http_request_t *r)
@@ -218,15 +374,23 @@ static ngx_int_t ngx_http_abc_handler(ngx_http_request_t *r)
        ngx_http_abc_ctx_t*   ctx;
        ngx_int_t             rc;
 
        ngx_http_abc_ctx_t*   ctx;
        ngx_int_t             rc;
 
-       if (!(r->method & (NGX_HTTP_GET | NGX_HTTP_POST)))
-               return NGX_HTTP_NOT_ALLOWED;
+       if (r->method & NGX_HTTP_GET) {
 
 
-       r->request_body_in_file_only = 1;
+               rc = ngx_http_discard_request_body(r);
+               if (rc != NGX_OK)
+                       return rc;
 
 
-//     rc = ngx_http_read_client_request_body(r, ngx_http_abc_body_handler);
-       rc = ngx_http_discard_request_body(r);
-       if (rc != NGX_OK)
-               return rc;
+       } else if (r->method & NGX_HTTP_POST) {
+               r->request_body_no_buffering = 1;
+
+               rc = ngx_http_read_client_request_body(r, ngx_http_abc_body_handler);
+
+               if (rc != NGX_OK && rc != NGX_AGAIN) {
+                       printf("%s(),%d, rc: %ld\n", __func__, __LINE__, rc);
+                       return rc;
+               }
+       } else
+               return NGX_HTTP_NOT_ALLOWED;
 
        ctx = ngx_http_get_module_ctx(r, ngx_http_abc_module);
        if (!ctx) {
 
        ctx = ngx_http_get_module_ctx(r, ngx_http_abc_module);
        if (!ctx) {
@@ -240,6 +404,11 @@ static ngx_int_t ngx_http_abc_handler(ngx_http_request_t *r)
                ctx->status.count = 0;
                ctx->status.start = NULL;
                ctx->status.end   = NULL;
                ctx->status.count = 0;
                ctx->status.start = NULL;
                ctx->status.end   = NULL;
+
+               ctx->chunk_CRLF = 0;
+               ctx->chunk_size = 0;
+               ctx->chunk_pos  = 0;
+               ctx->chunked    = 0;
        }
 
        if (ngx_http_upstream_create(r) != NGX_OK)
        }
 
        if (ngx_http_upstream_create(r) != NGX_OK)
@@ -266,15 +435,19 @@ static ngx_int_t ngx_http_abc_handler(ngx_http_request_t *r)
 
     u->resolved->port = 80;
 
 
     u->resolved->port = 80;
 
-       u->create_request   = abc_upstream_create_request;
-       u->process_header   = abc_upstream_process_status;
-       u->finalize_request = abc_upstream_finalize_request;
+       u->create_request    = abc_upstream_create_request;
+       u->process_header    = abc_upstream_process_status;
+       u->finalize_request  = abc_upstream_finalize_request;
+
+       u->input_filter_init = abc_input_filter_init;
+       u->input_filter      = abc_input_filter;
+       u->input_filter_ctx  = r;
 
        r->main->count++;
 
        ngx_http_upstream_init(r);
 
 
        r->main->count++;
 
        ngx_http_upstream_init(r);
 
-       printf("%s(),%d, subrequest_in_memory: %d\n", __func__, __LINE__, r->subrequest_in_memory);
+       printf("%s(), %d, done\n", __func__, __LINE__);
        return NGX_DONE;
 }
 
        return NGX_DONE;
 }
 
index 73e05081390488db3e89ab5604b8426fafc3b25d..cc9fd71ede2f7101d3c7c9be6d26f3e9a2beb17b 100644 (file)
@@ -12,13 +12,16 @@ CFILES += abc_layout_img.c
 CFILES += abc_layout_form.c
 CFILES += abc_layout_label.c
 CFILES += abc_layout_input.c
 CFILES += abc_layout_form.c
 CFILES += abc_layout_label.c
 CFILES += abc_layout_input.c
+CFILES += abc_layout_td.c
 
 CFILES += abc_render.c
 CFILES += abc_render_html.c
 CFILES += abc_render_title.c
 
 CFILES += abc_render.c
 CFILES += abc_render_html.c
 CFILES += abc_render_title.c
+CFILES += abc_render_meta.c
 CFILES += abc_render_head.c
 CFILES += abc_render_body.c
 CFILES += abc_render_div.c
 CFILES += abc_render_head.c
 CFILES += abc_render_body.c
 CFILES += abc_render_div.c
+
 CFILES += abc_render_h1.c
 CFILES += abc_render_a.c
 CFILES += abc_render_a_href.c
 CFILES += abc_render_h1.c
 CFILES += abc_render_a.c
 CFILES += abc_render_a_href.c
@@ -27,6 +30,10 @@ CFILES += abc_render_form.c
 CFILES += abc_render_label.c
 CFILES += abc_render_input.c
 
 CFILES += abc_render_label.c
 CFILES += abc_render_input.c
 
+CFILES += abc_render_table.c
+CFILES += abc_render_tr.c
+CFILES += abc_render_td.c
+
 CFILES += ../html/abc_html.c
 CFILES += ../html/abc_html_util.c
 CFILES += ../html/abc_obj.c
 CFILES += ../html/abc_html.c
 CFILES += ../html/abc_html_util.c
 CFILES += ../html/abc_obj.c
index 0918e106cd55cb5b6f2d9f7877431fc1f494f7a7..4411a10d135246c2ae0efd383a93efbcf9d499af 100644 (file)
@@ -14,6 +14,13 @@ int abc_layout_form (abc_layout_t* layout, abc_obj_t* obj, int width, int height
 int abc_layout_label(abc_layout_t* layout, abc_obj_t* obj, int width, int height);
 int abc_layout_input(abc_layout_t* layout, abc_obj_t* obj, int width, int height);
 
 int abc_layout_label(abc_layout_t* layout, abc_obj_t* obj, int width, int height);
 int abc_layout_input(abc_layout_t* layout, abc_obj_t* obj, int width, int height);
 
+int abc_layout_td   (abc_layout_t* layout, abc_obj_t* obj, int width, int height);
+
+int abc_layout_empty(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+       return 0;
+}
+
 static abc_layout_pt abc_layouts[ABC_HTML_NB] =
 {
        [ABC_HTML]         = abc_layout_html,
 static abc_layout_pt abc_layouts[ABC_HTML_NB] =
 {
        [ABC_HTML]         = abc_layout_html,
@@ -22,6 +29,8 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] =
        [ABC_HTML_BODY]    = abc_layout_body,
        [ABC_HTML_DIV]     = abc_layout_div,
 
        [ABC_HTML_BODY]    = abc_layout_body,
        [ABC_HTML_DIV]     = abc_layout_div,
 
+       [ABC_HTML_META]    = abc_layout_empty,
+
        [ABC_HTML_H1]      = abc_layout_h1,
        [ABC_HTML_H2]      = abc_layout_h1,
        [ABC_HTML_H3]      = abc_layout_h1,
        [ABC_HTML_H1]      = abc_layout_h1,
        [ABC_HTML_H2]      = abc_layout_h1,
        [ABC_HTML_H3]      = abc_layout_h1,
@@ -38,6 +47,10 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] =
        [ABC_HTML_FORM]    = abc_layout_form,
        [ABC_HTML_LABEL]   = abc_layout_label,
        [ABC_HTML_INPUT]   = abc_layout_input,
        [ABC_HTML_FORM]    = abc_layout_form,
        [ABC_HTML_LABEL]   = abc_layout_label,
        [ABC_HTML_INPUT]   = abc_layout_input,
+
+       [ABC_HTML_TABLE]   = abc_layout_empty,
+       [ABC_HTML_TR]      = abc_layout_empty,
+       [ABC_HTML_TD]      = abc_layout_td,
 };
 
 int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
 };
 
 int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
@@ -96,6 +109,7 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height)
                                break;
 
                        case ABC_HTML_BR:
                                break;
 
                        case ABC_HTML_BR:
+                       case ABC_HTML_TR:
                                x  = root->x + 4;
                                y += h;
                                h  = 0;
                                x  = root->x + 4;
                                y += h;
                                h  = 0;
index 2242bf88bcb4194e09adcbd5ec8e7332b8f2aba6..56f7032c5d11a6540ba7cfbb57a1430d8d74a526 100644 (file)
@@ -32,7 +32,7 @@ int abc_layout_h1(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
        obj->w = (obj->w + 3) & ~0x3;
        obj->h = (obj->h + 3) & ~0x3;
 
        obj->w = (obj->w + 3) & ~0x3;
        obj->h = (obj->h + 3) & ~0x3;
 
-       scf_logi("%s, w: %d, h: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg\n",
+       scf_logd("%s, w: %d, h: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg\n",
                        obj->text->data, obj->w, obj->h,
                        extents.x_bearing, extents.y_bearing, extents.width, extents.height,
                        extents.x_advance, extents.y_advance);
                        obj->text->data, obj->w, obj->h,
                        extents.x_bearing, extents.y_bearing, extents.width, extents.height,
                        extents.x_advance, extents.y_advance);
diff --git a/ui/abc_layout_td.c b/ui/abc_layout_td.c
new file mode 100644 (file)
index 0000000..73d9410
--- /dev/null
@@ -0,0 +1,43 @@
+#include"abc.h"
+
+int abc_layout_td(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       if (!obj->text)
+               return 0;
+
+       surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+       cr      = cairo_create(surface);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, obj->text->data, &extents);
+
+//     obj->x = 4;
+//     obj->y = 4;
+       obj->w = extents.width  + extents.x_bearing;
+       obj->h = extents.height + extents.height / 2;
+
+       obj->w = (obj->w + 3) & ~0x3;
+       obj->h = (obj->h + 3) & ~0x3;
+
+       scf_logd("%s, w: %d, h: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg\n",
+                       obj->text->data, obj->w, obj->h,
+                       extents.x_bearing, extents.y_bearing, extents.width, extents.height,
+                       extents.x_advance, extents.y_advance);
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       return 0;
+}
index 0b7960d4cd30207fe695f01be3b93c8b8f66ed94..81d433418d76c17ecd0f54c7572c154b67977b07 100644 (file)
@@ -5,6 +5,7 @@ extern abc_render_t  abc_render_title;
 extern abc_render_t  abc_render_head;
 extern abc_render_t  abc_render_body;
 
 extern abc_render_t  abc_render_head;
 extern abc_render_t  abc_render_body;
 
+extern abc_render_t  abc_render_meta;
 extern abc_render_t  abc_render_div;
 extern abc_render_t  abc_render_h1;
 
 extern abc_render_t  abc_render_div;
 extern abc_render_t  abc_render_h1;
 
@@ -16,6 +17,11 @@ extern abc_render_t  abc_render_form;
 extern abc_render_t  abc_render_label;
 extern abc_render_t  abc_render_input;
 
 extern abc_render_t  abc_render_label;
 extern abc_render_t  abc_render_input;
 
+extern abc_render_t  abc_render_table;
+extern abc_render_t  abc_render_tr;
+extern abc_render_t  abc_render_td;
+
+
 static abc_render_t* abc_renders[ABC_HTML_NB] =
 {
        [ABC_HTML]         = &abc_render_html,
 static abc_render_t* abc_renders[ABC_HTML_NB] =
 {
        [ABC_HTML]         = &abc_render_html,
@@ -23,6 +29,7 @@ static abc_render_t* abc_renders[ABC_HTML_NB] =
        [ABC_HTML_HEAD]    = &abc_render_head,
        [ABC_HTML_BODY]    = &abc_render_body,
        [ABC_HTML_DIV]     = &abc_render_div,
        [ABC_HTML_HEAD]    = &abc_render_head,
        [ABC_HTML_BODY]    = &abc_render_body,
        [ABC_HTML_DIV]     = &abc_render_div,
+       [ABC_HTML_META]    = &abc_render_meta,
 
        [ABC_HTML_H1]      = &abc_render_h1,
        [ABC_HTML_H2]      = &abc_render_h1,
 
        [ABC_HTML_H1]      = &abc_render_h1,
        [ABC_HTML_H2]      = &abc_render_h1,
@@ -41,6 +48,10 @@ static abc_render_t* abc_renders[ABC_HTML_NB] =
        [ABC_HTML_FORM]    = &abc_render_form,
        [ABC_HTML_LABEL]   = &abc_render_label,
        [ABC_HTML_INPUT]   = &abc_render_input,
        [ABC_HTML_FORM]    = &abc_render_form,
        [ABC_HTML_LABEL]   = &abc_render_label,
        [ABC_HTML_INPUT]   = &abc_render_input,
+
+       [ABC_HTML_TABLE]   = &abc_render_table,
+       [ABC_HTML_TR]      = &abc_render_tr,
+       [ABC_HTML_TD]      = &abc_render_td,
 };
 
 int abc_renders_fini()
 };
 
 int abc_renders_fini()
index 35031373adfa2404003e2dfc48eec8d0bf64c800..300e84cbfe858619b1eecff96459512afe7f3e45 100644 (file)
@@ -94,7 +94,7 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int
        float mvp[16];
        __compute_mvp(mvp, 0, 0, 0);
 
        float mvp[16];
        __compute_mvp(mvp, 0, 0, 0);
 
-       scf_logi("%s, x: %d, y: %d, w: %d, h: %d\n", obj->text->data, obj->x, obj->y, obj->w, obj->h);
+       scf_logd("%s, x: %d, y: %d, w: %d, h: %d\n", obj->text->data, obj->x, obj->y, obj->w, obj->h);
 
        GLfloat vert_update[] =
        {
 
        GLfloat vert_update[] =
        {
diff --git a/ui/abc_render_meta.c b/ui/abc_render_meta.c
new file mode 100644 (file)
index 0000000..d6b22cf
--- /dev/null
@@ -0,0 +1,19 @@
+#include"abc.h"
+
+static int _render_fini_meta(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_meta(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       return 0;
+}
+
+abc_render_t  abc_render_meta =
+{
+       .type = ABC_HTML_META,
+
+       .draw = _render_draw_meta,
+       .fini = _render_fini_meta,
+};
diff --git a/ui/abc_render_table.c b/ui/abc_render_table.c
new file mode 100644 (file)
index 0000000..592865e
--- /dev/null
@@ -0,0 +1,147 @@
+#include"abc.h"
+
+static const char* vert_shader =
+       "#version 330 core\n"
+       "layout(location = 0) in vec4 position; \n"
+       "layout(location = 1) in vec2 a_texCoord; \n"
+       "out vec2 v_texCoord; \n"
+       "unitable mat4 mvp; \n"
+       "void main() { \n"
+               "gl_Position = mvp * position; \n"
+               "v_texCoord  = a_texCoord; \n"
+       "} \n";
+
+static const char* frag_shader =
+       "#version 330 core\n"
+       "in  vec2 v_texCoord; \n"
+       "out vec4 outputColor; \n"
+       "unitable sampler2D tex_rgba; \n"
+       "void main() { \n"
+       "    vec2 xy = v_texCoord; \n"
+       "    vec4 v  = texture2D(tex_rgba, xy).rgba; \n"
+       "    outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
+       "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2]   = {0};
+static GLuint texture_rgba = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+
+
+static int _render_fini_table(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_table(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       if (!obj->text)
+               return 0;
+
+       if (0 == program)
+               __init_program(&program, vert_shader, frag_shader);
+
+       if (0 == vao)
+               __init_buffers(&vao, buffers);
+
+       if (0 == texture_rgba)
+               __init_texture(&texture_rgba, GL_RGBA, obj->w, obj->h, NULL);
+
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+       if (!bgra)
+               return -ENOMEM;
+
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+       cr      = cairo_create(surface);
+
+       cairo_set_line_width(cr, 1);
+       cairo_set_source_rgb(cr, 1, 1, 1);
+       cairo_rectangle(cr, 0, 0, obj->w, obj->h);
+       cairo_fill(cr);
+       cairo_stroke(cr);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, obj->text->data, &extents);
+
+       cairo_move_to  (cr, extents.x_bearing, -extents.y_bearing);
+       cairo_show_text(cr, obj->text->data);
+
+//     cairo_surface_write_to_png(surface, "tmp.png");
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       surface = NULL;
+       cr = NULL;
+
+       float mvp[16];
+       __compute_mvp(mvp, 0, 0, 0);
+
+       scf_logi("%s, x: %d, y: %d, w: %d, h: %d\n", obj->text->data, obj->x, obj->y, obj->w, obj->h);
+
+       GLfloat vert_update[] =
+       {
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+       };
+
+       glUseProgram(program);
+       uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+       uniform_mvp  = glGetUniformLocation(program, "mvp");
+
+       glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+       // board
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture  (GL_TEXTURE_2D, texture_rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+       glUniform1i(uniform_rgba, 0);
+
+       // draw
+       glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+       glBindVertexArray(vao);
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+       glBindVertexArray(0);
+       glUseProgram(0);
+
+       free(bgra);
+       return 0;
+}
+
+abc_render_t  abc_render_table =
+{
+       .type = ABC_HTML_TABLE,
+
+       .draw = _render_draw_table,
+       .fini = _render_fini_table,
+};
diff --git a/ui/abc_render_td.c b/ui/abc_render_td.c
new file mode 100644 (file)
index 0000000..1f96e32
--- /dev/null
@@ -0,0 +1,147 @@
+#include"abc.h"
+
+static const char* vert_shader =
+       "#version 330 core\n"
+       "layout(location = 0) in vec4 position; \n"
+       "layout(location = 1) in vec2 a_texCoord; \n"
+       "out vec2 v_texCoord; \n"
+       "uniform mat4 mvp; \n"
+       "void main() { \n"
+               "gl_Position = mvp * position; \n"
+               "v_texCoord  = a_texCoord; \n"
+       "} \n";
+
+static const char* frag_shader =
+       "#version 330 core\n"
+       "in  vec2 v_texCoord; \n"
+       "out vec4 outputColor; \n"
+       "uniform sampler2D tex_rgba; \n"
+       "void main() { \n"
+       "    vec2 xy = v_texCoord; \n"
+       "    vec4 v  = texture2D(tex_rgba, xy).rgba; \n"
+       "    outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
+       "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2]   = {0};
+static GLuint texture_rgba = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+
+
+static int _render_fini_td(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_td(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       if (!obj->text)
+               return 0;
+
+       if (0 == program)
+               __init_program(&program, vert_shader, frag_shader);
+
+       if (0 == vao)
+               __init_buffers(&vao, buffers);
+
+       if (0 == texture_rgba)
+               __init_texture(&texture_rgba, GL_RGBA, obj->w, obj->h, NULL);
+
+       abc_obj_t*            attr;
+       cairo_text_extents_t  extents;
+       cairo_surface_t*      surface;
+       cairo_t*              cr;
+
+       uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+       if (!bgra)
+               return -ENOMEM;
+
+       surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+       cr      = cairo_create(surface);
+
+       cairo_set_line_width(cr, 1);
+       cairo_set_source_rgb(cr, 1, 1, 1);
+       cairo_rectangle(cr, 0, 0, obj->w, obj->h);
+       cairo_fill(cr);
+       cairo_stroke(cr);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+       if (attr)
+               cairo_select_font_face(cr, attr->value->data, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+       if (attr)
+               cairo_set_font_size(cr, atoi(attr->value->data));
+
+       cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+       cairo_text_extents(cr, obj->text->data, &extents);
+
+       cairo_move_to  (cr, extents.x_bearing, -extents.y_bearing);
+       cairo_show_text(cr, obj->text->data);
+
+//     cairo_surface_write_to_png(surface, "tmp.png");
+
+       cairo_destroy(cr);
+       cairo_surface_destroy(surface);
+       surface = NULL;
+       cr = NULL;
+
+       float mvp[16];
+       __compute_mvp(mvp, 0, 0, 0);
+
+       scf_logd("%s, x: %d, y: %d, w: %d, h: %d\n", obj->text->data, obj->x, obj->y, obj->w, obj->h);
+
+       GLfloat vert_update[] =
+       {
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+                2.0 *  obj->x           / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+
+                2.0 * (obj->x + obj->w) / (float)width  - 1.0,
+               -2.0 *  obj->y           / (float)height + 1.0,
+       };
+
+       glUseProgram(program);
+       uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+       uniform_mvp  = glGetUniformLocation(program, "mvp");
+
+       glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+       // board
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture  (GL_TEXTURE_2D, texture_rgba);
+       glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+       glUniform1i(uniform_rgba, 0);
+
+       // draw
+       glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
+       glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+       glBindVertexArray(vao);
+
+       glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+       glBindVertexArray(0);
+       glUseProgram(0);
+
+       free(bgra);
+       return 0;
+}
+
+abc_render_t  abc_render_td =
+{
+       .type = ABC_HTML_TD,
+
+       .draw = _render_draw_td,
+       .fini = _render_fini_td,
+};
diff --git a/ui/abc_render_tr.c b/ui/abc_render_tr.c
new file mode 100644 (file)
index 0000000..9428ccc
--- /dev/null
@@ -0,0 +1,19 @@
+#include"abc.h"
+
+static int _render_fini_tr(abc_render_t* render)
+{
+       return 0;
+}
+
+static int _render_draw_tr(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+       return 0;
+}
+
+abc_render_t  abc_render_tr =
+{
+       .type = ABC_HTML_TR,
+
+       .draw = _render_draw_tr,
+       .fini = _render_fini_tr,
+};
index a0c7804d64f50368d02c242955b1256faa66e7d1..8738b0403f6002f89e63bfde009505580b658223 100644 (file)
--- a/ui/main.c
+++ b/ui/main.c
@@ -58,6 +58,12 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
        GdkWindow*  window;
        GdkCursor*  cursor;
 
        GdkWindow*  window;
        GdkCursor*  cursor;
 
+       if (!ctx->current->download)
+               return 0;
+
+       if (!ctx->current->root)
+               return 0;
+
        abc_obj_t*  prev = ctx->current->current;
        abc_obj_t*  obj  = abc_obj_find(ctx->current->root, x, y);
        abc_obj_t*  attr;
        abc_obj_t*  prev = ctx->current->current;
        abc_obj_t*  obj  = abc_obj_find(ctx->current->root, x, y);
        abc_obj_t*  attr;
@@ -79,8 +85,8 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y)
        }
 
        if (obj) {
        }
 
        if (obj) {
-               scf_logd("obj: %s, x: %d, y: %d, w: %d, h: %d, event x: %d, y: %d\n",
-                               obj->key->data, obj->x, obj->y, obj->w, obj->h, x, y);
+               scf_logd("obj: %s, type: %d, x: %d, y: %d, w: %d, h: %d, event x: %d, y: %d\n",
+                               obj->keys[0], obj->type, obj->x, obj->y, obj->w, obj->h, x, y);
 
                switch (obj->type) {
 
 
                switch (obj->type) {
 
@@ -157,8 +163,9 @@ static int __do_button_release_a(abc_ctx_t* ctx, abc_obj_t* obj, int x, int y)
 
 static int __do_button_release(abc_ctx_t* ctx, int x, int y)
 {
 
 static int __do_button_release(abc_ctx_t* ctx, int x, int y)
 {
-       abc_obj_t* attr;
-       abc_obj_t* obj = abc_obj_find(ctx->current->root, x, y);
+       abc_html_t* html;
+       abc_obj_t*  attr;
+       abc_obj_t*  obj = abc_obj_find(ctx->current->root, x, y);
        if (!obj)
                return -ENOMEM;
 
        if (!obj)
                return -ENOMEM;
 
@@ -178,7 +185,15 @@ static int __do_button_release(abc_ctx_t* ctx, int x, int y)
                        attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_TYPE);
 
                        if (!strcmp(attr->value->data, "submit")) {
                        attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_TYPE);
 
                        if (!strcmp(attr->value->data, "submit")) {
-                               abc_obj_print(ctx->current->root);
+                               html = NULL;
+
+                               int ret = abc_html_post(&html, ctx->current, obj);
+                               if (ret < 0)
+                                       return ret;
+
+                               scf_list_add_tail(&ctx->html_list, &html->list);
+
+                               ctx->current = html;
                                return 0;
                        }
 
                                return 0;
                        }
 
@@ -360,8 +375,25 @@ static gboolean timer_handler(gpointer user_data)
        abc_obj_t* obj;
 
        if (ctx->current) {
        abc_obj_t* obj;
 
        if (ctx->current) {
-               obj = ctx->current->current;
+               if (!ctx->current->download)
+                       return TRUE;
+
+               if (!ctx->current->root) {
+                       int ret = abc_html_parse(ctx->current);
+                       if (ret < 0) {
+                               abc_obj_free(ctx->current->root);
+                               ctx->current->root = NULL;
+                               return TRUE;
+                       }
+
+                       ctx->current->root->gtk_builder = ctx->builder;
+                       ctx->current->current           = ctx->current->root;
 
 
+                       gtk_widget_set_sensitive(GTK_WIDGET(ctx->back), TRUE);
+                       gtk_gl_area_queue_render(ctx->gl_area);
+               }
+
+               obj = ctx->current->current;
                if (obj) {
                        obj->jiffies++;
                        gtk_gl_area_queue_render(ctx->gl_area);
                if (obj) {
                        obj->jiffies++;
                        gtk_gl_area_queue_render(ctx->gl_area);