css: support counter() & counters()
authoryu.dongliang <18588496441@163.com>
Sat, 6 Jun 2026 06:43:43 +0000 (14:43 +0800)
committeryu.dongliang <18588496441@163.com>
Sat, 6 Jun 2026 06:43:43 +0000 (14:43 +0800)
19 files changed:
examples/counter.html [new file with mode: 0644]
examples/counters.html [new file with mode: 0644]
html/Makefile
html/abc_css.c
html/abc_css_counter.c [new file with mode: 0644]
html/abc_html.c
html/abc_html.h
html/abc_obj.c
html/abc_obj.h
js/util/scf_string.c
ui/Makefile
ui/__render_text.c
ui/abc_layout.c
ui/abc_layout_h1.c
ui/abc_layout_li.c [new file with mode: 0644]
ui/abc_layout_text.c
ui/abc_render_li.c
ui/abc_render_text.c
util/scf_string.c

diff --git a/examples/counter.html b/examples/counter.html
new file mode 100644 (file)
index 0000000..da86816
--- /dev/null
@@ -0,0 +1,27 @@
+<!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>
diff --git a/examples/counters.html b/examples/counters.html
new file mode 100644 (file)
index 0000000..7a8038c
--- /dev/null
@@ -0,0 +1,48 @@
+<!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>
index d41e793fe5834c5d1b2710c869d4c3a08557e1ae..bbb8c73c506c9c9aa671b253a0e09dbaee77db47 100644 (file)
@@ -7,6 +7,7 @@ CFILES += abc_css_position.c
 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
index 0a6713b9000a8386edfdebaf3369c114920c50dd..ba92c419da787056b3e2b8681496781eb898f099 100644 (file)
@@ -59,6 +59,7 @@ static int __css_parse_str(abc_obj_t* style, scf_string_t* s, int (*end)(int c))
 {
        abc_char_t* c  = NULL;
        int         c0 = ' ';
+       int         flag = 0;
 
        while (1) {
                c = __io_pop_char(&style->io);
@@ -82,8 +83,17 @@ static int __css_parse_str(abc_obj_t* style, scf_string_t* s, int (*end)(int c))
 
                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++;
@@ -123,6 +133,7 @@ static int __css_parse_str(abc_obj_t* style, scf_string_t* s, int (*end)(int c))
                                break;
                };
 
+next:
                free(c);
                c = NULL;
                if (ret < 0)
@@ -150,11 +161,13 @@ static int __css_parse_value(abc_obj_t* style, abc_attr_t* attr)
                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;
@@ -187,40 +200,38 @@ static int __css_parse_attr2(abc_obj_t* style, css_rule_t* css, const html_attr_
                        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;
 
@@ -802,6 +813,18 @@ static void __css_set_attr(abc_obj_t* obj, abc_attr_t* attr)
                        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;
@@ -831,10 +854,14 @@ static abc_obj_t* __css_filter_pse(abc_obj_t* current, abc_attr_t* pse)
                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;
        };
diff --git a/html/abc_css_counter.c b/html/abc_css_counter.c
new file mode 100644 (file)
index 0000000..a91985a
--- /dev/null
@@ -0,0 +1,215 @@
+#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;
+}
index c0af1e8472a720d2811a733b1948cd2798d8fc30..fbe18328e829e98fb2334eb82eaaf1a4548cf4aa 100644 (file)
@@ -11,7 +11,6 @@ static abc_str_t  height_keys[]  = {ABC_STR("height"),     ABC_STR("高度")};
 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("上边缘")};
@@ -80,11 +79,14 @@ static abc_str_t  control_keys[] = {ABC_STR("controls"),  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("网页")};
@@ -148,6 +150,9 @@ static abc_str_t  css_visited_keys[]     = {ABC_STR(":visited"), 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("第一个子元素")};
 
 
@@ -182,8 +187,7 @@ static html_attr_t  html_attrs[] =
        \
        {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}, \
@@ -225,12 +229,20 @@ static html_attr_t  html_attrs[] =
        {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, )
@@ -253,6 +265,7 @@ static html_attr_t  body_attrs[] =
        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, )
