From: yu.dongliang <18588496441@163.com> Date: Sat, 6 Jun 2026 06:43:43 +0000 (+0800) Subject: css: support counter() & counters() X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=d2b702d86a2c3509215628198c9110fd4f9cc9d2;p=abc.git css: support counter() & counters() --- diff --git a/examples/counter.html b/examples/counter.html new file mode 100644 index 0000000..da86816 --- /dev/null +++ b/examples/counter.html @@ -0,0 +1,27 @@ + + +
+ +注æ: IE8 éè¦æå® !DOCTYPE æå¯ä»¥æ¯æè¯¥å±æ§ã
+ + + diff --git a/examples/counters.html b/examples/counters.html new file mode 100644 index 0000000..7a8038c --- /dev/null +++ b/examples/counters.html @@ -0,0 +1,48 @@ + + + + +注æ: IE8 éè¦æå® !DOCTYPE æå¯ä»¥æ¯æè¯¥å±æ§ã
+ + + diff --git a/html/Makefile b/html/Makefile index d41e793..bbb8c73 100644 --- a/html/Makefile +++ b/html/Makefile @@ -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 diff --git a/html/abc_css.c b/html/abc_css.c index 0a6713b..ba92c41 100644 --- a/html/abc_css.c +++ b/html/abc_css.c @@ -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 index 0000000..a91985a --- /dev/null +++ b/html/abc_css_counter.c @@ -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; +} diff --git a/html/abc_html.c b/html/abc_html.c index c0af1e8..fbe1832 100644 --- a/html/abc_html.c +++ b/html/abc_html.c @@ -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; diff --git a/html/abc_html.h b/html/abc_html.h index 89a1b6c..4b7baac 100644 --- a/html/abc_html.h +++ b/html/abc_html.h @@ -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 diff --git a/html/abc_obj.c b/html/abc_obj.c index e871ba4..60ca2e1 100644 --- a/html/abc_obj.c +++ b/html/abc_obj.c @@ -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'); diff --git a/html/abc_obj.h b/html/abc_obj.h index a574f7d..a493295 100644 --- a/html/abc_obj.h +++ b/html/abc_obj.h @@ -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); diff --git a/js/util/scf_string.c b/js/util/scf_string.c index ac82cd5..c73f9a2 100644 --- a/js/util/scf_string.c +++ b/js/util/scf_string.c @@ -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) diff --git a/ui/Makefile b/ui/Makefile index fe8d516..36893bd 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -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 diff --git a/ui/__render_text.c b/ui/__render_text.c index 121fdd0..279f2e5 100644 --- a/ui/__render_text.c +++ b/ui/__render_text.c @@ -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; diff --git a/ui/abc_layout.c b/ui/abc_layout.c index 244380b..28689e0 100644 --- a/ui/abc_layout.c +++ b/ui/abc_layout.c @@ -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, diff --git a/ui/abc_layout_h1.c b/ui/abc_layout_h1.c index c045ee8..939476e 100644 --- a/ui/abc_layout_h1.c +++ b/ui/abc_layout_h1.c @@ -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 index 0000000..312b51d --- /dev/null +++ b/ui/abc_layout_li.c @@ -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; +} diff --git a/ui/abc_layout_text.c b/ui/abc_layout_text.c index cb11c1b..1a4e299 100644 --- a/ui/abc_layout_text.c +++ b/ui/abc_layout_text.c @@ -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; diff --git a/ui/abc_render_li.c b/ui/abc_render_li.c index 2407ae7..d02e9a7 100644 --- a/ui/abc_render_li.c +++ b/ui/abc_render_li.c @@ -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; diff --git a/ui/abc_render_text.c b/ui/abc_render_text.c index 04da387..c11d96d 100644 --- a/ui/abc_render_text.c +++ b/ui/abc_render_text.c @@ -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); diff --git a/util/scf_string.c b/util/scf_string.c index a0b4587..6535893 100644 --- a/util/scf_string.c +++ b/util/scf_string.c @@ -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)