--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+[title]
+{
+ color:blue;
+}
+</style>
+</head>
+
+<body>
+<h2>Will apply to:</h2>
+<h1 title="Hello world">Hello world</h1>
+<a title="runoob.com" href="https://www.runoob.com/">runoob.com</a>
+<hr>
+<h2>Will not apply to:</h2>
+<p>Hello!</p>
+</body>
+</html>
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);
case ',':
case ':':
case '.':
+ case '[':
+ case ']':
+ case '(':
+ case ')':
// case '#':
if (s->len > 0 && ' ' == s->data[s->len - 1]) {
s->data[s->len - 1] = c->c;
int combinator = -1;
int id = 0;
int class = 0;
+ int attr = 0;
int pseClass = -1;
int pseElement = -1;
int c;
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);
combinator = -1;
id = 0;
class = 0;
+ attr = 0;
pseClass = -1;
pseElement = -1;
case '.':
class++;
break;
+ case '[':
+ attr++;
+ break;
case ':':
if (pseClass < 0)
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);
|| ('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) {
break;
case ABC_CSS_CLASS:
+ case ABC_CSS_ATTR:
scf_list_del(&src->list);
scf_list_add_tail(&h_class, &src->list);
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, 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;
{
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;
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;
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;
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;
}
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;
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;
};
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];
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;
case ' ':
case '>':
case '+':
- case '~':
current = __css_select_by_key(css, current, vec, vec->size - 1, key, len);
j = i;
break;
{
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:
// 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};
#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) \
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)
{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},
{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},
ABC_HTML_ATTR_NAME,
ABC_HTML_ATTR_VALUE,
ABC_HTML_ATTR_CLASS,
+ ABC_HTML_ATTR_TITLE,
ABC_HTML_ATTR_STYLE,
ABC_HTML_ATTR_HREF,
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,
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
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
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);
[ABC_HTML_P] = abc_layout_h1,
[ABC_HTML_BR] = abc_layout_h1,
+ [ABC_HTML_HR] = abc_layout_hr,
[ABC_HTML_IMG] = abc_layout_img,
break;
case ABC_HTML_BR:
+ case ABC_HTML_HR:
case ABC_HTML_TR:
x = root->x + root->left;
y += h;
--- /dev/null
+#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;
+}
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;
[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,
--- /dev/null
+#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,
+};