From: yu.dongliang <18588496441@163.com> Date: Tue, 19 Nov 2024 04:05:15 +0000 (+0800) Subject: http post with a simple HTML
content ok X-Git-Url: http://baseworks.info/?a=commitdiff_plain;ds=inline;p=abc.git http post with a simple HTML content ok --- diff --git a/html/abc_html.c b/html/abc_html.c index 3f34859..0dd2cd4 100644 --- a/html/abc_html.c +++ b/html/abc_html.c @@ -28,6 +28,7 @@ static abc_io_t* abc_io_array[ABC_PROTO_NB] = [ABC_PROTO_HTTP] = &abc_io_http, }; +// HTML attrs 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* 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}; @@ -54,13 +66,20 @@ static char* form_keys[] = {"form", "表单", 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* 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* 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 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[] = { @@ -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}, + + {enctype_keys, "", ABC_HTML_ATTR_ENCTYPE, 0}, }; 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}, @@ -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}, + + {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); @@ -258,6 +298,86 @@ static int __html_load_attrs(abc_obj_t* obj, html_attr_t* attrs, int n_attrs) 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) @@ -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 - || ('a' <= c->c && 'z' >= c->c)) + || ':' == c->c + || ('a' <= c->c && 'z' >= c->c)) { 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); @@ -807,9 +931,9 @@ int abc_html_parse(abc_html_t* html) 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; } } diff --git a/html/abc_html.h b/html/abc_html.h index 48aa167..f235163 100644 --- a/html/abc_html.h +++ b/html/abc_html.h @@ -34,7 +34,7 @@ struct abc_io_s 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 @@ -56,7 +56,8 @@ struct abc_html_s }; 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); diff --git a/html/abc_io_http.c b/html/abc_io_http.c index d62afd5..1d6b246 100644 --- a/html/abc_io_http.c +++ b/html/abc_io_http.c @@ -14,6 +14,9 @@ typedef struct { int content_length; + int cpos; + uint32_t chunk_flag:1; + int exit; pthread_t tid; pthread_mutex_t mutex; @@ -34,13 +37,22 @@ static void http_parse_head(abc_http_t* http) 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; + + } 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; @@ -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; @@ -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; + http->cpos = http->rpos; http_parse_head(http); break; @@ -106,13 +191,17 @@ static void* http_thread(void* arg) } 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 { + 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; } -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"); @@ -286,6 +375,23 @@ static int __http_open(abc_html_t* html, const char* path) 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); \ @@ -319,6 +425,52 @@ static int __http_open(abc_html_t* html, const char* path) 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) @@ -350,12 +502,6 @@ static int __http_popc(abc_html_t* html) return EOF; } -static int __http_post(abc_html_t* html) -{ - scf_loge("\n"); - return -1; -} - abc_io_t abc_io_http = { .proto = "http://", diff --git a/html/abc_obj.c b/html/abc_obj.c index f268cba..8c49328 100644 --- a/html/abc_obj.c +++ b/html/abc_obj.c @@ -165,3 +165,122 @@ void abc_obj_print(abc_obj_t* obj) printf("\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, "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; +} diff --git a/html/abc_obj.h b/html/abc_obj.h index ac7b04c..4780ca0 100644 --- a/html/abc_obj.h +++ b/html/abc_obj.h @@ -32,7 +32,7 @@ enum abc_objs ABC_HTML_A, ABC_HTML_A_HREF, - // 15 + // 16 ABC_HTML_IMG, ABC_HTML_FORM, @@ -40,6 +40,12 @@ enum abc_objs 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, @@ -61,6 +67,16 @@ enum abc_objs 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 @@ -101,13 +117,15 @@ struct abc_obj_s 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 diff --git a/net/ngx_http_abc.h b/net/ngx_http_abc.h index e7bce37..1511570 100644 --- a/net/ngx_http_abc.h +++ b/net/ngx_http_abc.h @@ -13,6 +13,11 @@ typedef struct { 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 diff --git a/net/ngx_http_abc_module.c b/net/ngx_http_abc_module.c index 14ad489..fc8a509 100644 --- a/net/ngx_http_abc_module.c +++ b/net/ngx_http_abc_module.c @@ -2,69 +2,56 @@ #include #include #include "ngx_http_abc.h" -#if 0 + 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("hello

hello world

"); - - 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) { - 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"); + 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; - 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) @@ -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_body_sent = 0; 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_abc_ctx_t* ctx; 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); + 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); @@ -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__); + + 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) @@ -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; - 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) { @@ -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->chunk_CRLF = 0; + ctx->chunk_size = 0; + ctx->chunk_pos = 0; + ctx->chunked = 0; } 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->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); - printf("%s(),%d, subrequest_in_memory: %d\n", __func__, __LINE__, r->subrequest_in_memory); + printf("%s(), %d, done\n", __func__, __LINE__); return NGX_DONE; } diff --git a/ui/Makefile b/ui/Makefile index 73e0508..cc9fd71 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -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_td.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_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_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 diff --git a/ui/abc_layout.c b/ui/abc_layout.c index 0918e10..4411a10 100644 --- a/ui/abc_layout.c +++ b/ui/abc_layout.c @@ -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_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, @@ -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_META] = abc_layout_empty, + [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_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) @@ -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: + case ABC_HTML_TR: x = root->x + 4; y += h; h = 0; diff --git a/ui/abc_layout_h1.c b/ui/abc_layout_h1.c index 2242bf8..56f7032 100644 --- a/ui/abc_layout_h1.c +++ b/ui/abc_layout_h1.c @@ -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; - 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); diff --git a/ui/abc_layout_td.c b/ui/abc_layout_td.c new file mode 100644 index 0000000..73d9410 --- /dev/null +++ b/ui/abc_layout_td.c @@ -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; +} diff --git a/ui/abc_render.c b/ui/abc_render.c index 0b7960d..81d4334 100644 --- a/ui/abc_render.c +++ b/ui/abc_render.c @@ -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_meta; 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_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, @@ -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_META] = &abc_render_meta, [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_TABLE] = &abc_render_table, + [ABC_HTML_TR] = &abc_render_tr, + [ABC_HTML_TD] = &abc_render_td, }; int abc_renders_fini() diff --git a/ui/abc_render_h1.c b/ui/abc_render_h1.c index 3503137..300e84c 100644 --- a/ui/abc_render_h1.c +++ b/ui/abc_render_h1.c @@ -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); - 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[] = { diff --git a/ui/abc_render_meta.c b/ui/abc_render_meta.c new file mode 100644 index 0000000..d6b22cf --- /dev/null +++ b/ui/abc_render_meta.c @@ -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 index 0000000..592865e --- /dev/null +++ b/ui/abc_render_table.c @@ -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 index 0000000..1f96e32 --- /dev/null +++ b/ui/abc_render_td.c @@ -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 index 0000000..9428ccc --- /dev/null +++ b/ui/abc_render_tr.c @@ -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, +}; diff --git a/ui/main.c b/ui/main.c index a0c7804..8738b04 100644 --- 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; + 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; @@ -79,8 +85,8 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y) } 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) { @@ -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) { - 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; @@ -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")) { - 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; } @@ -360,8 +375,25 @@ static gboolean timer_handler(gpointer user_data) 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);