--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>菜鸟教程(runoob.com)</title>
+<style>
+body {
+ counter-reset: section;
+}
+
+h2::before {
+ counter-increment: section;
+ content: "Section " counter(section) ": ";
+}
+</style>
+</head>
+<body>
+
+<h1>使用 CSS 计数器:</h1>
+<h2>HTML 教程</h2>
+<h2>CSS 教程</h2>
+<h2>JavaScript 教程</h2>
+
+<p><b>注意:</b> IE8 需要指定 !DOCTYPE 才可以支持该属性。</p>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>菜鸟教程(runoob.com)</title>
+<style>
+ol {
+ counter-reset: section;
+ list-style-type: none;
+}
+
+li::before {
+ counter-increment: section;
+ content: counters(section,".") " ";
+}
+</style>
+</head>
+<body>
+
+<ol>
+ <li>item</li>
+ <li>item
+ <ol>
+ <li>item</li>
+ <li>item</li>
+ <li>item
+ <ol>
+ <li>item</li>
+ <li>item</li>
+ <li>item</li>
+ </ol>
+ </li>
+ <li>item</li>
+ </ol>
+ </li>
+ <li>item</li>
+ <li>item</li>
+</ol>
+
+<ol>
+ <li>item</li>
+ <li>item</li>
+</ol>
+
+<p><b>注意:</b> IE8 需要指定 !DOCTYPE 才可以支持该属性。</p>
+
+</body>
+</html>
CFILES += abc_css_border.c
CFILES += abc_css_length.c
CFILES += abc_css_display.c
+CFILES += abc_css_counter.c
CFILES += abc_io_util.c
CFILES += abc_io_file.c
{
abc_char_t* c = NULL;
int c0 = ' ';
+ int flag = 0;
while (1) {
c = __io_pop_char(&style->io);
if (end(c->c))
break;
-
int ret = 0;
+
+ if ('\"' == c->c || flag) {
+ if ('\"' == c->c)
+ flag = !flag;
+
+ ret = scf_string_cat_cstr_len(s, c->utf8, c->len);
+ c0 = c->c;
+ goto next;
+ }
+
switch (c->c) { // drop more ' ' & add c to string
case '\n':
style->text_line++;
break;
};
+next:
free(c);
c = NULL;
if (ret < 0)
case ';':
case '}':
case EOF:
- if (attr->value)
- scf_string_free(attr->value);
+ if (attr) {
+ if (attr->value)
+ scf_string_free(attr->value);
- attr->value = value;
- break;
+ attr->value = value;
+ break;
+ }
default:
scf_string_free(value);
break;
break;
};
- scf_list_t* l;
- abc_attr_t* attr;
-
+ abc_attr_t* attr = NULL;
+ abc_str_t* s;
int i;
int j;
- int k;
+
for (i = 0; attrs && i < n_attrs; i++) {
- abc_str_t* s;
for (j = 0; j < attrs[i].n_names; j++) {
s = &(attrs[i].names[j]);
- if (s->len == key->len && !__html_strcmp(s->data, key->data))
- goto found;
- }
- }
+ if (s->len != key->len || __html_strcmp(s->data, key->data))
+ continue;
- scf_loge("invalid HTML attribute '%s' in file: %s, line: %d\n", key->data, style->file->data, style->text_pos);
- scf_string_free(key);
- return -EINVAL;
+ int k = attrs[i].type;
+ assert(k >= ABC_CSS_CLASS && k < ABC_HTML_CSS_NB);
-found:
- k = attrs[i].type;
- assert(k >= ABC_CSS_CLASS && k < ABC_HTML_CSS_NB);
+ attr = css->attrs[k - ABC_CSS_CLASS];
+ if (!attr) {
+ int ret = __html_add_attr((abc_obj_t*)css, attrs[i].type, attrs[i].names, attrs[i].n_names, attrs[i].value, attrs[i].flags);
+ if (ret < 0)
+ return ret;
- attr = css->attrs[k - ABC_CSS_CLASS];
- if (!attr) {
- int ret = __html_add_attr((abc_obj_t*)css, attrs[i].type, attrs[i].names, attrs[i].n_names, attrs[i].value, attrs[i].flags);
- if (ret < 0)
- return ret;
+ attr = css->attrs[k - ABC_CSS_CLASS];
+ }
- attr = css->attrs[k - ABC_CSS_CLASS];
+ goto found;
+ }
}
+ scf_logw("unknown HTML attribute '%s' in file: %s, line: %d\n", key->data, style->file->data, style->text_pos);
+
+found:
scf_string_free(key);
key = NULL;
else if (!__html_strcmp(attr->value->data, "capitalize"))
__css_text_transform(obj, 2);
break;
+
+ case ABC_CSS_COUNTER_RESET:
+ abc_css_counter_reset(obj, attr);
+ break;
+
+ case ABC_CSS_COUNTER_INC:
+ abc_css_counter_inc(obj, attr);
+ break;
+
+ case ABC_CSS_CONTENT:
+ abc_css_content(obj, attr);
+ break;
default:
abc_obj_set_attr(obj, attr->type, attr->value->data, attr->value->len);
break;
case ABC_CSS_VISITED:
case ABC_CSS_HOVER:
case ABC_CSS_ACTIVE:
-
if (!(pse->flags & ABC_CSS_FLAG_ON))
return NULL;
break;
+
+ case ABC_CSS_BEFORE:
+ case ABC_CSS_AFTER:
+ scf_logd("%s\n", pse->keys[0].data);
+ break;
default:
break;
};
--- /dev/null
+#include"abc_html.h"
+
+int abc_css_counter_reset(abc_obj_t* obj, abc_attr_t* attr)
+{
+ if (!obj || !attr || !attr->value || 0 == attr->value->len)
+ return -EINVAL;
+
+ css_count_t* cnt = obj->counter_list;
+ while (cnt) {
+ if (!scf_string_cmp(cnt->name, attr->value))
+ break;
+ cnt = cnt->next;
+ }
+
+ if (!cnt) {
+ cnt = calloc(1, sizeof(css_count_t));
+ if (!cnt)
+ return -ENOMEM;
+
+ cnt->name = scf_string_clone(attr->value);
+ if (!cnt->name) {
+ free(cnt);
+ return -ENOMEM;
+ }
+
+ cnt->next = obj->counter_list;
+ obj->counter_list = cnt;
+ }
+
+ cnt->value = 0;
+
+ scf_logd("cnt->name: %s, value: %ld\n", cnt->name->data, cnt->value);
+ return 0;
+}
+
+int abc_css_counter_inc(abc_obj_t* obj, abc_attr_t* attr)
+{
+ if (!obj || !attr || !attr->value || 0 == attr->value->len)
+ return -EINVAL;
+
+ css_count_t* cnt;
+ abc_obj_t* parent;
+
+ for (parent = obj->parent; parent; parent = parent->parent) {
+
+ for (cnt = parent->counter_list; cnt; cnt = cnt->next)
+ {
+ if (!scf_string_cmp(cnt->name, attr->value)) {
+ cnt->value++;
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int __css_recursive_counter(scf_string_t* content, abc_obj_t* parent, const char* name, int len, const char* split, int split_len, int all_flag)
+{
+ if (all_flag && parent->parent) {
+
+ int ret = __css_recursive_counter(content, parent->parent, name, len, split, split_len, all_flag);
+ if (ret < 0)
+ return ret;
+ }
+
+ css_count_t* cnt;
+
+ for (cnt = parent->counter_list; cnt; cnt = cnt->next) {
+
+ if (cnt->name->len == len && !memcmp(cnt->name->data, name, len)) {
+ uint8_t buf[128];
+
+ int n = snprintf(buf, sizeof(buf) - 1, "%ld", cnt->value);
+
+ int ret = scf_string_cat_cstr_len(content, buf, n);
+ if (ret < 0)
+ return ret;
+
+ if (split && split_len > 0) {
+
+ ret = scf_string_cat_cstr_len(content, split, split_len);
+ if (ret < 0)
+ return ret;
+ }
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int __css_counter(abc_obj_t* obj, abc_attr_t* attr, int lp, int comma, int rp, int all_flag)
+{
+ char* name = attr->value->data + lp + 1;
+ int len = comma - lp - 1;
+
+ char* split = NULL;
+ char* split2 = NULL;
+ int i;
+ int c;
+
+ for (i = comma + 1; i < rp; i++) {
+ c = attr->value->data[i];
+
+ if ('\"' != c)
+ continue;
+
+ if (!split)
+ split = attr->value->data + i + 1;
+ else if (!split2) {
+ split2 = attr->value->data + i;
+ break;
+ }
+ }
+
+ int split_len = (int)(split2 - split);
+
+ return __css_recursive_counter(obj->content, obj->parent, name, len, split, split_len, all_flag);
+}
+
+int abc_css_content(abc_obj_t* obj, abc_attr_t* attr)
+{
+ if (!obj || !attr || !attr->value || 0 == attr->value->len)
+ return -EINVAL;
+
+ if (obj->content)
+ scf_string_free(obj->content);
+
+ obj->content = scf_string_alloc();
+ if (!obj->content)
+ return -ENOMEM;
+
+ abc_str_t counter = ABC_STR("counter");
+ abc_str_t counters = ABC_STR("counters");
+
+/*
+content: "prev" counters(name, ".") "next";
+ | | | | | |
+ quote func lp comma i quote
+*/
+ int quote = -1;
+ int func = -1;
+ int lp = -1;
+ int rp = -1;
+ int comma = -1;
+ int i;
+ int c;
+
+ for (i = 0; i < attr->value->len; i++) {
+ c = attr->value->data[i];
+
+ if ('\"' == c) {
+ if (quote < 0) {
+ quote = i + 1;
+ continue;
+ }
+
+ if (i > quote && lp < 0) {
+ int ret = scf_string_cat_cstr_len(obj->content, attr->value->data + quote, i - quote);
+ if (ret < 0)
+ return ret;
+ }
+
+ quote = -1;
+ }
+
+ if (quote >= 0)
+ continue;
+
+ switch (c) {
+ case 'c':
+ case 'C':
+ if (i <= 0 || ' ' == attr->value->data[i - 1]
+ || '\"' == attr->value->data[i - 1])
+ func = i;
+ break;
+
+ case '(':
+ lp = i;
+ break;
+
+ case ',':
+ if (comma < 0 && lp >= 0)
+ comma = i;
+ break;
+
+ case ')':
+ rp = i;
+ if (comma < 0)
+ comma = rp;
+
+ if (func < lp && lp < comma && comma <= rp)
+ {
+ if (lp - func == counter.len && !__html_strncmp(attr->value->data + func, counter.data, counter.len))
+ __css_counter(obj, attr, lp, comma, rp, 0);
+
+ else if (lp - func == counters.len && !__html_strncmp(attr->value->data + func, counters.data, counters.len))
+ __css_counter(obj, attr, lp, comma, rp, 1);
+ }
+
+ func = -1;
+ lp = -1;
+ rp = -1;
+ comma = -1;
+ quote = -1;
+ break;
+ default:
+ break;
+ };
+ }
+
+ return 0;
+}
static abc_str_t display_keys[] = {ABC_STR("display"), ABC_STR("显示模式")};
static abc_str_t visible_keys[] = {ABC_STR("visibility"), ABC_STR("可见性")};
static abc_str_t opacity_keys[] = {ABC_STR("opacity"), ABC_STR("透明度")};
-static abc_str_t filter_keys[] = {ABC_STR("filter"), ABC_STR("滤镜")};
static abc_str_t margin_keys[] = {ABC_STR("margin"), ABC_STR("外边距")};
static abc_str_t margin_top_keys[] = {ABC_STR("margin-top"), ABC_STR("上边缘")};
static abc_str_t xmlns_keys[] = {ABC_STR("xmlns")};
static abc_str_t xmlang_keys[] = {ABC_STR("xml:lang")};
static abc_str_t lang_keys[] = {ABC_STR("lang"), ABC_STR("语言")};
-static abc_str_t content_keys[] = {ABC_STR("content"), ABC_STR("正文类型")};
static abc_str_t charset_keys[] = {ABC_STR("charset"), ABC_STR("字符集")};
static abc_str_t enctype_keys[] = {ABC_STR("enctype")};
-static abc_str_t http_equiv_keys[] = {ABC_STR("http-equiv")};
+static abc_str_t counter_reset_keys[] = {ABC_STR("counter-reset"), ABC_STR("计数器重置")};
+static abc_str_t counter_inc_keys[] = {ABC_STR("counter-increment"), ABC_STR("计数值增加")};
+static abc_str_t content_keys[] = {ABC_STR("content"), ABC_STR("内容")};
+
+static abc_str_t http_equiv_keys[] = {ABC_STR("http-equiv")};
// HTML labels
static abc_str_t html_keys[] = {ABC_STR("html"), ABC_STR("网页")};
static abc_str_t css_hover_keys[] = {ABC_STR(":hover"), ABC_STR("正在指向")};
static abc_str_t css_active_keys[] = {ABC_STR(":active"), ABC_STR("正在点击")};
+static abc_str_t css_before_keys[] = {ABC_STR("::before"), ABC_STR(":before")};
+static abc_str_t css_after_keys[] = {ABC_STR("::after"), ABC_STR(":after")};
+
static abc_str_t css_first_child_keys[] = {ABC_STR(":first-child"), ABC_STR("第1个子元素"), ABC_STR("第一个子元素")};
\
{width_keys, abc_number_of(width_keys), "", ABC_HTML_ATTR_WIDTH, ABC_HTML_FLAG_SHOW}, \
{height_keys, abc_number_of(height_keys), "", ABC_HTML_ATTR_HEIGHT, ABC_HTML_FLAG_SHOW}, \
- {opacity_keys, abc_number_of(opacity_keys), "1.0", ABC_CSS_OPACITY, ABC_HTML_FLAG_SHOW}, \
- {filter_keys, abc_number_of(filter_keys), "", ABC_CSS_FILTER, 0},
+ {opacity_keys, abc_number_of(opacity_keys), "1.0", ABC_CSS_OPACITY, ABC_HTML_FLAG_SHOW},
#define ABC_CSS_SCROLL(overflow, scroll_width, scroll_color) \
{overflow_keys, abc_number_of(overflow_keys), #overflow, ABC_CSS_OVERFLOW, ABC_HTML_FLAG_SHOW}, \
{css_visited_keys, abc_number_of(css_visited_keys), "", ABC_CSS_VISITED, ABC_HTML_FLAG_SHOW}, \
{css_hover_keys, abc_number_of(css_hover_keys), "", ABC_CSS_HOVER, ABC_HTML_FLAG_SHOW}, \
{css_active_keys, abc_number_of(css_active_keys), "", ABC_CSS_ACTIVE, ABC_HTML_FLAG_SHOW}, \
+ {css_before_keys, abc_number_of(css_before_keys), "", ABC_CSS_BEFORE, 0}, \
+ {css_after_keys, abc_number_of(css_after_keys), "", ABC_CSS_AFTER, 0}, \
{css_first_child_keys, abc_number_of(css_first_child_keys), "", ABC_CSS_FIRST_CHILD, 0},
+#define ABC_CSS_COUNTER() \
+ {counter_reset_keys, abc_number_of(counter_reset_keys), "", ABC_CSS_COUNTER_RESET, ABC_HTML_FLAG_SHOW}, \
+ {counter_inc_keys, abc_number_of(counter_inc_keys), "", ABC_CSS_COUNTER_INC, ABC_HTML_FLAG_SHOW}, \
+ {content_keys, abc_number_of(content_keys), "", ABC_CSS_CONTENT, ABC_HTML_FLAG_SHOW},
+
ABC_CSS_BOX(block, , , 12px)
ABC_CSS_SCROLL(scroll, 12px, orangeRed white)
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND(white)
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SCROLL( , 8px, orangeRed white)
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND(white)
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimHei, 40, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimHei, 32, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimHei, 28, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimHei, 24, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimHei, 20, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimHei, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, blue, )
ABC_CSS_TEXT(left, underline)
ABC_CSS_SCROLL( , , )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
+ ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_LIST()
};
+static html_attr_t li_attrs[] =
+{
+ ABC_CSS_BOX(block, , , )
+ ABC_CSS_SELECTOR()
+ ABC_CSS_BACK_GROUND()
+ ABC_CSS_PSE()
+ ABC_CSS_COUNTER()
+
+ ABC_CSS_FONT(SimSong, 16, black, )
+ ABC_CSS_TEXT(left, )
+};
+
static html_attr_t table_attrs[] =
{
ABC_CSS_BOX(block, 2px, 2px, 4px)
ABC_CSS_SCROLL( , , )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT(left, )
ABC_CSS_SCROLL( , , )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimHei, 24, black, )
ABC_CSS_TEXT( , )
ABC_CSS_SCROLL( , , )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT( , )
ABC_CSS_SCROLL( , , )
ABC_CSS_SELECTOR()
ABC_CSS_BACK_GROUND()
+ ABC_CSS_COUNTER()
ABC_CSS_FONT(SimSong, 16, black, )
ABC_CSS_TEXT( , )
{ol_keys, abc_number_of(ol_keys), ABC_HTML_OL, abc_number_of(ol_attrs), ol_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{ul_keys, abc_number_of(ul_keys), ABC_HTML_UL, abc_number_of(ol_attrs), ol_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
- {li_keys, abc_number_of(li_keys), ABC_HTML_LI, 0, NULL, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
+ {li_keys, abc_number_of(li_keys), ABC_HTML_LI, abc_number_of(li_attrs), li_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{video_keys, abc_number_of(video_keys), ABC_HTML_VIDEO, abc_number_of(video_attrs), video_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
{audio_keys, abc_number_of(audio_keys), ABC_HTML_AUDIO, abc_number_of(audio_attrs), audio_attrs, ABC_HTML_FLAG_CLOSE | ABC_HTML_FLAG_SHOW},
if (!c) {
scf_loge("\n");
scf_string_free(value);
- return -1;
+ return -EINVAL;
}
html->pos += c->len;
free(c);
c = NULL;
- if (attr->value)
- scf_string_free(attr->value);
+ if (attr) {
+ if (attr->value)
+ scf_string_free(attr->value);
+
+ attr->value = value;
+ }
- attr->value = value;
return tmp;
}
c->c, html->file->data, html->n_lines);
free(c);
scf_string_free(key);
- return -1;
+ return -EINVAL;
}
free(c);
}
}
- if (i >= sizeof(obj->attrs) / sizeof(obj->attrs[0])) {
- scf_loge("invalid HTML attribute '%s' in file: %s, line: %d\n", key->data, html->file->data, html->n_lines);
- scf_string_free(key);
- return -1;
- }
+ scf_loge("invalid HTML attribute '%s' in file: %s, line: %d\n", key->data, html->file->data, html->n_lines);
+ scf_string_free(key);
+ return -EINVAL;
+ attr = NULL;
found:
scf_string_free(key);
key = NULL;
void abc_overflow_show(int* x, int* y, int* w, int* h, int mask_x, int mask_y, int mask_w, int mask_h);
+int abc_css_counter_reset(abc_obj_t* obj, abc_attr_t* attr);
+int abc_css_counter_inc (abc_obj_t* obj, abc_attr_t* attr);
+int abc_css_content (abc_obj_t* obj, abc_attr_t* attr);
+
#endif
}
}
+abc_text_t* abc_text_alloc(const uint8_t* text, int len, int w, int h)
+{
+ abc_text_t* t = calloc(1, sizeof(abc_text_t));
+ if (!t)
+ return NULL;
+
+ t->data = (uint8_t*)text;
+ t->len = len;
+
+ t->w = w;
+ t->h = h;
+ return t;
+}
+
css_rule_t* css_rule_alloc(scf_string_t* file, int line, int pos, int type)
{
css_rule_t* css = calloc(1, sizeof(css_rule_t));
}
}
- if (obj->flags & ABC_HTML_FLAG_SINGLE)
+ if (obj->flags & ABC_HTML_FLAG_SINGLE) {
printf(" />\n");
- else if (obj->keys)
+
+ } else if (obj->keys) {
printf(">\n");
+ }
+
+ if (obj->content)
+ printf("%s", obj->content->data);
if (obj->text)
printf("%s\n", obj->text->data);
static const char* ROMAN[] = {"M","CM", "D","CD", "C","XC", "L","XL","X","IX","V","IV","I"};
static const char* roman[] = {"m","cm", "d","cd", "c","xc", "l","xl","x","ix","v","iv","i"};
+static abc_str_t upper_roman = ABC_STR("upper-roman");
+static abc_str_t lower_alpha = ABC_STR("lower-alpha");
+
scf_string_t* abc_ol_list_style(abc_obj_t* obj, int num)
{
abc_attr_t* attr = abc_obj_find_attr(obj, ABC_CSS_LIST_STYLE_TYPE);
- if (attr) {
- const char* p = attr->value->data;
- if (!__html_strcmp(p, "upper-roman"))
- return __li_style_roman(num + 1, ROMAN);
+ if (attr && attr->value && attr->value->len > 0) {
+ const size_t len = attr->value->len;
+ const char* p = attr->value->data;
- else if (!__html_strcmp(p, "lower-roman"))
- return __li_style_roman(num + 1, roman);
+ if (4 == len && !__html_strcmp(p, "none"))
+ return NULL;
- else if (!__html_strcmp(p, "upper-alpha"))
- return __li_style_number(num, 26, 'A');
+ if (len == upper_roman.len)
+ {
+ if (!__html_strcmp(p, "upper-roman"))
+ return __li_style_roman(num + 1, ROMAN);
+
+ else if (!__html_strcmp(p, "lower-roman"))
+ return __li_style_roman(num + 1, roman);
- else if (!__html_strcmp(p, "lower-alpha"))
- return __li_style_number(num, 26, 'a');
+ else if (!__html_strcmp(p, "upper-alpha"))
+ return __li_style_number(num, 26, 'A');
+
+ else if (!__html_strcmp(p, "lower-alpha"))
+ return __li_style_number(num, 26, 'a');
+ }
}
return __li_style_number(num, 10, '0');
#include"abc_ffmpeg.h"
#include"abc_io.h"
-typedef struct abc_obj_s abc_obj_t;
-typedef struct abc_attr_s abc_attr_t;
-typedef struct abc_text_s abc_text_t;
+typedef struct abc_obj_s abc_obj_t;
+typedef struct abc_attr_s abc_attr_t;
+typedef struct abc_text_s abc_text_t;
-typedef struct abc_css_s abc_css_t;
-typedef struct css_rule_s css_rule_t;
-typedef struct css_hash_s css_hash_t;
+typedef struct abc_css_s abc_css_t;
+typedef struct css_rule_s css_rule_t;
+typedef struct css_hash_s css_hash_t;
+typedef struct css_count_s css_count_t;
enum abc_objs
{
ABC_CSS_SCROLLBAR_COLOR,
ABC_CSS_OPACITY,
- ABC_CSS_FILTER,
ABC_CSS_LIST_STYLE,
ABC_CSS_LIST_STYLE_TYPE,
ABC_CSS_LIST_STYLE_IMAGE,
ABC_CSS_LIST_STYLE_POSITION,
+ ABC_CSS_COUNTER_RESET,
+ ABC_CSS_COUNTER_INC,
+ ABC_CSS_CONTENT,
+
// css pse class (element)
ABC_CSS_FIRST_CHILD,
+ ABC_CSS_BEFORE,
+ ABC_CSS_AFTER,
+
ABC_CSS_LINK,
ABC_CSS_HOVER,
ABC_CSS_ACTIVE,
{
abc_text_t* next;
- int start;
+ uint8_t* data;
int len;
+ uint32_t ref_flag:1;
+ uint32_t new_line_flag:1;
+
int w;
int h;
};
+struct css_count_s
+{
+ css_count_t* next;
+
+ scf_string_t* name;
+ intptr_t value;
+};
+
#define ABC_HTML_FLAG_OPEN 0
#define ABC_HTML_FLAG_CLOSE 1
#define ABC_HTML_FLAG_SINGLE 2
abc_text_t* text_splits; // for layout, split a long text to multi-lines and save every-line here
abc_io_t io;
+ css_count_t* counter_list;
+ scf_string_t* content;
+
int border_top;
int border_bottom;
int border_left;
void abc_obj_free (abc_obj_t* obj);
void abc_attr_free(abc_attr_t* attr);
+abc_text_t* abc_text_alloc(const uint8_t* text, int len, int w, int h);
+
abc_css_t* abc_css_alloc();
void abc_css_free (abc_css_t* css);
if (s0->len > s1->len)
return 1;
- return strncmp(s0->data, s1->data, s0->len);
+ return memcmp(s0->data, s1->data, s0->len);
}
int scf_string_cmp_cstr(const scf_string_t* s0, const char* str)
CFILES += abc_layout_input.c
CFILES += abc_layout_table.c
CFILES += abc_layout_td.c
+CFILES += abc_layout_li.c
CFILES += abc_layout_video.c
CFILES += abc_layout_audio.c
CFILES += ../html/abc_css_border.c
CFILES += ../html/abc_css_length.c
CFILES += ../html/abc_css_display.c
+CFILES += ../html/abc_css_counter.c
CFILES += ../html/abc_io_util.c
CFILES += ../html/abc_io_file.c
line_type = ABC_LINE_THROUGH;
}
- double x = obj->parent->list_order_width;
+ double x = obj->parent->list_order_width * scale;
double y = 0.0;
if (!obj->text_splits) {
- __draw_text(&extents, cr, obj->text->data, x * scale, 0.0, obj->y_bearing * scale, line_type, line_width * scale);
+ __draw_text(&extents, cr, obj->text->data, x, 0.0, obj->y_bearing * scale, line_type, line_width * scale);
return 0;
}
while (obj->text_splits) {
t = obj->text_splits;
- s = scf_string_cstr_len(obj->text->data + t->start, t->len);
+ s = scf_string_cstr_len(t->data, t->len);
if (!s) {
scf_slist_clear(obj->text_splits, abc_text_t, next, free);
return -ENOMEM;
}
- __draw_text(&extents, cr, s->data, x * scale, y, obj->y_bearing * scale, line_type, line_width * scale);
- y += extents.height;
+ __draw_text(&extents, cr, s->data, x, y, obj->y_bearing * scale, line_type, line_width * scale);
+
+ if (t->new_line_flag) {
+ y += extents.height;
+ x = obj->parent->list_order_width * scale;
+ } else
+ x += extents.x_bearing + extents.x_advance;
obj->text_splits = t->next;
int abc_layout_table(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height);
int abc_layout_td (abc_ctx_t* ctx, abc_obj_t* obj, int width, int height);
+int abc_layout_li (abc_ctx_t* ctx, abc_obj_t* obj, int width, int height);
int abc_layout_video(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height);
int abc_layout_audio(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height);
[ABC_HTML_OL] = abc_layout_empty,
[ABC_HTML_UL] = abc_layout_empty,
- [ABC_HTML_LI] = abc_layout_h1,
+ [ABC_HTML_LI] = abc_layout_li,
[ABC_HTML_VIDEO] = abc_layout_video,
[ABC_HTML_AUDIO] = abc_layout_audio,
int abc_layout_h1(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height)
{
abc_attr_t* attr;
- abc_attr_t* style;
cairo_text_extents_t extents;
cairo_surface_t* surface;
cairo_t* cr;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cr = cairo_create(surface);
- attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
- if (attr) {
- 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);
-
int w_set = abc_css_width (obj, width);
int h_set = abc_css_height(obj, height);
- int dw = 0;
- switch (obj->parent->type) {
- case ABC_HTML_OL:
- if (0 == obj->parent->list_order_width) {
- scf_string_t* s = abc_ol_list_style(obj->parent, obj->parent->n_childs);
- if (s) {
- cairo_text_extents(cr, s->data, &extents);
-
- obj->parent->list_order_width = extents.width + extents.x_bearing + size / 2;
-
- scf_string_free(s);
- s = NULL;
- }
- }
-
- dw = obj->parent->list_order_width;
- break;
-
- case ABC_HTML_UL:
- dw = size;
- obj->parent->list_order_width = size;
- break;
- default:
- break;
- };
-
- int w = (width - obj->left - obj->right - dw) / size * size;
+ int w = (width - obj->left - obj->right) / size * size;
int ret = __layout_text(cr, obj, 0, w, &extents);
if (ret < 0)
obj->y_bearing = extents.y_bearing;
- obj->w = extents.width + obj->left + obj->right + dw;
+ obj->w = extents.width + obj->left + obj->right;
obj->h = extents.height + extents.height / 2 + obj->top + obj->bottom;
scf_logd("%s, w: %d, h: %d, x_bearing: %lg, y_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg, width: %d, height: %d\n",
--- /dev/null
+#include"abc.h"
+
+static int __ol_list_order_width(cairo_text_extents_t* extents, abc_obj_t* obj, cairo_t* cr, int size)
+{
+ scf_string_t* s = abc_ol_list_style(obj->parent, obj->parent->n_childs);
+ if (!s)
+ return 0;
+
+ abc_attr_t* attr;
+ abc_attr_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);
+ }
+
+ cairo_set_font_size(cr, size);
+ cairo_text_extents (cr, s->data, extents);
+
+ scf_string_free(s);
+ s = NULL;
+
+ return extents->width + extents->x_bearing + size / 2;
+}
+
+int abc_layout_li(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height)
+{
+ abc_attr_t* attr;
+ cairo_text_extents_t extents;
+ cairo_surface_t* surface;
+ cairo_t* cr;
+
+ 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);
+
+ int size = 16;
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_SIZE);
+ if (attr)
+ size = atoi(attr->value->data);
+
+ int w_set = abc_css_width (obj, width);
+ int h_set = abc_css_height(obj, height);
+
+ int dw = 0;
+ switch (obj->parent->type) {
+ case ABC_HTML_OL:
+ if (0 == obj->parent->list_order_width)
+ obj->parent->list_order_width = __ol_list_order_width(&extents, obj, cr, size);
+
+ dw = obj->parent->list_order_width;
+ break;
+
+ case ABC_HTML_UL:
+ dw = size;
+ obj->parent->list_order_width = size;
+ break;
+ default:
+ break;
+ };
+
+ int w = (width - obj->left - obj->right - dw) / size * size;
+
+ int ret = __layout_text(cr, obj, 0, w, &extents);
+ if (ret < 0)
+ scf_loge("ret: %d\n", ret);
+
+ obj->y_bearing = extents.y_bearing;
+
+ obj->w = extents.width + obj->left + obj->right + dw;
+ obj->h = extents.height + extents.height / 2 + obj->top + obj->bottom;
+
+ scf_logd("%s, w: %d, h: %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,
+ 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)
+static int __layout_text_split2(cairo_text_extents_t* extents, cairo_t* cr, const uint8_t* text, int len)
{
int i;
for (i = len; i > 0; i--) {
return len;
}
+static int __layout_text_split(abc_text_t** h, cairo_text_extents_t* extents, cairo_t* cr,
+ int x,
+ int max_chars, int size, int width, const uint8_t* text, int len)
+{
+ int x_tail = -1;
+ int n;
+ int i;
+
+ for (i = 0; i < len; ) {
+ n = max_chars;
+
+ if (n > len - i)
+ n = len - i;
+
+ while (1) {
+ cairo_text_extents_t tmp;
+ int w;
+
+ int ret = __layout_text_split2(&tmp, cr, text + i, n);
+ if (ret < 0)
+ return ret;
+
+ w = tmp.x_bearing + tmp.x_advance;
+ w = (w + size - 1) / size * size;
+ x_tail = x + w;
+
+ if (x_tail <= width) {
+ x = 0;
+
+ abc_text_t* t = abc_text_alloc(text + i, ret, w, tmp.height);
+ if (!t)
+ return -ENOMEM;
+
+ scf_logd("t->data: %p, t->len: %d, t->w: %d, t->h: %d\n", t->data, t->len, t->w, t->h);
+
+ *h = t;
+ h = &t->next;
+
+ if (extents->y_bearing > tmp.y_bearing)
+ extents->y_bearing = tmp.y_bearing;
+
+ if (ret < n) {
+ extents->height += tmp.height;
+ t->new_line_flag = 1;
+ }
+
+ i += ret;
+ break;
+ }
+
+ n = --ret;
+ }
+ }
+
+ return x_tail;
+}
+
int __layout_text(cairo_t* cr, abc_obj_t* obj, int x, int width, cairo_text_extents_t* extents)
{
- abc_attr_t* attr;
- abc_attr_t* style;
+ 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;
+ abc_attr_t* attr;
+ abc_attr_t* style;
attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT);
if (attr) {
cairo_set_font_size(cr, size);
cairo_text_extents (cr, obj->text->data, extents);
- int w = extents->x_bearing + extents->x_advance;
+ int w_text = extents->x_bearing + extents->x_advance;
+ int w_content = 0;
+ int h_obj = extents->height;
+
+ int n = obj->text->len;
+ int w = w_text;
+
+ if (obj->content) {
+ cairo_text_extents(cr, obj->content->data, extents);
+
+ w_content = extents->x_bearing + extents->x_advance;
+
+ n += obj->content->len;
+ w += w_content;
+
+ if (h_obj < extents->height)
+ h_obj = extents->height;
+ }
w = (w + size - 1) / size * size;
if (x + w <= width) {
- extents->width = w;
+ extents->width = w;
+ extents->height = h_obj;
+
+ if (obj->content) {
+ abc_text_t* t = abc_text_alloc(obj->content->data, obj->content->len, w_content, h_obj);
+ if (!t)
+ return -ENOMEM;
+ *h = t;
+ h = &t->next;
+
+ t = abc_text_alloc(obj->text->data, obj->text->len, w_text, h_obj);
+ if (!t)
+ return -ENOMEM;
+ *h = t;
+ h = &t->next;
+ }
+
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 = (x + 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;
- w = (w + 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;
+ int max_lines = (x + w) / width;
+ int max_chars = n * 5 / 4 / max_lines;
+ int x_tail = 0;
+
+ if (obj->content) {
+ w = (w_content + size - 1) / size * size;
+
+ if (x + w < width) {
+ abc_text_t* t = abc_text_alloc(obj->content->data, obj->content->len, w_content, h_obj);
+ if (!t)
+ return -ENOMEM;
+ x_tail = x + w;
+
+ *h = t;
+ h = &t->next;
+ } else {
+ x_tail = __layout_text_split(h, extents, cr, x, max_chars, size, width, obj->content->data, obj->content->len);
+ if (x_tail < 0) {
+ scf_slist_clear(obj->text_splits, abc_text_t, next, free);
+ return x_tail;
}
-
- n--;
}
}
+ int ret = __layout_text_split(h, extents, cr, x_tail, max_chars, size, width, obj->text->data, obj->text->len);
+ if (ret < 0) {
+ scf_slist_clear(obj->text_splits, abc_text_t, next, free);
+ return ret;
+ }
+
return 0;
}
if (!obj->text)
return 0;
+ if (parent->content && !parent->text) {
+ if (obj->content) {
+ int ret = scf_string_cat(parent->content, obj->content);
+ if (ret < 0)
+ return ret;
+
+ scf_string_free(obj->content);
+ }
+
+ obj->content = parent->content;
+ parent->content = NULL;
+ }
+
int x = obj->x - (parent->x + parent->left);
int w = width;
if (ABC_HTML_OL == obj->parent->type)
{
scf_string_t* s = abc_ol_list_style(obj, obj->list_order);
- if (!s) {
- free(bgra1);
- free(bgra);
- return -ENOMEM;
- }
-
- SCF_XCHG(obj->text, s);
- __init_text(cr, obj, 1, ctx->gl_scale);
- SCF_XCHG(obj->text, s);
+ if (s) {
+ SCF_XCHG(obj->text, s);
+ __init_text(cr, obj, 1, ctx->gl_scale);
+ SCF_XCHG(obj->text, s);
- scf_string_free(s);
- s = NULL;
+ scf_string_free(s);
+ s = NULL;
+ }
} else {
rgba[0] = 0.0;
rgba[1] = 0.0;
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);
+ scf_string_t* s = scf_string_cstr_len(t->data, t->len);
if (!s) {
scf_slist_clear(obj->text_splits, abc_text_t, next, free);
return -ENOMEM;
scf_string_free(s);
s = NULL;
- x = obj->parent->x + obj->parent->left;
- y += h;
+ if (t->new_line_flag) {
+ x = obj->parent->x + obj->parent->left;
+ y += h;
+ } else
+ x += w;
obj->text_splits = t->next;
free(t);
if (s0->len > s1->len)
return 1;
- return strncmp(s0->data, s1->data, s0->len);
+ return memcmp(s0->data, s1->data, s0->len);
}
int scf_string_cmp_cstr(const scf_string_t* s0, const char* str)