From: yu.dongliang <18588496441@163.com> Date: Tue, 7 Apr 2026 10:10:55 +0000 (+0800) Subject: css: support 'background-color' & 'background-image' X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=a50ea7ae4d12f2a604ad87e72218450bd3259f67;p=abc.git css: support 'background-color' & 'background-image' --- diff --git a/examples/css.html b/examples/css.html index 9b738ff..2eb455e 100644 --- a/examples/css.html +++ b/examples/css.html @@ -8,6 +8,7 @@

这个段落采用CSS样式化。

Hello World!

这个段落采用CSS样式化。

+

这个段落采用CSS样式化。

diff --git a/examples/img.png b/examples/img.png index a3a560b..17f8bd1 100644 Binary files a/examples/img.png and b/examples/img.png differ diff --git a/examples/style.css b/examples/style.css index 9306941..16354c1 100644 --- a/examples/style.css +++ b/examples/style.css @@ -1,3 +1,10 @@ +body +{ + background-color:#b0c4de; + background-image:url('img.png'); +} +h1 {background-color:#6495ed;} + #a /*css comment*/ { color:blue; diff --git a/html/abc_css.c b/html/abc_css.c index c7394d2..b04339d 100644 --- a/html/abc_css.c +++ b/html/abc_css.c @@ -85,7 +85,7 @@ static int __css_parse_value(abc_obj_t* css, abc_obj_t* attr) css->text_pos = 0; } - if (';' == c->c) + if (';' == c->c || EOF == c->c) break; else scf_string_cat_cstr_len(value, c->utf8, c->len); @@ -123,7 +123,7 @@ static int __css_parse_attr2(abc_obj_t* css, abc_obj_t* obj, const html_attr_t* css->text_pos += c->len; - if ('}' == c->c) { + if ('}' == c->c || EOF == c->c) { free(c); scf_string_free(key); return '}'; @@ -228,7 +228,7 @@ static int __css_parse_attr(abc_obj_t* css, abc_obj_t* obj, const html_attr_t* a if (ret < 0) return ret; - if ('}' == ret) + if ('}' == ret || EOF == ret) break; } @@ -382,7 +382,7 @@ int abc_css_parse(abc_obj_t* css) if (!href) return 0; - n = __io_url_path(&io, &spath, css->file->data, href->value->data); + n = __io_url_path(&io, &spath, css->file->data, href->value->data, href->value->len); if (n < 0) return n; @@ -415,12 +415,15 @@ int abc_css_parse(abc_obj_t* css) while (1) { c = __io_pop_char(&css->io); - if (!c) - return -1; + if (!c) { + ret = -1; + break; + } if (EOF == c->c) { free(c); - return 0; + ret = 0; + break; } if ('\n' == c->c) { @@ -452,16 +455,31 @@ int abc_css_parse(abc_obj_t* css) ret = __css_parse_obj(css, c); if (ret < 0) { scf_loge("css->text_line: %d, css->text_pos: %d\n", css->text_line, css->text_pos); - return ret; + break; } } else { scf_loge("'%c'(%#x), css->text_line: %d, css->text_pos: %d\n", c->c, c->c, css->text_line, css->text_pos); free(c); - return -1; + ret = -1; + break; } } - return -1; + io->close(&css->io); + return ret; +} + +static void __css_set_attr(abc_obj_t* obj, abc_obj_t* attr) +{ + switch (attr->type) + { + case ABC_HTML_ATTR_BG_COLOR: + abc_obj_set_attr(obj, attr->type, attr->value->data); + break; + default: + abc_recursive_set_attr(obj, attr->type, attr->value->data); + break; + }; } int abc_css_use(abc_html_t* html, abc_obj_t* obj) @@ -474,53 +492,92 @@ int abc_css_use(abc_html_t* html, abc_obj_t* obj) scf_list_t* l3; abc_obj_t* head; abc_obj_t* css; - abc_obj_t* label; + abc_obj_t* style; abc_obj_t* attr; + // for css in HTML head = abc_obj_find_type(html->root, ABC_HTML_HEAD); - if (!head) - return 0; + if (head) { + for (l = scf_list_head(&head->childs); l != scf_list_sentinel(&head->childs); l = scf_list_next(l)) { + css = scf_list_data(l, abc_obj_t, list); - for (l = scf_list_head(&head->childs); l != scf_list_sentinel(&head->childs); l = scf_list_next(l)) { - css = scf_list_data(l, abc_obj_t, list); + if (ABC_HTML_LINK == css->type) + { + attr = abc_obj_get_attr(css, ABC_HTML_ATTR_TYPE); + if (!attr) + continue; - if (ABC_HTML_LINK == css->type) - { - attr = abc_obj_get_attr(css, ABC_HTML_ATTR_TYPE); - if (!attr) - continue; + if (strcmp(attr->value->data, "text/css")) + continue; - if (strcmp(attr->value->data, "text/css")) + } else if (ABC_HTML_STYLE != css->type) continue; - } else if (ABC_HTML_STYLE != css->type) - continue; + for (l2 = scf_list_head(&css->childs); l2 != scf_list_sentinel(&css->childs); l2 = scf_list_next(l2)) { + style = scf_list_data(l2, abc_obj_t, list); - for (l2 = scf_list_head(&css->childs); l2 != scf_list_sentinel(&css->childs); l2 = scf_list_next(l2)) { - label = scf_list_data(l2, abc_obj_t, list); + if (ABC_CSS_ID == style->type || ABC_CSS_CLASS == style->type) + { + attr = abc_obj_get_attr(obj, style->type); + if (!attr) + continue; - if (ABC_CSS_ID == label->type || ABC_CSS_CLASS == label->type) - { - attr = abc_obj_get_attr(obj, label->type); - if (!attr) - continue; + if (strcmp(attr->value->data, style->text->data + style->css_dot + 1)) + continue; - if (strcmp(attr->value->data, label->text->data + label->css_dot + 1)) + if (style->css_dot > 0) { + if (strncmp(obj->keys[0], style->text->data, style->css_dot)) + continue; + } + + } else if (style->type != obj->type) continue; - if (label->css_dot > 0) { - if (strncmp(obj->keys[0], label->text->data, label->css_dot)) - continue; + for (l3 = scf_list_head(&style->attrs); l3 != scf_list_sentinel(&style->attrs); l3 = scf_list_next(l3)) { + attr = scf_list_data(l3, abc_obj_t, list); + + __css_set_attr(obj, attr); } + } + } + } - } else if (label->type != obj->type) - continue; + // for inline css below + css = abc_obj_get_attr(obj, ABC_HTML_ATTR_STYLE); - for (l3 = scf_list_head(&label->attrs); l3 != scf_list_sentinel(&label->attrs); l3 = scf_list_next(l3)) { - attr = scf_list_data(l3, abc_obj_t, list); + if (css && css->value && css->value->len > 0) + { + html_label_t* label = __html_find_label2(obj->type); + abc_io_t* io = abc_io_array[ABC_PROTO_STR]; - abc_recursive_set_attr(obj, attr->type, attr->value->data); - } + css->io.proto = io->proto; + css->io.priv = NULL; + css->io.open = io->open; + css->io.close = io->close; + css->io.popc = io->popc; + css->io.post = io->post; + + css->text_line = 1; + css->text_pos = 0; + + int ret = io->open(&css->io, css->value->data); + if (ret < 0) + return ret; + + ret = __css_parse_attr(css, css, label->attrs, label->n_attrs); + io->close(&css->io); + if (ret < 0 && EOF != ret) + return ret; + + for (l = scf_list_head(&css->attrs); l != scf_list_sentinel(&css->attrs); ) { + attr = scf_list_data(l, abc_obj_t, list); + l = scf_list_next(l); + + __css_set_attr(obj, attr); + + scf_list_del(&attr->list); + abc_obj_free(attr); + attr = NULL; } } diff --git a/html/abc_html.c b/html/abc_html.c index 6ab0fba..5cf7171 100644 --- a/html/abc_html.c +++ b/html/abc_html.c @@ -17,6 +17,9 @@ static char* font_italic_keys[] = {"italic", "斜体", NULL}; static char* text_align_keys[] = {"text-align", "对齐", NULL}; +static char* bg_color_keys[] = {"background-color", "背景颜色", NULL}; +static char* bg_image_keys[] = {"background-image", "背景图片", NULL}; + static char* class_keys[] = {"class", "类名", NULL}; static char* type_keys[] = {"type", "类型", NULL}; static char* name_keys[] = {"name", "名字", NULL}; @@ -102,78 +105,101 @@ static html_attr_t meta_attrs[] = static html_attr_t body_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}, + {bg_color_keys, "white", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, + {bg_image_keys, "", ABC_HTML_ATTR_BG_IMAGE, ABC_HTML_FLAG_SHOW}, }; static html_attr_t h1_attrs[] = { {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, + {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, - {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, - {font_size_keys, "40", ABC_HTML_ATTR_FONT_SIZE, 0}, + {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, + {font_size_keys, "40", ABC_HTML_ATTR_FONT_SIZE, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t h2_attrs[] = { {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, + {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, - {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, - {font_size_keys, "32", ABC_HTML_ATTR_FONT_SIZE, 0}, + {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, + {font_size_keys, "32", ABC_HTML_ATTR_FONT_SIZE, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t h3_attrs[] = { {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, + {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, - {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, - {font_size_keys, "28", ABC_HTML_ATTR_FONT_SIZE, 0}, + {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, + {font_size_keys, "28", ABC_HTML_ATTR_FONT_SIZE, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t h4_attrs[] = { {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, + {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, - {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, - {font_size_keys, "24", ABC_HTML_ATTR_FONT_SIZE, 0}, + {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, + {font_size_keys, "24", ABC_HTML_ATTR_FONT_SIZE, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t h5_attrs[] = { {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, + {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, - {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, - {font_size_keys, "20", ABC_HTML_ATTR_FONT_SIZE, 0}, + {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, + {font_size_keys, "20", ABC_HTML_ATTR_FONT_SIZE, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t h6_attrs[] = { {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, + {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, - {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, - {font_size_keys, "16", ABC_HTML_ATTR_FONT_SIZE, 0}, + {font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0}, + {font_size_keys, "16", ABC_HTML_ATTR_FONT_SIZE, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t p_attrs[] = { {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, + {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, {font_keys, "SimSong", ABC_HTML_ATTR_FONT, 0}, {font_size_keys, "16", ABC_HTML_ATTR_FONT_SIZE, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t css_id_attrs[] = @@ -191,6 +217,8 @@ static html_attr_t b_attrs[] = {font_bold_keys, "true", ABC_HTML_ATTR_FONT_BOLD, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t i_attrs[] = @@ -200,6 +228,8 @@ static html_attr_t i_attrs[] = {font_italic_keys, "true", ABC_HTML_ATTR_FONT_ITALIC, 0}, {font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW}, {text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW}, + + {bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t a_attrs[] = diff --git a/html/abc_io.h b/html/abc_io.h index 7092e64..d21edd1 100644 --- a/html/abc_io.h +++ b/html/abc_io.h @@ -47,6 +47,7 @@ struct abc_io_s abc_char_t* __io_pop_char (abc_io_t* io); void __io_push_char(abc_io_t* io, abc_char_t* c); -int __io_url_path (abc_io_t** io, scf_string_t** spath, const char* main, const char* current); +int __io_url_path (abc_io_t** io, scf_string_t** spath, const char* main, const char* current, size_t current_len); +int __io_url_css (abc_io_t** io, scf_string_t** spath, const char* main, const char* current); #endif diff --git a/html/abc_io_util.c b/html/abc_io_util.c index fc86416..a96ee22 100644 --- a/html/abc_io_util.c +++ b/html/abc_io_util.c @@ -96,7 +96,7 @@ void __io_push_char(abc_io_t* io, abc_char_t* c) io->tmp_list = c; } -int __io_url_path(abc_io_t** io, scf_string_t** spath, const char* main, const char* current) +int __io_url_path(abc_io_t** io, scf_string_t** spath, const char* main, const char* current, size_t current_len) { scf_string_t* path = scf_string_alloc(); if (!path) @@ -148,13 +148,13 @@ int __io_url_path(abc_io_t** io, scf_string_t** spath, const char* main, const c prefix = 7; proto = ABC_PROTO_FILE; - ret = scf_string_copy_cstr(path, current); + ret = scf_string_copy_cstr_len(path, current, current_len); } else if (!strncmp(current, "http://", 7)) { prefix = 7; proto = ABC_PROTO_HTTP; - ret = scf_string_copy_cstr(path, current); + ret = scf_string_copy_cstr_len(path, current, current_len); } else { if (prefix < 0) { prefix = 0; @@ -169,7 +169,7 @@ int __io_url_path(abc_io_t** io, scf_string_t** spath, const char* main, const c } } - ret = scf_string_cat_cstr(path, current); + ret = scf_string_cat_cstr_len(path, current, current_len); } if (ret < 0) { @@ -181,3 +181,17 @@ int __io_url_path(abc_io_t** io, scf_string_t** spath, const char* main, const c *spath = path; return prefix; } + +int __io_url_css(abc_io_t** io, scf_string_t** spath, const char* main, const char* current) +{ + if (strncmp(current, "url('", 5)) + return -EINVAL; + + const char* p0 = current + 5; + const char* p = p0; + + while (*p && '\'' != *p) + p++; + + return __io_url_path(io, spath, main, p0, (size_t)(p - p0)); +} diff --git a/html/abc_obj.c b/html/abc_obj.c index a1177ff..d97be6d 100644 --- a/html/abc_obj.c +++ b/html/abc_obj.c @@ -166,7 +166,8 @@ abc_obj_t* abc_obj_find_attr(abc_obj_t* obj, int key) while (obj) { attr = abc_obj_get_attr(obj, key); - if (attr) + + if (attr && attr->value && attr->value->len > 0) return attr; obj = obj->parent; @@ -193,7 +194,6 @@ void abc_obj_print(abc_obj_t* obj) } else if (obj->keys) printf("<%s", obj->keys[0]); - 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); diff --git a/html/abc_obj.h b/html/abc_obj.h index 2701a74..c114b4a 100644 --- a/html/abc_obj.h +++ b/html/abc_obj.h @@ -69,6 +69,7 @@ enum abc_objs ABC_HTML_ATTR_NAME, ABC_HTML_ATTR_VALUE, ABC_HTML_ATTR_CLASS, + ABC_HTML_ATTR_STYLE, ABC_HTML_ATTR_HREF, ABC_HTML_ATTR_SRC, @@ -87,6 +88,9 @@ enum abc_objs ABC_HTML_ATTR_TEXT_ALIGN, + ABC_HTML_ATTR_BG_COLOR, + ABC_HTML_ATTR_BG_IMAGE, + ABC_HTML_ATTR_WIDTH, ABC_HTML_ATTR_HEIGHT, diff --git a/ui/Makefile b/ui/Makefile index 6aa23e1..6b09791 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -25,6 +25,9 @@ CFILES += abc_render_head.c CFILES += abc_render_body.c CFILES += abc_render_div.c +CFILES += abc_render_bg_color.c +CFILES += abc_render_bg_image.c + CFILES += abc_render_empty.c CFILES += abc_render_h1.c diff --git a/ui/abc_layout.c b/ui/abc_layout.c index d2a41c6..d8cb26d 100644 --- a/ui/abc_layout.c +++ b/ui/abc_layout.c @@ -29,7 +29,7 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] = [ABC_HTML] = abc_layout_html, [ABC_HTML_TITLE] = abc_layout_title, [ABC_HTML_HEAD] = abc_layout_head, - [ABC_HTML_BODY] = abc_layout_h1, + [ABC_HTML_BODY] = abc_layout_body, [ABC_HTML_DIV] = abc_layout_div, [ABC_HTML_META] = abc_layout_empty, @@ -144,6 +144,12 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height) switch (root->type) { + case ABC_HTML_SCRIPT: + case ABC_HTML_STYLE: + case ABC_HTML_LINK: + return 0; + break; + case ABC_HTML_BODY: root->w = width; root->h = height; diff --git a/ui/abc_render.c b/ui/abc_render.c index 45f209c..bfdbd97 100644 --- a/ui/abc_render.c +++ b/ui/abc_render.c @@ -30,7 +30,7 @@ static abc_render_t* abc_renders[ABC_HTML_NB] = { [ABC_HTML] = &abc_render_empty, [ABC_HTML_HEAD] = &abc_render_empty, - [ABC_HTML_BODY] = &abc_render_h1, + [ABC_HTML_BODY] = &abc_render_body, [ABC_HTML_META] = &abc_render_empty, [ABC_HTML_TITLE] = &abc_render_title, [ABC_HTML_DIV] = &abc_render_div, @@ -104,6 +104,17 @@ int abc_render_draw(abc_obj_t* obj, int width, int height) static int __render_root(abc_ctx_t* ctx, abc_obj_t* root, int width, int height) { + switch (root->type) + { + case ABC_HTML_SCRIPT: + case ABC_HTML_STYLE: + case ABC_HTML_LINK: + return 0; + break; + default: + break; + }; + scf_list_t* l; abc_obj_t* child; diff --git a/ui/abc_render_bg_color.c b/ui/abc_render_bg_color.c new file mode 100644 index 0000000..e7ae029 --- /dev/null +++ b/ui/abc_render_bg_color.c @@ -0,0 +1,101 @@ +#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 vec4 bgColor; \n" + "void main() { \n" + " vec2 xy = v_texCoord; \n" + " outputColor = bgColor; \n" + "} \n"; + + +static GLuint program = 0; + +static GLuint vao = 0; +static GLuint buffers[2] = {0}; + +static GLuint uniform_mvp; +static GLuint uniform_bgColor; + + +static int _render_fini_bg_color(abc_render_t* render) +{ + return 0; +} + +static int _render_draw_bg_color(abc_render_t* render, abc_obj_t* obj, int width, int height) +{ + if (0 == program) + __init_program(&program, vert_shader, frag_shader); + + if (0 == vao) + __init_buffers(&vao, buffers); + + double r = 0.0; + double g = 0.0; + double b = 0.0; + + abc_obj_t* attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BG_COLOR); + if (attr) + abc_css_color(&r, &g, &b, attr->value->data); + + 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_bgColor = glGetUniformLocation(program, "bgColor"); + uniform_mvp = glGetUniformLocation(program, "mvp"); + + glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp); + glUniform4f (uniform_bgColor, r, g, b, 1.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); + return 0; +} + +abc_render_t abc_render_bg_color = +{ + .type = ABC_HTML_ATTR_BG_COLOR, + + .draw = _render_draw_bg_color, + .fini = _render_fini_bg_color, +}; diff --git a/ui/abc_render_bg_image.c b/ui/abc_render_bg_image.c new file mode 100644 index 0000000..4ac8667 --- /dev/null +++ b/ui/abc_render_bg_image.c @@ -0,0 +1,175 @@ +#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 vec4 bgColor; \n" + "uniform vec4 rect; \n" + "uniform sampler2D tex_rgba; \n" + "void main() { \n" + " vec2 xy = v_texCoord; \n" + " if (rect.x < xy.x && xy.x < rect.x + rect.z \n" + " && rect.y < xy.y && xy.y < rect.y + rect.w) { \n" + " xy.x = (xy.x - rect.x) / rect.z; \n" + " xy.y = (xy.y - rect.y) / rect.w; \n" + " vec4 v = texture2D(tex_rgba, xy).rgba; \n" + " outputColor = vec4(v.b, v.g, v.r, 1.0); \n" + " } else { \n" + " outputColor = bgColor; \n" + " } \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 GLuint uniform_rect; +static GLuint uniform_color; + +static int _render_fini_bg_image(abc_render_t* render) +{ + return 0; +} + +static int _render_draw_bg_image(abc_render_t* render, abc_obj_t* obj, int width, int height) +{ + abc_obj_t* attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_BG_IMAGE); + if (!attr) + return 0; + if (!attr->value || attr->value->len <= 0) + return 0; + + scf_string_t* spath = NULL; + abc_io_t* io = NULL; + abc_img_t* img = NULL; + + int ret = __io_url_css(&io, &spath, obj->file->data, attr->value->data); + if (ret < 0) + return ret; + + scf_logi("background-image: %s\n", spath->data); + + ret = abc_img_open(&img, spath->data); + + scf_string_free(spath); + spath = NULL; + if (ret < 0) + return ret; + + uint8_t* bgra = calloc(1, img->width * img->height * 4); + if (!bgra) { + abc_img_close(img); + return -ENOMEM; + } + + ret = abc_img_read(img, bgra, img->width * img->height * 4); + if (ret < 0) { + abc_img_close(img); + free(bgra); + return ret; + } + + double r = 0.0; + double g = 0.0; + double b = 0.0; + attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BG_COLOR); + if (attr) + abc_css_color(&r, &g, &b, attr->value->data); + + 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, img->width, img->height, 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, + }; + + GLfloat x = 0.0; + GLfloat y = 0.0; + GLfloat w = img->width / (float)obj->w; + GLfloat h = img->height / (float)obj->h; + + if (w > 1.0 || h > 1.0) + { + GLfloat max = w > h ? w : h; + + w /= max; + h /= max; + } + + glUseProgram(program); + uniform_color = glGetUniformLocation(program, "bgColor"); + uniform_rgba = glGetUniformLocation(program, "tex_rgba"); + uniform_rect = glGetUniformLocation(program, "rect"); + uniform_mvp = glGetUniformLocation(program, "mvp"); + + glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp); + + glActiveTexture(GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, texture_rgba); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra); + glUniform1i(uniform_rgba, 0); + glUniform4f(uniform_rect, x, y, w, h); + glUniform4f(uniform_color, r, g, b, 1.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); + + abc_img_close(img); + free(bgra); + return 0; +} + +abc_render_t abc_render_bg_image = +{ + .type = ABC_HTML_ATTR_BG_IMAGE, + + .draw = _render_draw_bg_image, + .fini = _render_fini_bg_image, +}; diff --git a/ui/abc_render_body.c b/ui/abc_render_body.c index 2008e77..866a1a0 100644 --- a/ui/abc_render_body.c +++ b/ui/abc_render_body.c @@ -1,5 +1,9 @@ #include"abc.h" +extern abc_render_t abc_render_h1; +extern abc_render_t abc_render_bg_color; +extern abc_render_t abc_render_bg_image; + static int _render_fini_body(abc_render_t* render) { return 0; @@ -7,12 +11,23 @@ static int _render_fini_body(abc_render_t* render) static int _render_draw_body(abc_render_t* render, abc_obj_t* obj, int width, int height) { + abc_obj_t* attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_BG_IMAGE); + + if (attr && attr->value && attr->value->len > 0) + { + abc_render_bg_image.draw(&abc_render_bg_image, obj, width, height); + } else + abc_render_bg_color.draw(&abc_render_bg_color, obj, width, height); + + if (obj->text) + abc_render_h1.draw(&abc_render_h1, obj, width, height); + return 0; } abc_render_t abc_render_body = { - .type = ABC_HTML_H1, + .type = ABC_HTML_BODY, .draw = _render_draw_body, .fini = _render_fini_body, diff --git a/ui/abc_render_h1.c b/ui/abc_render_h1.c index beb45e1..4993ed3 100644 --- a/ui/abc_render_h1.c +++ b/ui/abc_render_h1.c @@ -38,39 +38,9 @@ static int _render_fini_h1(abc_render_t* render) return 0; } -static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int height) +static int __init_text(cairo_t* cr, abc_obj_t* obj) { - 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); + abc_obj_t* attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT); if (attr) { int bold = CAIRO_FONT_WEIGHT_NORMAL; int italic = CAIRO_FONT_SLANT_NORMAL; @@ -88,9 +58,11 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int if (attr) cairo_set_font_size(cr, atoi(attr->value->data)); + cairo_text_extents_t extents; double r = 0.0; double g = 0.0; double b = 0.0; + attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_COLOR); if (attr) abc_css_color(&r, &g, &b, attr->value->data); @@ -100,7 +72,46 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int cairo_move_to (cr, extents.x_bearing, -extents.y_bearing); cairo_show_text(cr, obj->text->data); + return 0; +} + +static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int height) +{ + 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_surface_t* surface; + cairo_t* cr; + + uint8_t* bgra = calloc(1, obj->w * obj->h * 4); + if (!bgra) + return -ENOMEM; + + double r = 0.0; + double g = 0.0; + double b = 0.0; + attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BG_COLOR); + if (attr) + abc_css_color(&r, &g, &b, attr->value->data); + + 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, r, g, b); + cairo_rectangle(cr, 0, 0, obj->w, obj->h); + cairo_fill(cr); + cairo_stroke(cr); + if (obj->text) + __init_text(cr, obj); // cairo_surface_write_to_png(surface, "tmp.png"); cairo_destroy(cr); diff --git a/ui/abc_render_img.c b/ui/abc_render_img.c index e5e2f87..20323ca 100644 --- a/ui/abc_render_img.c +++ b/ui/abc_render_img.c @@ -41,18 +41,11 @@ static int _render_fini_img(abc_render_t* render) static int _render_draw_img(abc_render_t* render, abc_obj_t* obj, int width, int height) { - scf_list_t* l; - abc_obj_t* attr; - abc_img_t* img = NULL; + abc_obj_t* attr; + abc_img_t* img = NULL; - 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_ATTR_SRC == attr->type) - break; - } - - if (l == scf_list_sentinel(&obj->attrs)) { + attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_SRC); + if (!attr) { scf_loge("src image of '%s' not found\n", obj->keys[0]); return -1; } @@ -109,7 +102,6 @@ static int _render_draw_img(abc_render_t* render, abc_obj_t* obj, int width, int glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp); - // board glActiveTexture(GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, texture_rgba); glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);