--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div {
+ background-color: lightgrey;
+ width: 300px;
+ border: 25px solid green;
+ padding: 25px;
+ margin: 25px;
+}
+</style>
+</head>
+
+<body>
+<h2>盒子模型演示</h2>
+
+<p>CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。</p>
+
+<div>这里是盒子内的实际内容。有 25px 内间距,<b>25px 外间距</b>、25px 绿色边框。</div>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>菜鸟教程(runoob.com)</title>
+<style>
+p
+{
+ color:blue;
+ text-align:center;
+}
+.marked
+{
+ background-color:red;
+}
+.marked p, p.marked
+{
+ color:white;
+}
+p.marked { text-decoration:underline;}
+</style>
+</head>
+
+<body>
+<p>这个段落是蓝色文本,居中对齐。</p>
+<div class="marked">
+<p>这个段落不是蓝色文本。</p>
+</div>
+<p>所有 class="marked"元素内的 p 元素指定一个样式,但有不同的文本颜色。</p>
+
+<p class="marked">带下划线的 p 段落。</p>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<style>
+p > b:first-child
+{
+ color:blue;
+}
+
+p:first-child b
+{
+ color:red;
+}
+</style>
+</head>
+
+<body>
+<p>I am a <b>strong</b> man. I am a <b>strong</b> man.</p>
+<p>I am a <b>strong</b> man. I am a <b>strong</b> man.</p>
+<p><b>注意:</b> 当 :first-child 作用于 IE8 以及更早版本的浏览器, !DOCTYPE 必须已经定义.</p>
+</body>
+</html>
{
abc_char_t* c = __io_pop_char(&css->io);
if (!c)
- return -1;
+ return -EINVAL;
if ('*' != c->c) {
__io_push_char(&css->io, c);
while (1) {
c = __io_pop_char(&css->io);
if (!c)
- return -1;
+ return -EINVAL;
int tmp = c->c;
free(c);
c = NULL;
if (EOF == tmp)
- return -1;
+ return -EINVAL;
if ('\n' == tmp) {
css->text_line++;
return 0;
}
-static int __css_parse_value(abc_obj_t* css, abc_obj_t* attr)
+static int __css_end_value(int c)
{
- scf_string_t* value = scf_string_alloc();
- if (!value)
- return -ENOMEM;
+ if (';' == c || '}' == c || EOF == c)
+ return 1;
+ return 0;
+}
+static int __css_parse_str(abc_obj_t* css, scf_string_t* s, int (*end)(int c))
+{
abc_char_t* c = NULL;
- abc_char_t* c2 = NULL;
int c0 = ' ';
while (1) {
c = __io_pop_char(&css->io);
- if (!c) {
- scf_string_free(value);
- return -1;
- }
+ if (!c)
+ return -EINVAL;
css->text_pos += c->len;
if (ret < 0) {
free(c);
- scf_string_free(value);
return ret;
}
}
- if ('\n' == c->c) {
- css->text_line++;
- css->text_pos = 0;
- }
-
- if (';' == c->c || '}' == c->c || EOF == c->c)
+ if (end(c->c))
break;
- if (' ' == c0) {
- if (' ' == c->c || '\t' == c->c || '\r' == c->c || '\n' == c->c) {
- free(c);
- continue;
- }
+ int ret = 0;
+ switch (c->c) { // drop more ' ' & add c to string
+ case '\n':
+ css->text_line++;
+ css->text_pos = 0;
+ case '\t':
+ case '\r':
+ case ' ':
+ if (' ' == c0
+ || '>' == c0 || '+' == c0 || '~' == c0
+ || ',' == c0 || ':' == c0 || '.' == c0 || '#' == c0)
+ break;
- c0 = c->c;
- }
+ ret = scf_string_cat_cstr_len(s, " ", 1);
+ c0 = ' ';
+ break;
- scf_string_cat_cstr_len(value, c->utf8, c->len);
+ case '>':
+ case '+':
+ case '~':
+ case ',':
+ case ':':
+ case '.':
+// case '#':
+ if (s->len > 0 && ' ' == s->data[s->len - 1]) {
+ s->data[s->len - 1] = c->c;
+ c0 = c->c;
+ break;
+ }
+ default:
+ ret = scf_string_cat_cstr_len(s, c->utf8, c->len);
+ c0 = c->c;
+ break;
+ };
free(c);
c = NULL;
+ if (ret < 0)
+ return ret;
}
+ while (s->len > 0 && ' ' == s->data[s->len - 1])
+ s->data[--s->len] = '\0';
+
int tmp = c->c;
free(c);
- c = NULL;
-
- if (attr->value)
- scf_string_free(attr->value);
-
- attr->value = value;
return tmp;
}
-static int __css_parse_attr2(abc_obj_t* css, abc_obj_t* obj, const html_attr_t* attrs, int n_attrs)
+static int __css_parse_value(abc_obj_t* css, abc_obj_t* attr)
{
- scf_string_t* key = scf_string_alloc();
- if (!key)
+ scf_string_t* value = scf_string_alloc();
+ if (!value)
return -ENOMEM;
- abc_char_t* c = NULL;
-
- while (1) {
- c = __io_pop_char(&css->io);
- if (!c) {
- scf_string_free(key);
- return -1;
- }
+ int tmp = __css_parse_str(css, value, __css_end_value);
- css->text_pos += c->len;
-
- if ('}' == c->c || EOF == c->c) {
- free(c);
- scf_string_free(key);
- return '}';
- }
+ switch (tmp) {
+ case ';':
+ case '}':
+ case EOF:
+ if (attr->value)
+ scf_string_free(attr->value);
- if (':' == c->c)
+ attr->value = value;
break;
+ default:
+ scf_string_free(value);
+ break;
+ };
- if ('/' == c->c) {
- int ret = __css_drop_comment(css);
- if (0 == ret) {
- free(c);
- continue;
- }
+ return tmp;
+}
- if (ret < 0) {
- free(c);
- scf_string_free(key);
- return ret;
- }
- }
+static int __css_end_attr(int c)
+{
+ if (':' == c || ';' == c || '}' == c || EOF == c)
+ return 1;
+ return 0;
+}
- if ('_' == c->c
- || '-' == c->c
- || ('a' <= c->c && 'z' >= c->c)) {
- scf_string_cat_cstr_len(key, c->utf8, c->len);
+static int __css_parse_attr2(abc_obj_t* css, abc_obj_t* obj, const html_attr_t* attrs, int n_attrs)
+{
+ scf_string_t* key = scf_string_alloc();
+ if (!key)
+ return -ENOMEM;
- } else if (' ' == c->c || '\t' == c->c || '\r' == c->c) {
+ int tmp = __css_parse_str(css, key, __css_end_attr);
- } else if ('\n' == c->c) {
- css->text_line++;
- css->text_pos = 0;
- } else {
- scf_loge("invalid char '%c:%#x' in CSS attribute, file: %s, line: %d\n", c->c, c->c, css->file->data, css->text_line);
- free(c);
+ switch (tmp) {
+ case ':':
+ break;
+ default:
scf_string_free(key);
- return -1;
- }
-
- free(c);
- c = NULL;
- }
-
- int tmp = c->c;
-
- free(c);
- c = NULL;
+ return tmp;
+ break;
+ };
scf_list_t* l;
abc_obj_t* attr;
scf_loge("invalid HTML attribute '%s' in file: %s, line: %d\n", key->data, css->file->data, css->text_pos);
scf_string_free(key);
- return -1;
+ return -EINVAL;
found:
for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) {
while (1) {
ret = __css_parse_attr2(css, obj, attrs, n_attrs);
- if (ret < 0)
- return ret;
if ('}' == ret || EOF == ret)
break;
+
+ if (ret < 0)
+ return ret;
}
return ret;
}
-static int __css_parse_obj(abc_obj_t* css, abc_char_t* c)
+static int __css_parse_comma(abc_obj_t* css, abc_obj_t* obj)
{
html_label_t* label;
- abc_obj_t* obj;
- scf_string_t* key = scf_string_cstr_len(c->utf8, c->len);
+ scf_list_t h;
- css->text_pos += c->len;
- free(c);
- c = NULL;
+ scf_list_init(&h);
- if (!key)
- return -ENOMEM;
+ int combinator = -1;
+ int id = 0;
+ int class = 0;
+ int pseClass = -1;
+ int pseElement = -1;
+ int c;
+ int i;
+ int j = -1;
+ int k = -1;
- int ret;
- int dot = -1;
- int colon = -1;
- int comma = -1;
+ for (i = obj->text->len - 1; i >= 0; i--) {
+ c = obj->text->data[i];
- while (1) {
- c = __io_pop_char(&css->io);
- if (!c) {
- scf_string_free(key);
- return -1;
+ assert('\t' != c);
+ assert('\r' != c);
+ assert('\n' != c);
+
+ if (' ' == c) {
+ if (combinator < 0 && k >= 0)
+ combinator = i;
+ continue;
}
- css->text_pos += c->len;
+ if (',' == c) {
+ if (k < 0)
+ continue;
- if ('{' == c->c)
- break;
+ assert(j >= 0);
- if ('/' == c->c) {
- ret = __css_drop_comment(css);
- if (0 == ret) {
- free(c);
- continue;
+ scf_string_t* key = scf_string_cstr_len(obj->text->data + j, k + 1 - j);
+ if (!key) {
+ scf_list_clear(&h, abc_obj_t, list, abc_obj_free);
+ return -ENOMEM;
}
- if (ret < 0) {
- free(c);
+ if (id > 0)
+ label = __html_find_label2(ABC_CSS_ID);
+ else if (class > 0)
+ label = __html_find_label2(ABC_CSS_CLASS);
+
+ else if (pseClass > 0)
+ label = __html_find_label2(ABC_CSS_PSE_CLASS);
+ else if (pseElement > 0)
+ label = __html_find_label2(ABC_CSS_PSE_ELEMENT);
+
+ else if (j < combinator && combinator < k)
+ label = __html_find_label2(ABC_CSS_COMBINATOR);
+ else {
+ label = __html_find_label(key->data);
+ if (!label) {
+ scf_loge("css selector '%s' invalid, file: %s, line: %d, pos: %d\n", key->data, obj->file->data, obj->line, j);
+
+ scf_string_free(key);
+ scf_list_clear(&h, abc_obj_t, list, abc_obj_free);
+ return -EINVAL;
+ }
+ }
+
+ abc_obj_t* rule = abc_obj_alloc(obj->file, obj->line, j, label->type);
+ if (!rule) {
+ scf_string_free(key);
+ scf_list_clear(&h, abc_obj_t, list, abc_obj_free);
+ return -ENOMEM;
+ }
+
+ rule->flags = label->flags;
+ rule->keys = label->names;
+ rule->parent = css;
+
+ if (rule->type < ABC_HTML_NB)
scf_string_free(key);
+ else
+ rule->text = key;
+ key = NULL;
+
+ int ret = abc_obj_copy_attrs(rule, obj);
+ if (ret < 0) {
+ abc_obj_free(rule);
+ scf_list_clear(&h, abc_obj_t, list, abc_obj_free);
return ret;
}
+
+ scf_list_add_front(&h, &rule->list);
+
+ combinator = -1;
+ id = 0;
+ class = 0;
+ pseClass = -1;
+ pseElement = -1;
+
+ j = -1;
+ k = -1;
+ continue;
}
- if (' ' == c->c || '\t' == c->c || '\r' == c->c) {
+ j = i;
+ if (k < 0)
+ k = i;
- } else if ('\n' == c->c) {
- css->text_line++;
- css->text_pos = 0;
- } else {
- if (dot < 0 && '.' == c->c)
- dot = key->len;
+ switch (c) {
+ case '#':
+ id++;
+ break;
+ case '.':
+ class++;
+ break;
- if (colon < 0 && ':' == c->c)
- colon = key->len;
+ case ':':
+ if (pseClass < 0)
+ pseClass = i;
+ else if (pseClass - 1 == i) {
+ pseElement = i;
+ pseClass = -1;
+ }
+ break;
+
+ case '>':
+ case '+':
+ case '~':
+ if (combinator < 0)
+ combinator = i;
+ break;
+ default:
+ break;
+ };
+ }
+
+ if (k >= 0) {
+ assert(k < obj->text->len);
+
+ obj->text->data[k + 1] = '\0';
+ obj->text->len = k + 1;
+
+ if (id > 0)
+ label = __html_find_label2(ABC_CSS_ID);
+ else if (class > 0)
+ label = __html_find_label2(ABC_CSS_CLASS);
- if (comma < 0 && ',' == c->c)
- comma = key->len;
+ else if (pseClass > 0)
+ label = __html_find_label2(ABC_CSS_PSE_CLASS);
+ else if (pseElement > 0)
+ label = __html_find_label2(ABC_CSS_PSE_ELEMENT);
- scf_string_cat_cstr_len(key, c->utf8, c->len);
+ else if (0 < combinator && combinator < k)
+ label = __html_find_label2(ABC_CSS_COMBINATOR);
+ else {
+ label = __html_find_label(obj->text->data);
+ if (!label) {
+ scf_loge("css selector '%s' invalid, file: %s, line: %d, pos: %d\n", obj->text->data, obj->file->data, obj->line, k);
+
+ scf_list_clear(&h, abc_obj_t, list, abc_obj_free);
+ return -EINVAL;
+ }
}
- free(c);
- c = NULL;
+ obj->type = label->type;
+ obj->flags = label->flags;
+ obj->keys = label->names;
+ obj->parent = css;
+
+ if (obj->type < ABC_HTML_NB) {
+ scf_string_free(obj->text);
+ obj->text = NULL;
+ }
+
+ scf_list_add_front(&h, &obj->list);
+
+ scf_list_mov2(&css->childs, &h);
+ return 0;
}
- int tmp = c->c;
+ scf_list_clear(&h, abc_obj_t, list, abc_obj_free);
+ return -EINVAL;
+}
+
+static int __css_end_obj(int c)
+{
+ if ('{' == c || EOF == c)
+ return 1;
+ return 0;
+}
+
+static int __css_parse_obj(abc_obj_t* css, abc_char_t* c)
+{
+ html_label_t* label;
+ abc_obj_t* obj;
+ scf_string_t* key = scf_string_cstr_len(c->utf8, c->len);
+
+ css->text_pos += c->len;
free(c);
c = NULL;
- switch (key->data[0])
- {
- case '#':
- dot = 0;
- label = __html_find_label2(ABC_CSS_ID);
- break;
+ if (!key)
+ return -ENOMEM;
- case '.':
- dot = 0;
- label = __html_find_label2(ABC_CSS_CLASS);
+ int tmp = __css_parse_str(css, key, __css_end_obj);
+ switch (tmp) {
+ case '{':
break;
default:
- if (dot >= 0)
- label = __html_find_label2(ABC_CSS_CLASS);
- else if (comma >= 0)
- label = __html_find_label2(ABC_CSS_COMMA);
- else if (colon >= 0)
- label = __html_find_label(key->data + colon);
- else
- label = __html_find_label(key->data);
+ scf_string_free(key);
+ return -EINVAL;
break;
};
+ label = __html_find_label2(ABC_CSS_COMBINATOR);
if (!label) {
scf_loge("invalid HTML label '%s' in file: %s, line: %d\n", key->data, css->file->data, css->text_line);
scf_string_free(key);
- return -1;
+ return -EINVAL;
}
obj = abc_obj_alloc(css->file, css->text_line, css->text_pos, label->type);
return -ENOMEM;
}
- obj->css_dot = dot;
- obj->css_colon = colon;
- obj->flags = label->flags;
- obj->keys = label->names;
- obj->parent = css;
-
- switch (obj->type) {
- case ABC_CSS_ID:
- case ABC_CSS_CLASS:
- case ABC_CSS_COMMA:
+ obj->flags = label->flags;
+ obj->keys = label->names;
+ obj->parent = css;
- case ABC_CSS_LINK:
- case ABC_CSS_VISITED:
- case ABC_CSS_HOVER:
- case ABC_CSS_ACTIVE:
- obj->text = key;
- break;
-
- default:
- scf_string_free(key);
- break;
- };
+ obj->text = key;
key = NULL;
+ int ret;
switch (tmp) {
case '{':
ret = __css_parse_attr(css, obj, label->attrs, label->n_attrs);
}
break;
default:
- ret = 0;
break;
};
- scf_list_add_tail(&css->childs, &obj->list);
- return 0;
+ ret = __css_parse_comma(css, obj);
+ if (ret < 0)
+ abc_obj_free(obj);
+
+ return ret;
}
int abc_css_parse(abc_obj_t* css)
if ('#' == c->c
|| ('a' <= c->c && 'z' >= c->c)
+ || ('A' <= c->c && 'Z' >= c->c)
|| (0x4e00 <= c->c && 0x9fa5 >= c->c)
|| '.' == c->c) {
};
}
-static void __css_set_status(abc_obj_t* obj, abc_obj_t* status)
+static void __css_set_pse(abc_obj_t* obj, abc_obj_t* pse, int colon)
{
- scf_list_t* l;
- abc_obj_t* attr;
- abc_obj_t* attr2;
- abc_obj_t* status2;
+ scf_string_t* s;
+ scf_list_t* l;
+ abc_obj_t* attr;
+ abc_obj_t* attr2;
+ abc_obj_t* pse2;
- if (scf_list_empty(&status->attrs))
+ if (scf_list_empty(&pse->attrs))
return;
- status2 = abc_obj_alloc(status->file, status->line, status->pos, status->type);
- if (!status2)
+ if (colon > 0 && ':' == pse->text->data[colon - 1])
+ colon--;
+
+ char* key = pse->text->data + colon;
+ int len = pse->text->len - colon;
+
+ pse2 = abc_obj_get_attr2(obj, key, len);
+ if (!pse2) {
+ pse2 = abc_obj_alloc(pse->file, pse->line, pse->pos, pse->type);
+ if (!pse2)
+ return;
+
+ pse2->flags = pse->flags;
+ pse2->keys = pse->keys;
+ }
+
+ s = scf_string_clone(pse->text);
+ if (!s)
return;
- status2->flags = status->flags;
- status2->keys = status->keys;
- for (l = scf_list_head(&status->attrs); l != scf_list_sentinel(&status->attrs); l = scf_list_next(l)) {
- attr = scf_list_data(l, abc_obj_t, list);
+ if (pse2->text)
+ scf_string_free(pse2->text);
- if (attr->value && attr->value->len > 0)
- {
- if (ABC_CSS_LINK == status->type)
- __css_set_attr(obj, attr);
+ pse2->text = s;
- attr2 = abc_obj_alloc(attr->file, attr->line, attr->pos, attr->type);
- if (!attr2) {
- abc_obj_free(status2);
- return;
- }
+ for (l = scf_list_head(&pse->attrs); l != scf_list_sentinel(&pse->attrs); l = scf_list_next(l)) {
+ attr = scf_list_data(l, abc_obj_t, list);
- attr2->value = scf_string_clone(attr->value);
- if (!attr2->value) {
- abc_obj_free(attr2);
- abc_obj_free(status2);
- return;
- }
+ if (!attr->value || 0 == attr->value->len)
+ continue;
- attr2->keys = attr->keys;
- attr2->flags = attr->flags;
+ attr2 = abc_obj_alloc(attr->file, attr->line, attr->pos, attr->type);
+ if (!attr2)
+ return;
- scf_list_add_tail(&status2->attrs, &attr2->list);
+ attr2->value = scf_string_clone(attr->value);
+ if (!attr2->value) {
+ abc_obj_free(attr2);
+ return;
}
- }
- scf_list_add_tail(&obj->attrs, &status2->list);
+ attr2->keys = attr->keys;
+ attr2->flags = attr->flags;
+
+ scf_list_add_tail(&pse2->attrs, &attr2->list);
+
+ switch (pse->css_pse_type)
+ {
+ case ABC_CSS_FIRST_CHILD:
+ case ABC_CSS_LINK:
+ __css_set_attr(obj, attr);
+ break;
+ default:
+ break;
+ };
+ }
}
static void __css_merge(abc_obj_t* dst, abc_obj_t* src)
else
scf_list_mov2(&html->css->childs, &css->childs);
- scf_list_t h;
scf_list_t* s;
scf_list_t* d;
abc_obj_t* src; // merge from
for (d = s; d != scf_list_sentinel(&html->css->childs); d = scf_list_prev(d)) {
dst = scf_list_data(d, abc_obj_t, list);
- if (src->type != dst->type)
- continue;
-
- int ret = -1;
-
- switch (dst->type) {
- case ABC_CSS_ID:
- case ABC_CSS_CLASS:
-
- case ABC_CSS_LINK:
- case ABC_CSS_VISITED:
- case ABC_CSS_HOVER:
- case ABC_CSS_ACTIVE:
- ret = scf_string_cmp(src->text, dst->text);
- break;
-
- default:
- ret = __html_strcmp(src->keys[0], dst->keys[0]);
- break;
- };
+ if (src->type == dst->type) {
+ if (src->type > ABC_HTML_NB && scf_string_cmp(src->text, dst->text))
+ continue;
- if (0 == ret) {
__css_merge(dst, src);
scf_list_del(&src->list);
}
}
- scf_list_init(&h);
+ scf_list_t h_id;
+ scf_list_t h_class;
+ scf_list_t h_pse_class;
+ scf_list_t h_pse_element;
+
+ scf_list_init(&h_id);
+ scf_list_init(&h_class);
+ scf_list_init(&h_pse_class);
+ scf_list_init(&h_pse_element);
for (s = scf_list_head(&html->css->childs); s != scf_list_sentinel(&html->css->childs); ) {
src = scf_list_data(s, abc_obj_t, list);
switch (src->type) {
case ABC_CSS_ID:
+ scf_list_del(&src->list);
+ scf_list_add_tail(&h_id, &src->list);
+ break;
+
case ABC_CSS_CLASS:
+ scf_list_del(&src->list);
+ scf_list_add_tail(&h_class, &src->list);
+ break;
- case ABC_CSS_LINK:
- case ABC_CSS_VISITED:
- case ABC_CSS_HOVER:
- case ABC_CSS_ACTIVE:
+ case ABC_CSS_PSE_CLASS:
+ scf_list_del(&src->list);
+ scf_list_add_tail(&h_pse_class, &src->list);
+ break;
+
+ case ABC_CSS_PSE_ELEMENT:
scf_list_del(&src->list);
- scf_list_add_tail(&h, &src->list);
+ scf_list_add_tail(&h_pse_element, &src->list);
break;
default:
break;
};
}
- scf_list_mov2(&html->css->childs, &h);
+ // sort css priority, the last is the highest
+ scf_list_mov2(&html->css->childs, &h_pse_element);
+ scf_list_mov2(&html->css->childs, &h_pse_class);
+ scf_list_mov2(&html->css->childs, &h_class);
+ scf_list_mov2(&html->css->childs, &h_id);
return 0;
}
-int abc_css_use(abc_html_t* html, abc_obj_t* obj)
+static abc_obj_t* __css_filter_pse(abc_obj_t* current, abc_obj_t* pse)
{
- if (!html || !obj)
- return -EINVAL;
+ scf_list_t* l;
+ abc_obj_t* parent = current->parent;
+ abc_obj_t* tmp;
- if (!html->css)
- return 0;
+ switch (pse->type)
+ {
+ case ABC_CSS_FIRST_CHILD:
+ if (!parent)
+ return NULL;
+
+ for (l = scf_list_prev(¤t->list); l != scf_list_sentinel(&parent->childs); l = scf_list_prev(l)) {
+ tmp = scf_list_data(l, abc_obj_t, list);
+ if (tmp->type == current->type)
+ return NULL;
+ }
+ break;
+
+ default:
+ break;
+ };
+
+ return current;
+}
+
+static abc_obj_t* __css_select_by_key(abc_obj_t* css, abc_obj_t* current, scf_vector_t* vec, int next, const char* key, int len)
+{
scf_list_t* l;
- scf_list_t* l2;
- abc_obj_t* css;
- abc_obj_t* __obj;
- abc_obj_t* attr;
+ abc_obj_t* tmp;
+ abc_obj_t* pse;
- for (l = scf_list_head(&html->css->childs); l != scf_list_sentinel(&html->css->childs); l = scf_list_next(l)) {
- css = scf_list_data(l, abc_obj_t, list);
+ assert(next >= 0 && next < vec->size);
- if (ABC_CSS_ID == css->type || ABC_CSS_CLASS == css->type)
- {
- attr = abc_obj_get_attr(obj, css->type);
- if (!attr)
- continue;
+ int j = (intptr_t)vec->data[next];
+ int k;
+ int c = 0;
+ if (j < css->text->len)
+ c = css->text->data[j];
- if (__html_strcmp(attr->value->data, css->text->data + css->css_dot + 1))
- continue;
+ switch (c) {
+ case ' ':
+ for (current = current->parent; current; current = current->parent)
+ {
+ if (!abc_obj_cmp_keys(current, key, len))
+ break;
+ }
+ break;
- if (css->css_dot > 0) {
- if (__html_strncmp(obj->keys[0], css->text->data, css->css_dot))
- continue;
+ case '>':
+ current = current->parent;
+
+ if (abc_obj_cmp_keys(current, key, 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);
+
+ if (abc_obj_cmp_keys(current, key, 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);
+
+ if (!abc_obj_cmp_keys(tmp, key, len))
+ break;
}
- } else if (ABC_CSS_COMMA == css->type) {
- int c;
- int c0 = ' ';
- uint8_t* p0 = NULL;
- uint8_t* p = css->text->data;
+ if (l == scf_list_sentinel(¤t->parent->childs))
+ return NULL;
- do {
- c = *p;
+ current = tmp;
+ break;
- if (!c || ' ' == c || '\t' == c || '\r' == c || '\n' == c || ',' == c) {
- if ( ' ' == c0 || '\t' == c0 || '\r' == c0 || '\n' == c0 || ',' == c0)
- goto next;
+ case ':':
+ assert(next - 1 >= 0 && next - 1 < vec->size);
- if (__html_strncmp(obj->keys[0], p0, (size_t)(p - p0))) {
- p0 = NULL;
- goto next;
- }
+ scf_logd("current: %s, key: %.*s, j: %d, next: %s\n", current->keys[0], len, key, j, css->text->data + j);
- abc_obj_set_css(obj, css);
+ k = (intptr_t) vec->data[next - 1];
+ if (k <= j)
+ return NULL;
+
+ current = __css_select_by_key(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;
+
+ 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:
+ if (abc_obj_cmp_keys(current, key, 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, int type, const char* key, int len)
+{
+ scf_list_t* l;
+ abc_obj_t* tmp;
+ abc_obj_t* attr;
+
+ 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_attr(current, type);
+
+ if (attr && !__html_strncmp(attr->value->data, key, len))
break;
- } else {
- if (!p0)
- p0 = p;
- }
-next:
- c0 = c;
- p++;
- } while (c);
+ }
+ break;
- continue;
+ case '>':
+ current = current->parent;
+ if (current) {
+ attr = abc_obj_get_attr(current, type);
+
+ if (!attr || __html_strncmp(attr->value->data, key, len))
+ return NULL;
+ }
+ break;
- } else if (ABC_CSS_LINK == css->type
- || ABC_CSS_VISITED == css->type
- || ABC_CSS_HOVER == css->type
- || ABC_CSS_ACTIVE == css->type) {
+ case '+':
+ if (!current->parent)
+ return NULL;
- if (css->css_colon > 0) {
- if (!__html_strncmp (obj->keys[0], css->text->data, css->css_colon))
- __css_set_status(obj, css);
+ 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_attr(current, type);
+
+ if (!attr || __html_strncmp(attr->value->data, key, 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_attr(tmp, type);
+
+ if (attr && !__html_strncmp(attr->value->data, key, len))
+ break;
}
- continue;
- } else if (css->type != obj->type)
- continue;
+ if (l == scf_list_sentinel(¤t->parent->childs))
+ return NULL;
+
+ current = tmp;
+ break;
+ default:
+ attr = abc_obj_get_attr(current, type);
+
+ if (!attr || __html_strncmp(attr->value->data, key, len))
+ return NULL;
+ break;
+ };
+
+ return current;
+}
+
+static int __css_use_complex(abc_obj_t* css, abc_obj_t* obj)
+{
+ scf_vector_t* vec;
+ abc_obj_t* current = obj;
+
+ int colon = -1;
+ int c;
+ int i;
+ int j = css->text->len;
+
+ vec = scf_vector_alloc();
+ if (!vec)
+ return -ENOMEM;
+
+ int ret = scf_vector_add(vec, (void*)(intptr_t)j);
+ if (ret < 0)
+ goto end;
+
+ css->css_pse_type = 0;
+
+ for (i = css->text->len - 1; i >= 0; i--) {
+ c = css->text->data[i];
+
+ assert('\t' != c);
+ assert('\r' != c);
+ assert('\n' != c);
+
+ char* key = css->text->data + i + 1;
+ int len = j - i - 1;
+
+ ret = 0;
+ switch (c) {
+ case '#':
+ current = __css_select_by_attr(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);
+ j = i;
+ break;
+
+ case ':':
+ if (colon < 0)
+ colon = i;
+
+ if (i > 0 && ':' == css->text->data[i - 1])
+ {
+ if (j < css->text->len) {
+ scf_loge("pse element must be the last for combinators '%s', file: %s, line: %d\n",
+ css->text->data, css->file->data, css->text_line);
+ ret = 0;
+ goto end;
+ }
+ } else
+ j = i;
+ break;
+
+ case ' ':
+ case '>':
+ case '+':
+ case '~':
+ current = __css_select_by_key(css, current, vec, vec->size - 1, key, len);
+ j = i;
+ break;
+ default:
+ if (0 == i)
+ current = __css_select_by_key(css, current, vec, vec->size - 1, css->text->data, j);
+ break;
+ };
+
+ if (!current) {
+ ret = 0;
+ goto end;
+ }
+ if (j == i) {
+ ret = scf_vector_add(vec, (void*)(intptr_t)j);
+ if (ret < 0)
+ goto end;
+ }
+ }
+
+ if (colon < 0)
abc_obj_set_css(obj, css);
+ else
+ __css_set_pse(obj, css, colon);
+
+ ret = 0;
+end:
+ scf_vector_free(vec);
+ return ret;
+}
+
+int abc_css_use(abc_html_t* html, abc_obj_t* obj)
+{
+ if (!html || !obj)
+ return -EINVAL;
+
+ if (!html->css)
+ return 0;
+
+ scf_list_t* l;
+ abc_obj_t* css;
+ abc_obj_t* attr;
+
+ for (l = scf_list_head(&html->css->childs); l != scf_list_sentinel(&html->css->childs); l = scf_list_next(l)) {
+ css = scf_list_data(l, abc_obj_t, list);
+
+ switch (css->type)
+ {
+ case ABC_CSS_ID:
+ case ABC_CSS_CLASS:
+ case ABC_CSS_PSE_CLASS:
+ case ABC_CSS_PSE_ELEMENT:
+ case ABC_CSS_COMBINATOR:
+ __css_use_complex(css, obj);
+ break;
+
+ default:
+ if (css->type == obj->type)
+ abc_obj_set_css(obj, css);
+ break;
+ };
}
// for inline css below
static char* css_Cornsilk[] = {"cornsilk", NULL};
static char* css_Crimson[] = {"crimson", "深红", "绯红", NULL};
static char* css_Cyan[] = {"cyan", NULL};
-static char* css_DarkBlue[] = {"darkblue", "深蓝", "黛蓝", NULL};
-static char* css_DarkCyan[] = {"darkcyan", NULL};
-static char* css_DarkGoldenRod[] = {"darkgoldenrod", NULL};
-static char* css_DarkGray[] = {"darkgray", NULL};
-static char* css_DarkGreen[] = {"darkgreen", "暗绿", NULL};
-static char* css_DarkKhaki[] = {"darkkhaki", NULL};
-static char* css_DarkMagenta[] = {"darkmagenta", NULL};
-static char* css_DarkOliveGreen[] = {"darkolivegreen", NULL};
-static char* css_DarkOrange[] = {"darkorange", NULL};
-static char* css_DarkOrchid[] = {"darkorchid", NULL};
-static char* css_DarkRed[] = {"darkred", "暗红", NULL};
-static char* css_DarkSalmon[] = {"darksalmon", NULL};
-static char* css_DarkSeaGreen[] = {"darkseagreen", NULL};
-static char* css_DarkSlateBlue[] = {"darkslateblue", NULL};
-static char* css_DarkSlateGray[] = {"darkslategray", NULL};
-static char* css_DarkTurquoise[] = {"darkturquoise", NULL};
-static char* css_DarkViolet[] = {"darkviolet", NULL};
-static char* css_DeepPink[] = {"deeppink", NULL};
-static char* css_DeepSkyBlue[] = {"deepskyblue", NULL};
-static char* css_DimGray[] = {"dimgray", NULL};
-static char* css_DodgerBlue[] = {"dodgerblue", NULL};
-static char* css_FireBrick[] = {"firebrick", NULL};
-static char* css_FloralWhite[] = {"floralwhite", NULL};
-static char* css_ForestGreen[] = {"forestgreen", NULL};
+static char* css_DarkBlue[] = {"DarkBlue", "深蓝", "黛蓝", NULL};
+static char* css_DarkCyan[] = {"DarkCyan", NULL};
+static char* css_DarkGoldenRod[] = {"DarkGoldenRod", NULL};
+static char* css_DarkGray[] = {"DarkGray", "DarkGrey", NULL};
+static char* css_DarkGreen[] = {"DarkGreen", "暗绿", NULL};
+static char* css_DarkKhaki[] = {"DarkKhaki", NULL};
+static char* css_DarkMagenta[] = {"DarkMagenta", NULL};
+static char* css_DarkOliveGreen[] = {"DarkOliveGreen", NULL};
+static char* css_DarkOrange[] = {"DarkOrange", NULL};
+static char* css_DarkOrchid[] = {"DarkOrchid", NULL};
+static char* css_DarkRed[] = {"DarkRed", "暗红", NULL};
+static char* css_DarkSalmon[] = {"DarkSalmon", NULL};
+static char* css_DarkSeaGreen[] = {"DarkSeaGreen", NULL};
+static char* css_DarkSlateBlue[] = {"DarkSlateBlue", NULL};
+static char* css_DarkSlateGray[] = {"DarkSlateGray", "DarkSlateGrey", NULL};
+static char* css_DarkTurquoise[] = {"DarkTurquoise", NULL};
+static char* css_DarkViolet[] = {"DarkViolet", NULL};
+static char* css_DeepPink[] = {"DeepPink", NULL};
+static char* css_DeepSkyBlue[] = {"DeepskyBlue", NULL};
+static char* css_DimGray[] = {"DimGray", "DimGrey", NULL};
+static char* css_DodgerBlue[] = {"DodgerBlue", NULL};
+static char* css_FireBrick[] = {"FireBrick", NULL};
+static char* css_FloralWhite[] = {"FloralWhite", NULL};
+static char* css_ForestGreen[] = {"ForestGreen", NULL};
static char* css_fuchsia[] = {"fuchsia", "紫红", "洋红", NULL};
static char* css_Gainsboro[] = {"Gainsboro", NULL};
static char* css_GhostWhite[] = {"GhostWhite", NULL};
static char* css_Gold[] = {"Gold", "金", "金黄", NULL};
static char* css_GoldenRod[] = {"GoldenRod", NULL};
-static char* css_Gray[] = {"Gray", "灰", NULL};
+static char* css_Gray[] = {"Gray", "Grey", "灰", NULL};
static char* css_green[] = {"green", "绿", NULL};
static char* css_GreenYellow[] = {"GreenYellow", "黄绿", NULL};
static char* css_LightCyan[] = {"LightCyan", NULL};
static char* css_LightGoldenRodYellow[] = {"LightGoldenRodYellow", NULL};
-static char* css_LightGray[] = {"LightGray", "浅灰", NULL};
-static char* css_LightGreen[] = {"LightGreen", "浅绿", NULL};
+static char* css_LightGray[] = {"LightGray", "LightGrey", "浅灰", NULL};
+static char* css_LightGreen[] = {"LightGreen", "浅绿", NULL};
static char* css_LightPink[] = {"LightPink", NULL};
static char* css_LightSalmon[] = {"LightSalmon", NULL};
-static char* css_LightSeaGreen[] = {"LightSeaGreen", "浅海绿", NULL};
-static char* css_LightSkyBlue[] = {"LightSkyBlue", "浅天蓝", NULL};
-static char* css_LightSlateGray[] = {"LightSlateGray", NULL};
+static char* css_LightSeaGreen[] = {"LightSeaGreen", "浅海绿", NULL};
+static char* css_LightSkyBlue[] = {"LightSkyBlue", "浅天蓝", NULL};
+static char* css_LightSlateGray[] = {"LightSlateGray", "LightSlateGrey", NULL};
static char* css_LightSteelBlue[] = {"LightSteelBlue", NULL};
static char* css_LightYellow[] = {"LightYellow", "浅黄", NULL};
static char* css_Lime[] = {"Lime", NULL};
static char* css_SeaGreen[] = {"SeaGreen", "海绿", NULL};
static char* css_SeaShell[] = {"SeaShell", NULL};
static char* css_Sienna[] = {"Sienna", NULL};
-static char* css_Silver[] = {"Silver", "银", NULL};
-static char* css_SkyBlue[] = {"SkyBlue", "天蓝", NULL};
+static char* css_Silver[] = {"Silver", "银", NULL};
+static char* css_SkyBlue[] = {"SkyBlue", "天蓝", NULL};
static char* css_SlateBlue[] = {"SlateBlue", NULL};
-static char* css_SlateGray[] = {"SlateGray", NULL};
-static char* css_Snow[] = {"Snow", "雪白", NULL};
-static char* css_SpringGreen[] = {"SpringGreen", "春绿", NULL};
+static char* css_SlateGray[] = {"SlateGray", "SlateGrey", NULL};
+static char* css_Snow[] = {"Snow", "雪白", NULL};
+static char* css_SpringGreen[] = {"SpringGreen", "春绿", NULL};
static char* css_SteelBlue[] = {"SteelBlue", NULL};
static char* css_Tan[] = {"Tan", NULL};
static char* script_keys[] = {"script", "脚本", NULL};
static char* style_keys[] = {"style", "样式", NULL};
-static char* css_id_keys[] = {"#", NULL};
-static char* css_class_keys[] = {".", NULL};
-static char* css_comma_keys[] = {",", NULL};
+static char* css_id_keys[] = {"#", NULL};
+static char* css_class_keys[] = {".", NULL};
+static char* css_other_keys[] = {"*", NULL};
+static char* css_pse_class_keys[] = {":", NULL};
+static char* css_pse_element_keys[] = {"::", NULL};
-static char* css_link_keys[] = {":link", ":未访问", NULL};
-static char* css_visited_keys[] = {":visited", ":已访问", NULL};
-static char* css_hover_keys[] = {":hover", ":已关注", NULL};
-static char* css_active_keys[] = {":active", ":已激活", NULL};
+static char* css_link_keys[] = {":link", "未访问", NULL};
+static char* css_visited_keys[] = {":visited", "已访问", NULL};
+static char* css_hover_keys[] = {":hover", "正在指向", NULL};
+static char* css_active_keys[] = {":active", "正在点击", NULL};
+
+static char* css_first_child_keys[] = {":first-child", "第1个子元素", "第一个子元素", NULL};
static html_attr_t html_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},
+ {charset_keys, "", ABC_HTML_ATTR_CHARSET, ABC_HTML_FLAG_SHOW},
};
static html_attr_t body_attrs[] =
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
+
+ {css_first_child_keys, "", ABC_CSS_FIRST_CHILD, ABC_HTML_FLAG_SHOW},
};
static html_attr_t css_id_attrs[] =
ABC_CSS_FONT(SimHei, 16, , bold)
ABC_CSS_TEXT(left, )
+
+ {css_first_child_keys, "", ABC_CSS_FIRST_CHILD, ABC_HTML_FLAG_SHOW},
};
static html_attr_t i_attrs[] =
ABC_CSS_FONT(SimSong, 16, , italic)
ABC_CSS_TEXT(left, )
+
+ {css_first_child_keys, "", ABC_CSS_FIRST_CHILD, ABC_HTML_FLAG_SHOW},
};
static html_attr_t a_attrs[] =
ABC_CSS_FONT(SimSong, 16, blue, )
ABC_CSS_TEXT(left, underline)
- {href_keys, "", ABC_HTML_ATTR_HREF, ABC_HTML_FLAG_SHOW},
+ {href_keys, "", ABC_HTML_ATTR_HREF, ABC_HTML_FLAG_SHOW},
+ {css_link_keys, "", ABC_CSS_LINK, ABC_HTML_FLAG_SHOW},
+ {css_visited_keys, "", ABC_CSS_VISITED, ABC_HTML_FLAG_SHOW},
+ {css_hover_keys, "", ABC_CSS_HOVER, ABC_HTML_FLAG_SHOW},
+ {css_active_keys, "", ABC_CSS_ACTIVE, ABC_HTML_FLAG_SHOW},
};
static html_attr_t link_attrs[] =
static html_label_t html_labels[] =
{
{html_keys, ABC_HTML, abc_number_of(html_attrs), html_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
- {meta_keys, ABC_HTML_META, abc_number_of(meta_attrs), meta_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SINGLE},
+ {meta_keys, ABC_HTML_META, abc_number_of(meta_attrs), meta_attrs, ABC_HTML_FLAG_OPEN | ABC_HTML_FLAG_SHOW},
{head_keys, ABC_HTML_HEAD, 0, NULL, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{title_keys, ABC_HTML_TITLE, 0, NULL, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{body_keys, ABC_HTML_BODY, abc_number_of(body_attrs), body_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{hr_keys, ABC_HTML_HR, 0, NULL, 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_CLOSE | ABC_HTML_FLAG_SINGLE | ABC_HTML_FLAG_SHOW},
+ {img_keys, ABC_HTML_IMG, abc_number_of(img_attrs), img_attrs, ABC_HTML_FLAG_OPEN | ABC_HTML_FLAG_SHOW},
{link_keys, ABC_HTML_LINK, abc_number_of(link_attrs), link_attrs, ABC_HTML_FLAG_OPEN | ABC_HTML_FLAG_SHOW},
{form_keys, ABC_HTML_FORM, abc_number_of(form_attrs), form_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{script_keys, ABC_HTML_SCRIPT, abc_number_of(script_attrs), script_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{style_keys, ABC_HTML_STYLE, 0, NULL, ABC_HTML_FLAG_CLOSE | 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_comma_keys, ABC_CSS_COMMA, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
-
- {css_link_keys, ABC_CSS_LINK, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
- {css_visited_keys, ABC_CSS_VISITED, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
- {css_hover_keys, ABC_CSS_HOVER, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
- {css_active_keys, ABC_CSS_ACTIVE, abc_number_of(css_id_attrs), css_id_attrs, ABC_HTML_FLAG_CLOSE | 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_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},
};
static int __html_parse_obj(abc_html_t* html, abc_char_t* c);
abc_obj_t* mov = NULL;
if ('/' != c->c) {
- if (ABC_HTML_BODY == obj->type
- || ABC_HTML_H1 == obj->type
- || ABC_HTML_H2 == obj->type
- || ABC_HTML_H3 == obj->type
- || ABC_HTML_H4 == obj->type
- || ABC_HTML_H5 == obj->type
- || ABC_HTML_H6 == obj->type
- || ABC_HTML_P == obj->type) {
-
- if (obj->text) {
+ if (obj->text) {
#define HTML_MOV_TEXT() \
- do { \
- mov = abc_obj_alloc(NULL, obj->line, obj->pos, obj->type); \
- if (!mov) \
- return -ENOMEM; \
- mov->text = obj->text; \
- obj->text = NULL; \
- mov->parent = obj; \
- mov->flags = obj->flags; \
- scf_list_add_tail(&obj->childs, &mov->list); \
- scf_logd("--- %s, %s\n", obj->keys[0], mov->text->data); \
- } while (0)
-
- HTML_MOV_TEXT();
- }
+ do { \
+ mov = abc_obj_alloc(NULL, obj->line, obj->pos, ABC_CORE_TEXT); \
+ if (!mov) \
+ return -ENOMEM; \
+ mov->text = obj->text; \
+ obj->text = NULL; \
+ mov->parent = obj; \
+ mov->flags = obj->flags; \
+ scf_list_add_tail(&obj->childs, &mov->list); \
+ scf_logd("--- %s, %s\n", obj->keys[0], mov->text->data); \
+ } while (0)
+
+ HTML_MOV_TEXT();
}
int ret = __html_parse_obj(html, c);
return ret;
}
- if (obj->text && !scf_list_empty(&obj->childs)) {
-
- if (ABC_HTML_BODY == obj->type
- || ABC_HTML_H1 == obj->type
- || ABC_HTML_H2 == obj->type
- || ABC_HTML_H3 == obj->type
- || ABC_HTML_H4 == obj->type
- || ABC_HTML_H5 == obj->type
- || ABC_HTML_H6 == obj->type
- || ABC_HTML_P == obj->type)
- HTML_MOV_TEXT();
- }
+ if (obj->text && !scf_list_empty(&obj->childs))
+ HTML_MOV_TEXT();
html->pos++;
free(c);
if ('_' == c->c
|| '-' == c->c
|| ':' == c->c
- || ('a' <= c->c && 'z' >= c->c)) {
+ || ('a' <= c->c && 'z' >= c->c)
+ || ('Z' <= c->c && 'Z' >= c->c)) {
scf_string_cat_cstr_len(key, c->utf8, c->len);
} else if (' ' == c->c) {
c = NULL;
}
- int tmp = c->c;
-
free(c);
c = NULL;
}
if (('a' <= c->c && 'z' >= c->c)
+ || ('A' <= c->c && 'Z' >= c->c)
|| (0x4e00 <= c->c && 0x9fa5 >= c->c)) {
int ret = __html_parse_obj(html, c);
return NULL;
}
+int abc_obj_cmp_keys(abc_obj_t* obj, const char* name, size_t len)
+{
+ int i;
+ for (i = 0; obj->keys[i]; i++) {
+
+ if (!__html_strncmp(obj->keys[i], name, len))
+ return 0;
+ }
+ return -1;
+}
+
+int abc_obj_copy_attrs(abc_obj_t* dst, abc_obj_t* src)
+{
+ scf_list_t* l;
+ abc_obj_t* attr;
+ abc_obj_t* copy;
+
+ for (l = scf_list_head(&src->attrs); l != scf_list_sentinel(&src->attrs); l = scf_list_next(l)) {
+ attr = scf_list_data(l, abc_obj_t, list);
+
+ copy = abc_obj_alloc(attr->file, attr->line, attr->pos, attr->type);
+ if (!copy)
+ return -ENOMEM;
+
+ copy->value = scf_string_clone(attr->value);
+ if (!copy->value) {
+ abc_obj_free(copy);
+ return -ENOMEM;
+ }
+
+ copy->keys = attr->keys;
+ copy->flags = attr->flags;
+
+ scf_list_add_tail(&dst->attrs, ©->list);
+ }
+
+ return 0;
+}
+
int abc_obj_set_attr(abc_obj_t* obj, int key, const char* value, size_t len)
{
scf_string_t* s;
return -EINVAL;
}
+abc_obj_t* abc_obj_get_attr2(abc_obj_t* obj, const char* key, int len)
+{
+ scf_list_t* l;
+ abc_obj_t* attr;
+
+ 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_obj_cmp_keys(attr, key, len))
+ return attr;
+ }
+
+ return NULL;
+}
+
abc_obj_t* abc_obj_get_attr(abc_obj_t* obj, int key)
{
- scf_list_t* l;
- abc_obj_t* attr;
+ scf_list_t* l;
+ abc_obj_t* attr;
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);
{
ABC_HTML,
ABC_HTML_TITLE,
+ ABC_HTML_META,
ABC_HTML_HEAD,
ABC_HTML_BODY,
ABC_HTML_INPUT,
ABC_HTML_CENTER,
- ABC_HTML_META,
-
ABC_HTML_TABLE,
ABC_HTML_TR,
ABC_HTML_TH,
ABC_HTML_UL,
ABC_HTML_LI,
- ABC_HTML_NB, // total HTML objects
+ ABC_CORE_TEXT, // not HTML label, only for browser core to layout & draw text
+ ABC_HTML_NB, // total HTML objects
ABC_HTML_ATTR_ID,
ABC_HTML_ATTR_TYPE,
ABC_HTML_ATTR_CONTROLS,
// css objects
- ABC_CSS_LINK,
- ABC_CSS_VISITED,
- ABC_CSS_HOVER,
- ABC_CSS_ACTIVE,
-
ABC_CSS_LIST_STYLE,
ABC_CSS_LIST_STYLE_TYPE,
ABC_CSS_LIST_STYLE_IMAGE,
ABC_CSS_BORDER_COLLAPSE,
- ABC_CSS_COMMA,
+ // css pse class or pse element, first status onload
+ ABC_CSS_FIRST_CHILD,
+ ABC_CSS_LINK,
+
+ // status after user operations
+ ABC_CSS_VISITED,
+ ABC_CSS_HOVER,
+ ABC_CSS_ACTIVE,
// ... new css add here
- // css enum from html attrs above
+ // css selectors
+ ABC_CSS_PSE_CLASS,
+ ABC_CSS_PSE_ELEMENT,
+ ABC_CSS_COMBINATOR,
+
+ // css selectors from html attrs above
ABC_CSS_ID = ABC_HTML_ATTR_ID,
ABC_CSS_CLASS = ABC_HTML_ATTR_CLASS,
};
int start;
int len;
+
+ int w;
+ int h;
};
struct abc_obj_s
#define ABC_HTML_FLAG_SHOW 4
uint32_t flags;
+ int d; // margin + border + padding
+ int w0;
+ int h0;
+
int x;
int y;
int w;
int text_pos;
abc_io_t io;
- int css_dot; // dot position for css class
- int css_colon; // colon position for css status
+ int css_pse_type;
scf_string_t* file; // file name
int line; // line
uint32_t clicked:1;
uint32_t visited:1;
+
+ uint32_t w_set:1;
+ uint32_t h_set:1;
};
abc_obj_t* abc_obj_alloc(scf_string_t* file, int line, int pos, int type);
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_cmp_keys (abc_obj_t* obj, const char* name, size_t len);
+int abc_obj_copy_attrs(abc_obj_t* dst, abc_obj_t* src);
+
void abc_obj_set_css (abc_obj_t* obj, abc_obj_t* css);
int abc_obj_set_attr (abc_obj_t* obj, int key, const char* value, size_t len);
+
+abc_obj_t* abc_obj_get_attr2(abc_obj_t* obj, const char* key, int len);
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);
CFILES += abc_layout_head.c
CFILES += abc_layout_body.c
CFILES += abc_layout_div.c
+
+CFILES += abc_layout_text.c
CFILES += abc_layout_h1.c
CFILES += abc_layout_img.c
CFILES += abc_render_title.c
CFILES += abc_render_head.c
CFILES += abc_render_body.c
-CFILES += abc_render_div.c
CFILES += __render_border.c
CFILES += __render_bg_image.c
CFILES += __render_text.c
+CFILES += abc_render_text.c
CFILES += abc_render_empty.c
return 0;
}
-void __draw_text(cairo_text_extents_t* extents, cairo_t* cr, const char* text, double x, double y, int line_type, int line_width)
+void __draw_text(cairo_text_extents_t* extents, cairo_t* cr, const char* text, double x, double y, double y_bearing, int line_type, int line_width)
{
cairo_text_extents(cr, text, extents);
double w = extents->width;
+ if (extents->y_bearing > y_bearing)
+ extents->y_bearing = y_bearing;
+
x += extents->x_bearing;
y -= extents->y_bearing;
}
if (!obj->text_splits) {
- __draw_text(&extents, cr, obj->text->data, obj->parent->padding, 0.0, line_type, line_width);
+ __draw_text(&extents, cr, obj->text->data, obj->parent->padding, 0.0, obj->y_bearing, line_type, line_width);
return 0;
}
return -ENOMEM;
}
- __draw_text(&extents, cr, s->data, x, y, line_type, line_width);
+ __draw_text(&extents, cr, s->data, x, y, obj->y_bearing, line_type, line_width);
y += extents.height;
obj->text_splits = t->next;
int __init_buffers(GLuint* vao, GLuint buffers[2]);
-int __init_text(cairo_t* cr, abc_obj_t* obj, int num_flag);
+void __draw_text(cairo_text_extents_t* extents, cairo_t* cr, const char* text, double x, double y, double y_bearing, int line_type, int line_width);
+
+int __init_text (cairo_t* cr, abc_obj_t* obj, int num_flag);
+int __layout_text(cairo_t* cr, abc_obj_t* obj, int x, int width, cairo_text_extents_t* extents);
extern abc_render_t __render_border;
extern abc_render_t __render_bg_image;
int abc_layout_head (abc_layout_t* layout, abc_obj_t* obj, int width, int height);
int abc_layout_body (abc_layout_t* layout, abc_obj_t* obj, int width, int height);
+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_img (abc_layout_t* layout, abc_obj_t* obj, int width, int height);
{
[ABC_HTML] = abc_layout_html,
[ABC_HTML_TITLE] = abc_layout_title,
+ [ABC_HTML_META] = abc_layout_empty,
[ABC_HTML_HEAD] = abc_layout_head,
[ABC_HTML_BODY] = abc_layout_body,
[ABC_HTML_DIV] = abc_layout_div,
- [ABC_HTML_META] = abc_layout_empty,
+ [ABC_CORE_TEXT] = abc_layout_text,
[ABC_HTML_H1] = abc_layout_h1,
[ABC_HTML_H2] = abc_layout_h1,
[ABC_HTML_STYLE] = abc_layout_empty,
[ABC_HTML_LINK] = abc_layout_empty,
- [ABC_HTML_B] = abc_layout_h1,
- [ABC_HTML_I] = abc_layout_h1,
+ [ABC_HTML_B] = abc_layout_text,
+ [ABC_HTML_I] = abc_layout_text,
};
int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
abc_obj_t* parent = root->parent;
abc_obj_t* attr;
- attr = abc_obj_get_attr(root, ABC_HTML_ATTR_TEXT_ALIGN);
- if (attr) {
- if (!parent || parent->w <= 0 || parent->h <= 0)
- return 0;
+ if (!parent || parent->w <= 0)
+ return 0;
- switch (parent->type)
- {
- case ABC_HTML_BODY:
- break;
- default:
- return 0;
- break;
- }
+ switch (parent->type)
+ {
+ case ABC_HTML_BODY:
+ case ABC_HTML_DIV:
+ break;
+ default:
+ return 0;
+ break;
+ };
+ attr = abc_obj_get_attr(root, ABC_HTML_ATTR_TEXT_ALIGN);
+ if (attr) {
int x = root->x;
if (!__html_strcmp(attr->value->data, "center"))
int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height)
{
- scf_string_t* key;
- scf_list_t* l;
- abc_obj_t* child;
-
if (!root)
return -EINVAL;
if (width <= 0 || height <= 0)
return -EINVAL;
+ int root_w = width;
+ int root_h = height;
+
switch (root->type)
{
case ABC_HTML_SCRIPT:
break;
case ABC_HTML_BODY:
- root->w = width;
- root->h = height;
+ case ABC_HTML_DIV:
+ root->d = abc_css_margin(root);
+ root->w_set = abc_css_width (root, width, root->d);
+ root->h_set = abc_css_height(root, height, root->d);
+
+ if (root->w_set) {
+ root->w0 = root->w;
+ root_w = root->w;
+ } else {
+// if (ABC_HTML_BODY != root->type)
+// root->w = 0;
+ }
+
+ if (root->h_set) {
+ root->h0 = root->h;
+ root_h = root->h;
+ } else {
+ if (ABC_HTML_BODY != root->type)
+ root->h = 0;
+ }
break;
default:
break;
};
- int x = root->x + 2;
- int y = root->y + 2;
+ scf_list_t* l;
+ abc_obj_t* child;
+
+ int x = root->x + root->d;
+ int y = root->y + root->d;
int h = 0;
int X = 0;
case ABC_HTML_H4:
case ABC_HTML_H5:
case ABC_HTML_H6:
+ case ABC_HTML_DIV:
case ABC_HTML_OL:
case ABC_HTML_UL:
case ABC_HTML_LI:
- child->x = root->x + 2;
+ child->x = root->x + root->d;
child->y = y + h;
- ret = abc_layout_root(NULL, child, width, height);
+ ret = abc_layout_root(NULL, child, root_w, root_h);
if (ret < 0)
return ret;
- x = root->x + 2;
+ x = root->x + root->d;
y = child->y + child->h;
h = 0;
break;
case ABC_HTML_BR:
case ABC_HTML_TR:
- x = root->x + 2;
+ x = root->x + root->d;
y += h;
h = 0;
default:
- if (child->type == root->type && l == scf_list_head(&root->childs)) {
- x = root->x;
- y = root->y;
- }
-
child->x = x;
child->y = y;
- ret = abc_layout_root(NULL, child, width, height);
+ ret = abc_layout_root(NULL, child, root_w, root_h);
if (ret < 0)
return ret;
- if (x + child->w < width) {
+ if (ABC_CORE_TEXT == child->type && child->text_splits) {
+ abc_text_t* t = child->text_splits;
+
+ if (h < t->h)
+ h = t->h;
+
+ t = t->next;
+ while (t && t->next) {
+ h += t->h;
+ t = t->next;
+ }
+
+ x = root->x + root->d;
+ y += h;
+ h = 0;
+
+ if (t) {
+ h = t->h;
+ x += t->w;
+ }
+
+ scf_logd("--- x: %d, y: %d, h: %d ---\n\n", x, y, h);
+
+ } else if (x + child->w < root_w) {
if (h < child->h)
h = child->h;
} else {
y += h;
- child->x = root->x + 2;
+ child->x = root->x + root->d;
child->y = y;
- ret = abc_layout_root(NULL, child, width, height);
+ ret = abc_layout_root(NULL, child, root_w, root_h);
if (ret < 0)
return ret;
x = child->x + child->w;
}
- if (ABC_HTML_P == child->type && ABC_HTML_P != root->type) {
- x = root->x + 2;
+ if (ABC_HTML_P == child->type) {
+ x = root->x + root->d;
y += h;
h = 0;
}
Y = child->y + child->h;
}
- int ret = abc_layout_obj(NULL, root, width, height);
- if (ret < 0)
- return ret;
+ X += root->d;
+ Y += root->d;
if (root->w < X - root->x)
root->w = X - root->x;
if (root->h < Y - root->y)
root->h = Y - root->y;
+ int ret = abc_layout_obj(NULL, root, width, height);
+ if (ret < 0)
+ return ret;
+
abc_layout_css(root);
#if 0
if (root->keys)
int abc_layout_div(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) {
+ if (obj->w_set)
+ obj->w = obj->w0;
+
+ if (obj->h_set)
+ obj->h = obj->h0;
+
+ return 0;
+ }
+
+ int size = 16;
+ int w;
+ int h;
+
+ if (obj->w_set)
+ w = obj->w0 - obj->d * 2;
+ else
+ w = width - obj->d * 2;
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+ if (attr)
+ size = atoi(attr->value->data);
+
+ if (w < size) {
+ scf_loge("\n");
+ return -EINVAL;
+ }
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, height);
+ cr = cairo_create(surface);
+
+ w = w / size * size;
+
+ int ret = __layout_text(cr, obj, 0, w, &extents);
+ if (ret < 0)
+ scf_loge("ret: %d\n", ret);
+
+ w = extents.width + extents.x_bearing + obj->d * 2;
+ h = extents.height + extents.height / 2 + obj->d * 2;
+
+ obj->w = obj->w_set ? obj->w0 : w;
+ obj->h = obj->h_set ? obj->h0 : h + obj->h;
+// obj->w = (obj->w + 3) & ~0x3;
+// obj->h = (obj->h + 3) & ~0x3;
+
+ scf_logd("%s, w: %d, h: %d, d: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg, width: %d, height: %d\n",
+ obj->text->data, obj->w, obj->h, d,
+ extents.x_bearing, extents.y_bearing, extents.width, extents.height,
+ extents.x_advance, extents.y_advance, width, height);
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
return 0;
}
#include"abc.h"
-static int __layout_text_split(cairo_text_extents_t* extents, cairo_t* cr, const uint8_t* text, int len)
-{
- int i;
- for (i = len; i > 0; i--) {
- int c = text[i];
-
- if ('\0' == c || ' ' == c || '\t' == c || '\r' == c || '\n' == c || '-' == c)
- break;
- else if (c < 0x80)
- continue;
-
- if ((c >> 6) != 0x2)
- break;
- }
-
- if (i > 0)
- len = i;
-
- scf_string_t* s = scf_string_cstr_len(text, len);
- if (!s)
- return -ENOMEM;
- cairo_text_extents(cr, s->data, extents);
-
- scf_string_free(s);
- return len;
-}
-
-int __layout_text(cairo_text_extents_t* extents, cairo_t* cr, abc_obj_t* obj, int width)
-{
- abc_obj_t* attr;
- abc_obj_t* style;
-
- attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
- if (attr) {
- int bold = CAIRO_FONT_WEIGHT_NORMAL;
- int italic = CAIRO_FONT_SLANT_NORMAL;
-
- style = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_STYLE);
- if (style) {
- if (!__html_strcmp(style->value->data, "bold"))
- bold = CAIRO_FONT_WEIGHT_BOLD;
-
- else if (!__html_strcmp(style->value->data, "italic") || !__html_strcmp(style->value->data, "oblique"))
- italic = CAIRO_FONT_SLANT_OBLIQUE;
- }
-
- cairo_select_font_face(cr, attr->value->data, italic, bold);
- }
-
- int size = 16;
- attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
- if (attr)
- size = atoi(attr->value->data);
-
- cairo_set_font_size(cr, size);
- cairo_text_extents (cr, obj->text->data, extents);
-
- int w = extents->x_bearing + extents->width;
- if (w <= width)
- return 0;
-
- extents->width = width;
- extents->height = 0;
-
- if (obj->text_splits)
- scf_slist_clear(obj->text_splits, abc_text_t, next, free);
-
- assert(NULL == obj->text_splits);
- abc_text_t** h = &obj->text_splits;
-
- int n_lines = w / width;
- int n_chars = obj->text->len * 5 / 4 / n_lines;
- int n;
- int i;
-
- for (i = 0; i < obj->text->len; ) {
- n = n_chars;
-
- if (n > obj->text->len - i)
- n = obj->text->len - i;
-
- while (1) {
- cairo_text_extents_t tmp;
-
- n = __layout_text_split(&tmp, cr, obj->text->data + i, n);
- if (n < 0)
- return n;
-
- if (tmp.x_bearing + tmp.width <= width)
- {
- abc_text_t* t = calloc(1, sizeof(abc_text_t));
- if (!t)
- return -ENOMEM;
- t->start = i;
- t->len = n;
-
- *h = t;
- h = &t->next;
- i += n;
-
- extents->height += tmp.height;
- break;
- }
-
- n--;
- }
- }
-
- return 0;
-}
-
int abc_layout_h1(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
{
abc_obj_t* attr;
abc_obj_t* style;
cairo_text_extents_t extents;
- cairo_text_extents_t extents2;
cairo_surface_t* surface;
cairo_t* cr;
- if (!obj->text)
+ if (!obj->text) {
+ scf_list_t* l;
+ abc_obj_t* child;
+
+ 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);
+
+ child->y_bearing = obj->y_bearing;
+ }
return 0;
+ }
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create(surface);
if (0 == obj->parent->padding) {
scf_string_t* s = abc_ol_list_style(obj->parent, obj->parent->n_childs);
if (s) {
- cairo_text_extents(cr, s->data, &extents2);
+ cairo_text_extents(cr, s->data, &extents);
- obj->parent->padding = extents2.width + extents2.x_bearing + size / 2;
+ obj->parent->padding = extents.width + extents.x_bearing + size / 2;
scf_string_free(s);
s = NULL;
int w = (width - d * 2 - dw) / size * size;
- int ret = __layout_text(&extents, cr, obj, w);
+ int ret = __layout_text(cr, obj, 0, w, &extents);
if (ret < 0)
scf_loge("ret: %d\n", ret);
- if (ABC_HTML_OL == obj->parent->type)
- obj->y_bearing = extents.y_bearing;
+ obj->y_bearing = extents.y_bearing;
- w = extents.width + extents.x_bearing + d * 2 + dw;
+ w = extents.x_advance + extents.x_bearing + d * 2 + dw;
obj->w = w;
obj->h = extents.height + extents.height / 2 + d * 2;
--- /dev/null
+#include"abc.h"
+
+static int __layout_text_split(cairo_text_extents_t* extents, cairo_t* cr, const uint8_t* text, int len)
+{
+ int i;
+ for (i = len; i > 0; i--) {
+ int c = text[i];
+
+ if ('\0' == c || ' ' == c || '\t' == c || '\r' == c || '\n' == c || '-' == c)
+ break;
+ else if (c < 0x80)
+ continue;
+
+ if ((c >> 6) != 0x2)
+ break;
+ }
+
+ if (i > 0)
+ len = i;
+
+ scf_string_t* s = scf_string_cstr_len(text, len);
+ if (!s)
+ return -ENOMEM;
+ cairo_text_extents(cr, s->data, extents);
+
+ scf_string_free(s);
+ return len;
+}
+
+int __layout_text(cairo_t* cr, abc_obj_t* obj, int x, int width, cairo_text_extents_t* extents)
+{
+ abc_obj_t* attr;
+ abc_obj_t* style;
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+ if (attr) {
+ int bold = CAIRO_FONT_WEIGHT_NORMAL;
+ int italic = CAIRO_FONT_SLANT_NORMAL;
+
+ style = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_STYLE);
+ if (style) {
+ if (!__html_strcmp(style->value->data, "bold"))
+ bold = CAIRO_FONT_WEIGHT_BOLD;
+
+ else if (!__html_strcmp(style->value->data, "italic") || !__html_strcmp(style->value->data, "oblique"))
+ italic = CAIRO_FONT_SLANT_OBLIQUE;
+ }
+
+ cairo_select_font_face(cr, attr->value->data, italic, bold);
+ }
+
+ int size = 16;
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+ if (attr)
+ size = atoi(attr->value->data);
+
+ cairo_set_font_size(cr, size);
+ cairo_text_extents (cr, obj->text->data, extents);
+
+ int w = extents->x_bearing + extents->x_advance;
+ if (x + w <= width)
+ return 0;
+
+ extents->width = width;
+ extents->height = 0;
+
+ if (obj->text_splits)
+ scf_slist_clear(obj->text_splits, abc_text_t, next, free);
+
+ assert(NULL == obj->text_splits);
+ abc_text_t** h = &obj->text_splits;
+
+ scf_logd("x: %d, w: %d, width: %d\n", x, w, width);
+
+ int n_lines = w / width;
+ int n_chars = obj->text->len * 5 / 4 / n_lines;
+ int n;
+ int i;
+
+ for (i = 0; i < obj->text->len; ) {
+ n = n_chars;
+
+ if (n > obj->text->len - i)
+ n = obj->text->len - i;
+
+ while (1) {
+ cairo_text_extents_t tmp;
+
+ n = __layout_text_split(&tmp, cr, obj->text->data + i, n);
+ if (n < 0)
+ return n;
+
+ w = (tmp.x_bearing + tmp.x_advance + size - 1) / size * size;
+ if (x + w <= width) {
+ x = 0;
+
+ abc_text_t* t = calloc(1, sizeof(abc_text_t));
+ if (!t)
+ return -ENOMEM;
+ t->start = i;
+ t->len = n;
+ t->w = w;
+ t->h = tmp.height;
+
+ scf_logd("t->start: %d, t->len: %d, t->w: %d, t->h: %d\n", t->start, t->len, t->w, t->h);
+
+ *h = t;
+ h = &t->next;
+ i += n;
+
+ if (extents->y_bearing > tmp.y_bearing)
+ extents->y_bearing = tmp.y_bearing;
+
+ extents->height += tmp.height;
+ break;
+ }
+
+ n--;
+ }
+ }
+
+ return 0;
+}
+
+int abc_layout_text(abc_layout_t* layout, abc_obj_t* obj, int width, int height)
+{
+ abc_obj_t* parent = obj->parent;
+ abc_obj_t* attr;
+ abc_obj_t* style;
+ cairo_text_extents_t extents;
+ cairo_text_extents_t extents2;
+ cairo_surface_t* surface;
+ cairo_t* cr;
+
+ if (!obj->text)
+ return 0;
+
+ int x = obj->x - parent->x;
+ int w = parent->w_set ? parent->w0 : width;
+ int d = parent->d;
+ int h;
+
+ scf_logd("obj->x: %d, parent->x: %d, w: %d, d: %d\n", obj->x, parent->x, w, d);
+ x -= d;
+ w -= d * 2;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, height);
+ cr = cairo_create(surface);
+
+ int size = 16;
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+ if (attr)
+ size = atoi(attr->value->data);
+
+ w = w / size * size;
+
+ scf_logd("text: %s, w: %d\n", obj->text->data, w);
+
+ int ret = __layout_text(cr, obj, x, w, &extents);
+ if (ret < 0)
+ scf_loge("ret: %d\n", ret);
+
+ obj->y_bearing = extents.y_bearing;
+
+ if (parent->y_bearing > obj->y_bearing)
+ parent->y_bearing = obj->y_bearing;
+
+ obj->w = extents.x_bearing + extents.x_advance;
+ 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, d: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg, width: %d, height: %d\n",
+ obj->text->data, obj->w, obj->h, d,
+ extents.x_bearing, extents.y_bearing, extents.width, extents.height,
+ extents.x_advance, extents.y_advance, width, height);
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+ return 0;
+}
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_text;
-extern abc_render_t abc_render_meta;
-extern abc_render_t abc_render_div;
+extern abc_render_t __render_text;
extern abc_render_t abc_render_h1;
extern abc_render_t abc_render_a_href;
{
[ABC_HTML] = &abc_render_empty,
[ABC_HTML_HEAD] = &abc_render_empty,
- [ABC_HTML_BODY] = &abc_render_body,
[ABC_HTML_META] = &abc_render_empty,
[ABC_HTML_TITLE] = &abc_render_title,
- [ABC_HTML_DIV] = &abc_render_div,
+ [ABC_HTML_BODY] = &abc_render_body,
+ [ABC_HTML_DIV] = &abc_render_body,
+
+ [ABC_CORE_TEXT] = &abc_render_text,
+ [ABC_HTML_B] = &abc_render_text,
+ [ABC_HTML_I] = &abc_render_text,
[ABC_HTML_H1] = &abc_render_h1,
[ABC_HTML_H2] = &abc_render_h1,
[ABC_HTML_SCRIPT] = &abc_render_empty,
[ABC_HTML_STYLE] = &abc_render_empty,
[ABC_HTML_LINK] = &abc_render_empty,
-
- [ABC_HTML_B] = &abc_render_h1,
- [ABC_HTML_I] = &abc_render_h1,
};
int abc_renders_fini()
--- /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 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, v.a); \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_text(abc_render_t* render)
+{
+ return 0;
+}
+
+static int _draw_text_line(abc_obj_t* obj, const char* text,
+ int x, int y, int w, int h, int width, int height,
+ float mvp[16],
+ double bcolor[3], double fcolor[3], int font_size, int bold, int italic, int line_type, int line_width)
+{
+ uint8_t* bgra = calloc(1, w * h * 4);
+ if (!bgra)
+ return -ENOMEM;
+
+ cairo_text_extents_t extents;
+ cairo_surface_t* surface;
+ cairo_t* cr;
+
+ surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, w, h, w * 4);
+ cr = cairo_create(surface);
+
+ cairo_set_line_width(cr, 1);
+ cairo_set_source_rgba(cr, bcolor[0], bcolor[1], bcolor[2], 0.0);
+ cairo_rectangle(cr, 0, 0, w, h);
+ cairo_fill(cr);
+ cairo_stroke(cr);
+
+ abc_obj_t* attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
+ if (attr)
+ cairo_select_font_face(cr, attr->value->data, italic, bold);
+
+ cairo_set_font_size (cr, font_size);
+ cairo_set_source_rgba(cr, fcolor[0], fcolor[1], fcolor[2], 1.0);
+
+ __draw_text(&extents, cr, text, 0, 0, obj->y_bearing, line_type, line_width);
+
+ // cairo_surface_write_to_png(surface, "tmp.png");
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+ surface = NULL;
+ cr = NULL;
+
+ 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 * x / (float)width - 1.0,
+ -2.0 * (y + h) / (float)height + 1.0,
+
+ 2.0 * (x + w) / (float)width - 1.0,
+ -2.0 * (y + h) / (float)height + 1.0,
+
+ 2.0 * x / (float)width - 1.0,
+ -2.0 * y / (float)height + 1.0,
+
+ 2.0 * (x + w) / (float)width - 1.0,
+ -2.0 * 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, w, 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);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ glDisable(GL_BLEND);
+
+ glBindVertexArray(0);
+ glUseProgram(0);
+
+ free(bgra);
+ return 0;
+}
+
+static int _render_draw_text(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+ if (obj->w <= 0 || obj->h <= 0)
+ 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_text_t* t;
+ abc_obj_t* attr;
+
+ double bcolor[3] = {0.0};
+ double fcolor[3] = {0.0};
+
+ double size = 16.0;
+ int bold = CAIRO_FONT_WEIGHT_NORMAL;
+ int italic = CAIRO_FONT_SLANT_NORMAL;
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BG_COLOR);
+ if (attr)
+ abc_css_color(bcolor, bcolor + 1, bcolor + 2, attr->value->data);
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_COLOR);
+ if (attr)
+ abc_css_color(fcolor, fcolor + 1, fcolor + 2, attr->value->data);
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+ if (attr)
+ size = atoi(attr->value->data);
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_STYLE);
+ if (attr) {
+ if (!__html_strcmp(attr->value->data, "bold"))
+ bold = CAIRO_FONT_WEIGHT_BOLD;
+
+ else if (!__html_strcmp(attr->value->data, "italic") || !__html_strcmp(attr->value->data, "oblique"))
+ italic = CAIRO_FONT_SLANT_OBLIQUE;
+ }
+
+ double line_width = 0.5 + size / 16.0;
+ int line_type = ABC_LINE_NONE;
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_TEXT_DECORATION);
+ if (attr) {
+ if (!__html_strcmp(attr->value->data, "underline"))
+ line_type = ABC_LINE_UNDER;
+
+ else if (!__html_strcmp(attr->value->data, "overline"))
+ line_type = ABC_LINE_OVER;
+
+ else if (!__html_strcmp(attr->value->data, "line-through"))
+ line_type = ABC_LINE_THROUGH;
+ }
+
+ float mvp[16];
+ __compute_mvp(mvp, 0, 0, 0);
+
+ int x = obj->x;
+ int y = obj->y;
+ int w = obj->w;
+ int h = obj->h;
+
+ if (!obj->text_splits)
+ return _draw_text_line(obj, obj->text->data,
+ x, y, w, h, width, height, mvp,
+ bcolor, fcolor, size, bold, italic, line_type, line_width);
+
+ while (obj->text_splits) {
+ t = obj->text_splits;
+
+ w = t->w;
+ h = t->h;
+
+ scf_logd("obj->type: %d, obj->w: %d, obj->h: %d, w: %d, h: %d, d: %d\n", obj->type, obj->w, obj->h, w, h, d);
+
+ scf_string_t* s = scf_string_cstr_len(obj->text->data + t->start, t->len);
+ if (!s) {
+ scf_slist_clear(obj->text_splits, abc_text_t, next, free);
+ return -ENOMEM;
+ }
+
+ _draw_text_line(obj, s->data,
+ x, y, w, h, width, height, mvp,
+ bcolor, fcolor, size, bold, italic, line_type, line_width);
+
+ scf_string_free(s);
+ s = NULL;
+
+ x = obj->parent->x + obj->parent->d;
+ y += h;
+
+ obj->text_splits = t->next;
+ free(t);
+ }
+ return 0;
+}
+
+abc_render_t abc_render_text =
+{
+ .type = ABC_CORE_TEXT,
+
+ .draw = _render_draw_text,
+ .fini = _render_fini_text,
+};