From: yu.dongliang <18588496441@163.com> Date: Wed, 27 May 2026 09:42:54 +0000 (+0800) Subject: css: simple attribute selector ok, draw HTML
Hello!
+ + diff --git a/html/abc_css.c b/html/abc_css.c index 4c555ad..a920336 100644 --- a/html/abc_css.c +++ b/html/abc_css.c @@ -93,7 +93,9 @@ static int __css_parse_str(abc_obj_t* css, scf_string_t* s, int (*end)(int c)) case ' ': if (' ' == c0 || '>' == c0 || '+' == c0 || '~' == c0 - || ',' == c0 || ':' == c0 || '.' == c0 || '#' == c0) + || ',' == c0 || ':' == c0 || '.' == c0 || '#' == c0 + || '[' == c0 || ']' == c0 + || '(' == c0 || ')' == c0) break; ret = scf_string_cat_cstr_len(s, " ", 1); @@ -106,6 +108,10 @@ static int __css_parse_str(abc_obj_t* css, scf_string_t* s, int (*end)(int c)) case ',': case ':': case '.': + case '[': + case ']': + case '(': + case ')': // case '#': if (s->len > 0 && ' ' == s->data[s->len - 1]) { s->data[s->len - 1] = c->c; @@ -248,6 +254,7 @@ static int __css_parse_comma(abc_obj_t* css, abc_obj_t* obj) int combinator = -1; int id = 0; int class = 0; + int attr = 0; int pseClass = -1; int pseElement = -1; int c; @@ -284,6 +291,8 @@ static int __css_parse_comma(abc_obj_t* css, abc_obj_t* obj) label = __html_find_label2(ABC_CSS_ID); else if (class > 0) label = __html_find_label2(ABC_CSS_CLASS); + else if (attr > 0) + label = __html_find_label2(ABC_CSS_ATTR); else if (pseClass > 0) label = __html_find_label2(ABC_CSS_PSE_CLASS); @@ -332,6 +341,7 @@ static int __css_parse_comma(abc_obj_t* css, abc_obj_t* obj) combinator = -1; id = 0; class = 0; + attr = 0; pseClass = -1; pseElement = -1; @@ -351,6 +361,9 @@ static int __css_parse_comma(abc_obj_t* css, abc_obj_t* obj) case '.': class++; break; + case '[': + attr++; + break; case ':': if (pseClass < 0) @@ -382,6 +395,8 @@ static int __css_parse_comma(abc_obj_t* css, abc_obj_t* obj) label = __html_find_label2(ABC_CSS_ID); else if (class > 0) label = __html_find_label2(ABC_CSS_CLASS); + else if (attr > 0) + label = __html_find_label2(ABC_CSS_ATTR); else if (pseClass > 0) label = __html_find_label2(ABC_CSS_PSE_CLASS); @@ -585,7 +600,8 @@ int abc_css_parse(abc_obj_t* css) || ('a' <= c->c && 'z' >= c->c) || ('A' <= c->c && 'Z' >= c->c) || (0x4e00 <= c->c && 0x9fa5 >= c->c) - || '.' == c->c) { + || '.' == c->c + || '[' == c->c) { ret = __css_parse_obj(css, c); if (ret < 0) { @@ -934,6 +950,7 @@ int abc_css_merge(abc_html_t* html, abc_obj_t* css) break; case ABC_CSS_CLASS: + case ABC_CSS_ATTR: scf_list_del(&src->list); scf_list_add_tail(&h_class, &src->list); break; @@ -1095,7 +1112,7 @@ static abc_obj_t* __css_select_by_key(abc_obj_t* css, abc_obj_t* current, scf_ve return current; } -static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_vector_t* vec, int next, int type, const char* key, int len) +static abc_obj_t* __css_select_by_id_class(abc_obj_t* css, abc_obj_t* current, scf_vector_t* vec, int next, int type, const char* value, int len) { scf_list_t* l; abc_obj_t* tmp; @@ -1117,7 +1134,7 @@ static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_v { attr = abc_obj_get_attr(current, type); - if (attr && !__html_strncmp(attr->value->data, key, len)) + if (attr && !__html_strncmp(attr->value->data, value, len)) break; } break; @@ -1127,7 +1144,7 @@ static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_v if (current) { attr = abc_obj_get_attr(current, type); - if (!attr || __html_strncmp(attr->value->data, key, len)) + if (!attr || __html_strncmp(attr->value->data, value, len)) return NULL; } break; @@ -1143,7 +1160,7 @@ static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_v current = scf_list_data(l, abc_obj_t, list); attr = abc_obj_get_attr(current, type); - if (!attr || __html_strncmp(attr->value->data, key, len)) + if (!attr || __html_strncmp(attr->value->data, value, len)) return NULL; break; @@ -1156,7 +1173,7 @@ static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_v attr = abc_obj_get_attr(tmp, type); - if (attr && !__html_strncmp(attr->value->data, key, len)) + if (attr && !__html_strncmp(attr->value->data, value, len)) break; } @@ -1175,7 +1192,7 @@ static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_v if (k <= j) return NULL; - current = __css_select_by_attr(css, current, vec, next - 1, type, key, len); + current = __css_select_by_id_class(css, current, vec, next - 1, type, value, len); if (!current) return NULL; @@ -1201,13 +1218,133 @@ static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_v css->css_pse_chain = pseLink; pseLink = NULL; - scf_logd("current: %s, key: %.*s, j: %d, k: %d, next: %.*s\n", current->keys[0], len, key, j, k, + scf_logd("current: %s, key: %.*s, j: %d, k: %d, next: %.*s\n", current->keys[0], len, value, j, k, k - j, css->text->data + j); break; default: attr = abc_obj_get_attr(current, type); - if (!attr || __html_strncmp(attr->value->data, key, len)) + if (!attr || __html_strncmp(attr->value->data, value, len)) + return NULL; + break; + }; + + return current; +} + +static abc_obj_t* __css_select_by_attr(abc_obj_t* css, abc_obj_t* current, scf_vector_t* vec, int next, const char* key, int len) +{ + scf_list_t* l; + abc_obj_t* tmp; + abc_attr_t* attr; + abc_attr_t* pse; + pse_link_t* pseLink; + + assert(next >= 0 && next < vec->size); + + int j = (intptr_t)vec->data[next]; + int k; + int c = 0; + if (j < css->text->len) + c = css->text->data[j]; + + switch (c) { + case ' ': + for (current = current->parent; current; current = current->parent) + { + attr = abc_obj_get_attr2(current, key, len); + + if (attr && attr->value && attr->value->len > 0) + break; + } + break; + + case '>': + current = current->parent; + if (current) { + attr = abc_obj_get_attr2(current, key, len); + + if (!attr || !attr->value || 0 == attr->value->len) + return NULL; + } + break; + + case '+': + if (!current->parent) + return NULL; + + l = scf_list_prev(¤t->list); + if (l == scf_list_sentinel(¤t->parent->childs)) + return NULL; + + current = scf_list_data(l, abc_obj_t, list); + attr = abc_obj_get_attr2(current, key, len); + + if (!attr || !attr->value || 0 == attr->value->len) + return NULL; + break; + + case '~': + if (!current->parent) + return NULL; + + for (l = scf_list_prev(¤t->list); l != scf_list_sentinel(¤t->parent->childs); l = scf_list_prev(l)) { + tmp = scf_list_data(l, abc_obj_t, list); + + attr = abc_obj_get_attr2(tmp, key, len); + + if (attr && attr->value && attr->value->len > 0) + break; + } + + if (l == scf_list_sentinel(¤t->parent->childs)) + return NULL; + + current = tmp; + break; + + case ':': + assert(next - 1 >= 0 && next - 1 < vec->size); + + scf_logd("current: %s, key: %.*s, j: %d, next: %s\n", current->keys[0], len, key, j, css->text->data + j); + + k = (intptr_t) vec->data[next - 1]; + if (k <= j) + return NULL; + + current = __css_select_by_attr(css, current, vec, next - 1, key, len); + if (!current) + return NULL; + + pse = abc_obj_get_attr2(current, css->text->data + j, k - j); + if (!pse) + return NULL; + + if (css->css_pse_type < pse->type) + css->css_pse_type = pse->type; + + current = __css_filter_pse(current, pse); + if (!current) + return NULL; + + pseLink = calloc(1, sizeof(pse_link_t)); + if (!pseLink) + return NULL; + + pseLink->obj = current; + pseLink->pse_type = pse->type; + pseLink->next = css->css_pse_chain; + + css->css_pse_chain = pseLink; + pseLink = NULL; + + scf_logd("current: %s, key: %.*s, j: %d, k: %d, next: %.*s\n", current->keys[0], len, key, j, k, + k - j, css->text->data + j); + break; + default: + attr = abc_obj_get_attr2(current, key, len); + + if (!attr || !attr->value || 0 == attr->value->len) return NULL; break; }; @@ -1235,6 +1372,8 @@ static int __css_use_complex(abc_obj_t* css, abc_obj_t* obj) css->css_pse_type = 0; scf_slist_clear(css->css_pse_chain, pse_link_t, next, free); + int n_sqares = 0; + for (i = css->text->len - 1; i >= 0; i--) { c = css->text->data[i]; @@ -1248,12 +1387,53 @@ static int __css_use_complex(abc_obj_t* css, abc_obj_t* obj) ret = 0; switch (c) { case '#': - current = __css_select_by_attr(css, current, vec, vec->size - 1, ABC_CSS_ID, key, len); + current = __css_select_by_id_class(css, current, vec, vec->size - 1, ABC_CSS_ID, key, len); j = i; break; case '.': - current = __css_select_by_attr(css, current, vec, vec->size - 1, ABC_CSS_CLASS, key, len); + current = __css_select_by_id_class(css, current, vec, vec->size - 1, ABC_CSS_CLASS, key, len); + j = i; + break; + + case ']': + n_sqares++; + j = i; + break; + + case '~': + if (n_sqares <= 0) + current = __css_select_by_key(css, current, vec, vec->size - 1, key, len); + j = i; + break; + case '|': + case '^': + case '$': + case '*': + if (n_sqares > 0) + j = i; + break; + case '=': + if (n_sqares > 0) { + if (i > 0 && ('~' == css->text->data[i - 1] + || '|' == css->text->data[i - 1] + || '^' == css->text->data[i - 1] + || '$' == css->text->data[i - 1] + || '*' == css->text->data[i - 1])) + break; + j = i; + } + break; + + case '[': + if (0 != --n_sqares) { + ret = -EINVAL; + goto end; + } + + scf_logw("i: %d, %.*s\n", i, len, key); + + current = __css_select_by_attr(css, current, vec, vec->size - 1, key, len); j = i; break; @@ -1273,7 +1453,6 @@ static int __css_use_complex(abc_obj_t* css, abc_obj_t* obj) case ' ': case '>': case '+': - case '~': current = __css_select_by_key(css, current, vec, vec->size - 1, key, len); j = i; break; @@ -1324,6 +1503,7 @@ int abc_css_use(abc_html_t* html, abc_obj_t* obj) { case ABC_CSS_ID: case ABC_CSS_CLASS: + case ABC_CSS_ATTR: case ABC_CSS_PSE_CLASS: case ABC_CSS_PSE_ELEMENT: case ABC_CSS_COMBINATOR: diff --git a/html/abc_html.c b/html/abc_html.c index 20bedb2..70287b7 100644 --- a/html/abc_html.c +++ b/html/abc_html.c @@ -135,6 +135,7 @@ static char* style_keys[] = {"style", "æ ·å¼", NULL}; // css selectors static char* css_id_keys[] = {"#", NULL}; static char* css_class_keys[] = {".", NULL}; +static char* css_attr_keys[] = {"[]", NULL}; static char* css_other_keys[] = {"*", NULL}; static char* css_pse_class_keys[] = {":", NULL}; static char* css_pse_element_keys[] = {"::", NULL}; @@ -185,6 +186,7 @@ static html_attr_t html_attrs[] = #define ABC_CSS_SELECTOR() \ {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, \ {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, \ + {title_keys, "", ABC_HTML_ATTR_TITLE, ABC_HTML_FLAG_SHOW}, \ {id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW}, #define ABC_CSS_BACK_GROUND(color) \ @@ -314,6 +316,17 @@ static html_attr_t h6_attrs[] = ABC_CSS_TEXT(left, ) }; +static html_attr_t hr_attrs[] = +{ + ABC_CSS_BOX( , , ) + ABC_CSS_SCROLL( , , ) + ABC_CSS_SELECTOR() + ABC_CSS_BACK_GROUND() + + ABC_CSS_FONT(SimHei, 16, lightGray, ) + ABC_CSS_TEXT(left, ) +}; + static html_attr_t p_attrs[] = { ABC_CSS_BOX(2px, , 2px) @@ -547,7 +560,7 @@ static html_label_t html_labels[] = {i_keys, ABC_HTML_I, abc_number_of(i_attrs), i_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, {br_keys, ABC_HTML_BR, 0, NULL, ABC_HTML_FLAG_OPEN | ABC_HTML_FLAG_SHOW}, - {hr_keys, ABC_HTML_HR, 0, NULL, ABC_HTML_FLAG_OPEN | ABC_HTML_FLAG_SHOW}, + {hr_keys, ABC_HTML_HR, abc_number_of(hr_attrs), hr_attrs, ABC_HTML_FLAG_OPEN | ABC_HTML_FLAG_SHOW}, {a_keys, ABC_HTML_A, abc_number_of(a_attrs), a_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, {img_keys, ABC_HTML_IMG, abc_number_of(img_attrs), img_attrs, ABC_HTML_FLAG_OPEN | ABC_HTML_FLAG_SHOW}, @@ -578,6 +591,7 @@ static html_label_t html_labels[] = {css_id_keys, ABC_CSS_ID, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, {css_class_keys, ABC_CSS_CLASS, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, + {css_attr_keys, ABC_CSS_ATTR, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, {css_pse_class_keys, ABC_CSS_PSE_CLASS, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, {css_pse_element_keys, ABC_CSS_PSE_ELEMENT, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, {css_other_keys, ABC_CSS_COMBINATOR, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW}, diff --git a/html/abc_obj.h b/html/abc_obj.h index ff49d6a..6b6faad 100644 --- a/html/abc_obj.h +++ b/html/abc_obj.h @@ -77,6 +77,7 @@ enum abc_objs ABC_HTML_ATTR_NAME, ABC_HTML_ATTR_VALUE, ABC_HTML_ATTR_CLASS, + ABC_HTML_ATTR_TITLE, ABC_HTML_ATTR_STYLE, ABC_HTML_ATTR_HREF, @@ -173,6 +174,7 @@ enum abc_objs ABC_HTML_CSS_NB = ABC_CSS_PSE_DYNAMIC, // total HTML & CSS attrs // css selectors + ABC_CSS_ATTR, ABC_CSS_PSE_CLASS, ABC_CSS_PSE_ELEMENT, ABC_CSS_COMBINATOR, diff --git a/ui/Makefile b/ui/Makefile index e7567f9..36f96a1 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -6,6 +6,7 @@ CFILES += abc_layout_div.c CFILES += abc_layout_text.c CFILES += abc_layout_h1.c +CFILES += abc_layout_hr.c CFILES += abc_layout_img.c CFILES += abc_layout_form.c @@ -28,6 +29,7 @@ CFILES += abc_render_text.c CFILES += abc_render_empty.c CFILES += abc_render_h1.c +CFILES += abc_render_hr.c CFILES += abc_render_a_href.c CFILES += abc_render_img.c CFILES += abc_render_form.c diff --git a/ui/abc_layout.c b/ui/abc_layout.c index c03ef1a..01d01f3 100644 --- a/ui/abc_layout.c +++ b/ui/abc_layout.c @@ -6,6 +6,7 @@ int abc_layout_text(abc_layout_t* layout, abc_obj_t* obj, int width, int height) int abc_layout_div (abc_layout_t* layout, abc_obj_t* obj, int width, int height); int abc_layout_h1 (abc_layout_t* layout, abc_obj_t* obj, int width, int height); +int abc_layout_hr (abc_layout_t* layout, abc_obj_t* obj, int width, int height); int abc_layout_img (abc_layout_t* layout, abc_obj_t* obj, int width, int height); int abc_layout_form (abc_layout_t* layout, abc_obj_t* obj, int width, int height); @@ -53,6 +54,7 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] = [ABC_HTML_P] = abc_layout_h1, [ABC_HTML_BR] = abc_layout_h1, + [ABC_HTML_HR] = abc_layout_hr, [ABC_HTML_IMG] = abc_layout_img, @@ -359,6 +361,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_HR: case ABC_HTML_TR: x = root->x + root->left; y += h; diff --git a/ui/abc_layout_hr.c b/ui/abc_layout_hr.c new file mode 100644 index 0000000..6639222 --- /dev/null +++ b/ui/abc_layout_hr.c @@ -0,0 +1,42 @@ +#include"abc.h" + +int abc_layout_hr(abc_layout_t* layout, abc_obj_t* obj, int width, int height) +{ + int size = 16; + + if (obj->parent) { + scf_list_t* l; + abc_attr_t* attr; + abc_obj_t* tmp; + + l = scf_list_prev(&obj->list); + if (l != scf_list_sentinel(&obj->parent->childs)) { + tmp = scf_list_data(l, abc_obj_t, list); + + attr = abc_obj_find_attr(tmp, ABC_HTML_ATTR_FONT_SIZE); + + if (attr && attr->value && attr->value->len > 0) + size = atoi(attr->value->data); + } + + l = scf_list_next(&obj->list); + if (l != scf_list_sentinel(&obj->parent->childs)) { + tmp = scf_list_data(l, abc_obj_t, list); + + attr = abc_obj_find_attr(tmp, ABC_HTML_ATTR_FONT_SIZE); + + if (attr && attr->value && attr->value->len > 0) { + int size2 = atoi(attr->value->data); + if (size < size2) + size = size2; + } + } + } + + int w_set = abc_css_width (obj, width); + int h_set = abc_css_height(obj, height); + + if (!h_set) + obj->h = size; + return 0; +} diff --git a/ui/abc_render.c b/ui/abc_render.c index 43a3d50..a5e774a 100644 --- a/ui/abc_render.c +++ b/ui/abc_render.c @@ -5,6 +5,7 @@ extern abc_render_t abc_render_text; extern abc_render_t __render_text; extern abc_render_t abc_render_h1; +extern abc_render_t abc_render_hr; extern abc_render_t abc_render_a_href; extern abc_render_t abc_render_img; @@ -45,6 +46,7 @@ static abc_render_t* abc_renders[ABC_HTML_NB] = [ABC_HTML_P] = &abc_render_h1, [ABC_HTML_BR] = &abc_render_h1, + [ABC_HTML_HR] = &abc_render_hr, [ABC_HTML_A_HREF] = &abc_render_a_href, [ABC_HTML_IMG] = &abc_render_img, diff --git a/ui/abc_render_hr.c b/ui/abc_render_hr.c new file mode 100644 index 0000000..168ecf3 --- /dev/null +++ b/ui/abc_render_hr.c @@ -0,0 +1,177 @@ +#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 color; \n" + "uniform vec4 bgColor; \n" + "uniform float line_width; \n" + "\n" + "void main() { \n" + " float x = v_texCoord.x; \n" + " float y = v_texCoord.y; \n" + " if (y > 0.5 - line_width && y < 0.5 + line_width) { \n" + " outputColor = color; \n" + " } else { \n" + " outputColor = bgColor; \n" + " } \n" + "} \n"; + + +static GLuint program = 0; + +static GLuint vao = 0; +static GLuint buffers[2] = {0}; + +static GLuint uniform_mvp; +static GLuint uniform_color; +static GLuint uniform_bgColor; +static GLuint uniform_line_width; + +static int __render_fini_hr(abc_render_t* render) +{ + return 0; +} + +static int __render_draw_hr(abc_render_t* render, abc_obj_t* obj, int width, int height) +{ + abc_obj_t* parent = obj->parent; + + if (0 == program) + __init_program(&program, vert_shader, frag_shader); + + if (0 == vao) + __init_buffers(&vao, buffers); + + double fgColor[3] = {0.0, 0.0, 0.0}; + double bgColor[4] = {0.0, 0.0, 0.0, 0.0}; + + abc_attr_t* attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_BG_COLOR); + if (attr && attr->value->len > 0) { + bgColor[3] = 1.0; + abc_css_color(bgColor, bgColor + 1, bgColor + 2, attr->value->data, attr->value->len); + } + + attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_COLOR); + if (attr) + abc_css_color(fgColor, fgColor + 1, fgColor + 2, attr->value->data, attr->value->len); + + int x = obj->x + obj->margin_left; + int y = obj->y + obj->margin_top; + int w = obj->w - obj->margin_left - obj->margin_right; + int h = obj->h - obj->margin_top - obj->margin_bottom; + + obj->view_x = x; + obj->view_y = y; + obj->view_w = w; + obj->view_h = h; + + attr = abc_obj_find_attr(obj, ABC_CSS_OVERFLOW); + if (attr) + obj->overflow_type = abc_css_overflow(attr->value->data); + + switch (obj->overflow_type) + { + case ABC_OVERFLOW_SCROLL: + case ABC_OVERFLOW_AUTO: + case ABC_OVERFLOW_HIDDEN: + if (parent && (x < parent->view_x + || y < parent->view_y + || x + w > parent->view_x + parent->view_w + || y + h > parent->view_y + parent->view_h)) { + + abc_overflow_show(&obj->view_x, &obj->view_y, &obj->view_w, &obj->view_h, + parent->view_x, + parent->view_y, + parent->view_w - parent->border_right - parent->padding_right, + parent->view_h - parent->border_bottom - parent->padding_bottom); + } + break; + default: + break; + }; + + float mvp[16]; + __compute_mvp(mvp, 0, 0, 0); + + GLfloat vert_update[] = + { + 2.0 * obj->view_x / (float)width - 1.0, + -2.0 * (obj->view_y + obj->view_h) / (float)height + 1.0, + + 2.0 * (obj->view_x + obj->view_w) / (float)width - 1.0, + -2.0 * (obj->view_y + obj->view_h) / (float)height + 1.0, + + 2.0 * obj->view_x / (float)width - 1.0, + -2.0 * obj->view_y / (float)height + 1.0, + + 2.0 * (obj->view_x + obj->view_w) / (float)width - 1.0, + -2.0 * obj->view_y / (float)height + 1.0, + }; + + GLfloat texture_update[] = + { + (obj->view_x - x) / (float)w, + (obj->view_y + obj->view_h - y) / (float)h, + + (obj->view_x + obj->view_w - x) / (float)w, + (obj->view_y + obj->view_h - y) / (float)h, + + (obj->view_x - x) / (float)w, + (obj->view_y - y) / (float)h, + + (obj->view_x + obj->view_w - x) / (float)w, + (obj->view_y - y) / (float)h, + }; + + glUseProgram(program); + uniform_mvp = glGetUniformLocation(program, "mvp"); + uniform_color = glGetUniformLocation(program, "color"); + uniform_bgColor = glGetUniformLocation(program, "bgColor"); + uniform_line_width = glGetUniformLocation(program, "line_width"); + + glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp); + + glUniform4f(uniform_color, fgColor[0], fgColor[1], fgColor[2], 1.0); + glUniform4f(uniform_bgColor, bgColor[0], bgColor[1], bgColor[2], bgColor[3]); + glUniform1f(uniform_line_width, 1.0 / (float)h); + + // draw + glBindBuffer (GL_ARRAY_BUFFER, buffers[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update); + + glBindBuffer (GL_ARRAY_BUFFER, buffers[1]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(texture_update), texture_update); + + glBindVertexArray(vao); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glDisable(GL_BLEND); + + glBindVertexArray(0); + glUseProgram(0); + return 0; +} + +abc_render_t abc_render_hr = +{ + .type = ABC_HTML_HR, + + .draw = __render_draw_hr, + .fini = __render_fini_hr, +};