@@ -265,6 +278,7 @@ static html_attr_t  div_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimSong, 16, black, )
        ABC_CSS_TEXT(left, )
@@ -277,6 +291,7 @@ static html_attr_t  h1_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimHei, 40, black, )
        ABC_CSS_TEXT(left, )
@@ -289,6 +304,7 @@ static html_attr_t  h2_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimHei, 32, black, )
        ABC_CSS_TEXT(left, )
@@ -301,6 +317,7 @@ static html_attr_t  h3_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimHei, 28, black, )
        ABC_CSS_TEXT(left, )
@@ -313,6 +330,7 @@ static html_attr_t  h4_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimHei, 24, black, )
        ABC_CSS_TEXT(left, )
@@ -325,6 +343,7 @@ static html_attr_t  h5_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimHei, 20, black, )
        ABC_CSS_TEXT(left, )
@@ -337,6 +356,7 @@ static html_attr_t  h6_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimHei, 16, black, )
        ABC_CSS_TEXT(left, )
@@ -360,6 +380,7 @@ static html_attr_t  p_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimSong, 16, black, )
        ABC_CSS_TEXT(left, )
@@ -378,6 +399,7 @@ static html_attr_t  css_id_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimSong, 16, black, )
        ABC_CSS_TEXT(left, )
@@ -415,6 +437,7 @@ static html_attr_t  a_attrs[] =
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
        ABC_CSS_PSE()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimSong, 16, blue, )
        ABC_CSS_TEXT(left, underline)
@@ -507,18 +530,33 @@ static html_attr_t  ol_attrs[] =
        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, )
@@ -532,6 +570,7 @@ static html_attr_t  th_attrs[] =
        ABC_CSS_SCROLL( , , )
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimHei, 24, black, )
        ABC_CSS_TEXT( , )
@@ -543,6 +582,7 @@ static html_attr_t  tr_attrs[] =
        ABC_CSS_SCROLL( , , )
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimSong, 16, black, )
        ABC_CSS_TEXT( , )
@@ -554,6 +594,7 @@ static html_attr_t  td_attrs[] =
        ABC_CSS_SCROLL( , , )
        ABC_CSS_SELECTOR()
        ABC_CSS_BACK_GROUND()
+       ABC_CSS_COUNTER()
 
        ABC_CSS_FONT(SimSong, 16, black, )
        ABC_CSS_TEXT( , )
@@ -603,7 +644,7 @@ static html_label_t  html_labels[] =
 
        {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},
@@ -1108,7 +1149,7 @@ static int __html_parse_value(abc_html_t* html, abc_attr_t* attr)
                if (!c) {
                        scf_loge("\n");
                        scf_string_free(value);
-                       return -1;
+                       return -EINVAL;
                }
 
                html->pos += c->len;
@@ -1144,10 +1185,13 @@ static int __html_parse_value(abc_html_t* html, abc_attr_t* attr)
        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;
 }
 
@@ -1192,7 +1236,7 @@ static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_
                                        c->c, html->file->data, html->n_lines);
                        free(c);
                        scf_string_free(key);
-                       return -1;
+                       return -EINVAL;
                }
 
                free(c);
@@ -1220,12 +1264,11 @@ static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_
                }
        }
 
-       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;
index 89a1b6c12e125c3c5fc1befe42398c26c2ab2fa5..4b7baaceb2a90bd05bda632a8d0575a39f755b9f 100644 (file)
@@ -86,4 +86,8 @@ int  abc_css_scrollbar_color(double thumb[4], double track[4], const uint8_t* st
 
 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
index e871ba4b6918fd730b18ee4367567de655884a76..60ca2e1066eea17afab7b3d543a5eb4958e43ec4 100644 (file)
@@ -153,6 +153,20 @@ 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_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));
@@ -482,10 +496,15 @@ void abc_obj_print(abc_obj_t* obj)
                }
        }
 
-       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);
@@ -722,23 +741,34 @@ static scf_string_t* __li_style_number(int num, uint32_t base, const char c0)
 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');
index a574f7de6c36a4479c43376ede5de7e84fcb7754..a49329578a7b82a427fd50a39ddefb3ac7a5003a 100644 (file)
@@ -6,13 +6,14 @@
 #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
 {
@@ -174,16 +175,22 @@ 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,
@@ -244,13 +251,24 @@ struct abc_text_s
 {
        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
@@ -350,6 +368,9 @@ struct abc_obj_s
        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;
@@ -437,6 +458,8 @@ abc_obj_t*     abc_obj_alloc(scf_string_t* file, int line, int pos, int type);
 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);
 
index ac82cd5c2d958bff7b9429c64c54db98b220dd7c..c73f9a24471c81f3215cbb6c841e5c697353734f 100644 (file)
@@ -108,7 +108,7 @@ int scf_string_cmp(const scf_string_t* s0, const scf_string_t* s1)
 
        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)
index fe8d516dcb9ff9fc231d74b11754835836bcde67..36893bd873f9236223797832c5955901e70eda83 100644 (file)
@@ -14,6 +14,7 @@ CFILES += abc_layout_label.c
 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
@@ -52,6 +53,7 @@ CFILES += ../html/abc_css_position.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
index 121fdd04b98bb0107cb1b547623bc888dfe4740d..279f2e5537a9b42c124a47fa1406082202e563f1 100644 (file)
@@ -108,11 +108,11 @@ int __init_text(cairo_t* cr, abc_obj_t* obj, int num_flag, double scale)
                        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;
        }
 
@@ -122,14 +122,19 @@ int __init_text(cairo_t* cr, abc_obj_t* obj, int num_flag, double scale)
        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;
 
index 244380ba30b0091b33b744e79df471bcbcd0f597..28689e0cf5b8e64053d22e104ae55b068d2f49be 100644 (file)
@@ -15,6 +15,7 @@ int abc_layout_input(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height);
 
 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);
@@ -69,7 +70,7 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] =
 
        [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,
index c045ee882ca50ea4d11895b9b2c2a20b54a2abd4..939476ee58f49eedd4031efcbbc1b683bda0d8b2 100644 (file)
@@ -3,7 +3,6 @@
 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;
@@ -23,60 +22,15 @@ int abc_layout_h1(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height)
        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)
@@ -84,7 +38,7 @@ int abc_layout_h1(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height)
 
        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",
diff --git a/ui/abc_layout_li.c b/ui/abc_layout_li.c
new file mode 100644 (file)
index 0000000..312b51d
--- /dev/null
@@ -0,0 +1,104 @@
+#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;
+}
index cb11c1b6079ff7f542e4687892997bff7060ec56..1a4e29954bb4b160d1e08efea843f4ebe353edb9 100644 (file)
@@ -1,6 +1,6 @@
 #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--) {
@@ -27,10 +27,73 @@ static int __layout_text_split(cairo_text_extents_t* extents, cairo_t* cr, const
        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) {
@@ -57,73 +120,82 @@ int __layout_text(cairo_t* cr, abc_obj_t* obj, int x, int width, cairo_text_exte
        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;
 }
 
@@ -138,6 +210,19 @@ int abc_layout_text(abc_ctx_t* ctx, abc_obj_t* obj, int width, int height)
        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;
 
index 2407ae7ace378a9ff3676cc72667b695c4d7809a..d02e9a7f4e79b848c157b40226662ded2883b4aa 100644 (file)
@@ -125,18 +125,14 @@ static int _render_draw_li(abc_render_t* render, abc_obj_t* obj, int width, int
                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;
index 04da387cb835214fcf5a8f15b9c3e78b49f724e5..c11d96d4017846315f7f96e939dd99b83836b926 100644 (file)
@@ -159,7 +159,7 @@ static int _render_draw_text(abc_render_t* render, abc_obj_t* obj, int width, in
 
                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;
@@ -172,8 +172,11 @@ static int _render_draw_text(abc_render_t* render, abc_obj_t* obj, int width, in
                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);
index a0b458794e3846e1c96658c474922c95f841a240..653589354489e2a8e64fd23d8128f7841357d589 100644 (file)
@@ -111,7 +111,7 @@ int scf_string_cmp(const scf_string_t* s0, const scf_string_t* s1)
 
        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)