From 048df23d3846ddf9779cf7b0bc8b696d6c88514b Mon Sep 17 00:00:00 2001 From: "yu.dongliang" <18588496441@163.com> Date: Mon, 25 May 2026 21:42:51 +0800 Subject: [PATCH] css: support 'position sticky, fixed, absolute, relative, static' --- examples/padding.html | 26 +++++++ examples/position_sticky.html | 32 ++++++++ html/abc_css_length.c | 42 +++++----- html/abc_html.c | 80 +++++++++++++------ html/abc_obj.c | 48 ++++++++++++ html/abc_obj.h | 23 ++++-- ui/abc_layout.c | 141 ++++++++++++++++++++-------------- ui/abc_layout_div.c | 6 +- ui/abc_render.c | 38 ++++++++- ui/main.c | 8 +- 10 files changed, 327 insertions(+), 117 deletions(-) create mode 100644 examples/padding.html create mode 100644 examples/position_sticky.html diff --git a/examples/padding.html b/examples/padding.html new file mode 100644 index 0000000..0d84985 --- /dev/null +++ b/examples/padding.html @@ -0,0 +1,26 @@ + + + + +菜鸟教程(runoob.com) + + + + +

这是一个没有指定填充边距的段落。

+

这是一个指定填充边距的段落。

+ + + diff --git a/examples/position_sticky.html b/examples/position_sticky.html new file mode 100644 index 0000000..ecc9df2 --- /dev/null +++ b/examples/position_sticky.html @@ -0,0 +1,32 @@ + + + + + + + + +

尝试滚动页面。

+

注意: IE/Edge 15 及更早 IE 版本不支持 sticky 属性。

+ +
我是粘性定位!
+ +
+

滚动我

+

来回滚动我

+

滚动我

+

来回滚动我

+

滚动我

+

来回滚动我

+
+ + + diff --git a/html/abc_css_length.c b/html/abc_css_length.c index 9b1fa6a..59b5f57 100644 --- a/html/abc_css_length.c +++ b/html/abc_css_length.c @@ -71,46 +71,48 @@ next: int abc_css_width(abc_obj_t* obj, int width) { + obj->left = obj->margin_left + obj->border_left + obj->padding_left; + obj->right = obj->margin_right + obj->border_right + obj->padding_right; + abc_attr_t* attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_WIDTH); if (attr && attr->value && attr->value->len > 0) { obj->w = abc_css_length(obj, width, attr->value->data); - - obj->w += obj->margin_left + obj->border_left - + obj->padding_left - + obj->padding_right - + obj->border_right - + obj->margin_right; - - if (obj->w > width - obj->x) - obj->w = width - obj->x; + obj->w += obj->left + obj->right; return 1; } - obj->w = width - obj->x; + if (obj->x + obj->left + obj->right < width) + obj->w = width - obj->x; + + else if (obj->left + obj->right < width) + obj->w = width - obj->left - obj->right; + else + obj->w = width + obj->left + obj->right; return 0; } int abc_css_height(abc_obj_t* obj, int height) { + obj->top = obj->margin_top + obj->border_top + obj->padding_top; + obj->bottom = obj->margin_bottom + obj->border_bottom + obj->padding_bottom; + abc_attr_t* attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_HEIGHT); if (attr && attr->value && attr->value->len > 0) { obj->h = abc_css_length(obj, height, attr->value->data); - - obj->h += obj->margin_top + obj->border_top - + obj->padding_top - + obj->padding_bottom - + obj->border_bottom - + obj->margin_bottom; - - if (obj->h > height - obj->y) - obj->h = height - obj->y; + obj->h += obj->top + obj->bottom; return 1; } - obj->h = height - obj->y; + if (obj->y + obj->top + obj->bottom < height) + obj->h = height - obj->y; + + else if (obj->bottom + obj->top < height) + obj->h = height - obj->top - obj->bottom; + else + obj->h = height + obj->top + obj->bottom; return 0; } diff --git a/html/abc_html.c b/html/abc_html.c index beecad4..20bedb2 100644 --- a/html/abc_html.c +++ b/html/abc_html.c @@ -148,20 +148,6 @@ static char* css_active_keys[] = {":active", "正在点击", NULL}; static char* css_first_child_keys[] = {":first-child", "第1个子元素", "第一个子元素", NULL}; static html_attr_t html_attrs[] = -{ - {xmlns_keys, "", ABC_HTML_ATTR_XMLNS, 0}, - {xmlang_keys, "", ABC_HTML_ATTR_XMLANG, 0}, - {lang_keys, "", ABC_HTML_ATTR_LANG, 0}, -}; - -static html_attr_t meta_attrs[] = -{ - {http_equiv_keys, "", ABC_HTML_ATTR_HTTP_EQUIV, ABC_HTML_FLAG_SHOW}, - {content_keys, "", ABC_HTML_ATTR_CONTENT, ABC_HTML_FLAG_SHOW}, - {charset_keys, "", ABC_HTML_ATTR_CHARSET, ABC_HTML_FLAG_SHOW}, -}; - -static html_attr_t body_attrs[] = { #define ABC_CSS_BOX(margin, border, padding) \ {border_keys, #border, ABC_CSS_BORDER, ABC_HTML_FLAG_SHOW}, \ @@ -182,10 +168,6 @@ static html_attr_t body_attrs[] = {padding_left_keys, #padding, ABC_CSS_PADDING_LEFT, ABC_HTML_FLAG_SHOW}, \ {padding_right_keys, #padding, ABC_CSS_PADDING_RIGHT, ABC_HTML_FLAG_SHOW}, \ \ - {overflow_keys, "", ABC_CSS_OVERFLOW, ABC_HTML_FLAG_SHOW}, \ - {scroll_width_keys, "", ABC_CSS_SCROLLBAR_WIDTH, ABC_HTML_FLAG_SHOW}, \ - {scroll_color_keys, "", ABC_CSS_SCROLLBAR_COLOR, ABC_HTML_FLAG_SHOW}, \ - \ {position_keys, "", ABC_CSS_POSITION, ABC_HTML_FLAG_SHOW}, \ {top_keys, "", ABC_CSS_TOP, ABC_HTML_FLAG_SHOW}, \ {bottom_keys, "", ABC_CSS_BOTTOM, ABC_HTML_FLAG_SHOW}, \ @@ -195,6 +177,11 @@ static html_attr_t body_attrs[] = {width_keys, "", ABC_HTML_ATTR_WIDTH, ABC_HTML_FLAG_SHOW}, \ {height_keys, "", ABC_HTML_ATTR_HEIGHT, ABC_HTML_FLAG_SHOW}, +#define ABC_CSS_SCROLL(overflow, scroll_width, scroll_color) \ + {overflow_keys, #overflow, ABC_CSS_OVERFLOW, ABC_HTML_FLAG_SHOW}, \ + {scroll_width_keys, #scroll_width, ABC_CSS_SCROLLBAR_WIDTH, ABC_HTML_FLAG_SHOW}, \ + {scroll_color_keys, #scroll_color, ABC_CSS_SCROLLBAR_COLOR, ABC_HTML_FLAG_SHOW}, + #define ABC_CSS_SELECTOR() \ {style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW}, \ {class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW}, \ @@ -219,7 +206,30 @@ static html_attr_t body_attrs[] = {text_transform_keys, "", ABC_HTML_ATTR_TEXT_TRANSFORM, ABC_HTML_FLAG_SHOW}, \ {text_indent_keys, "", ABC_HTML_ATTR_TEXT_INDENT, ABC_HTML_FLAG_SHOW}, - ABC_CSS_BOX(4px, , 4px) + ABC_CSS_BOX( , , 12px) + ABC_CSS_SCROLL(scroll, 12px, orangeRed white) + ABC_CSS_SELECTOR() + ABC_CSS_BACK_GROUND(white) + + ABC_CSS_FONT(SimSong, 16, black, ) + ABC_CSS_TEXT(left, ) + + {xmlns_keys, "", ABC_HTML_ATTR_XMLNS, 0}, + {xmlang_keys, "", ABC_HTML_ATTR_XMLANG, 0}, + {lang_keys, "", ABC_HTML_ATTR_LANG, 0}, +}; + +static html_attr_t meta_attrs[] = +{ + {http_equiv_keys, "", ABC_HTML_ATTR_HTTP_EQUIV, ABC_HTML_FLAG_SHOW}, + {content_keys, "", ABC_HTML_ATTR_CONTENT, ABC_HTML_FLAG_SHOW}, + {charset_keys, "", ABC_HTML_ATTR_CHARSET, ABC_HTML_FLAG_SHOW}, +}; + +static html_attr_t body_attrs[] = +{ + ABC_CSS_BOX( , , 8px) + ABC_CSS_SCROLL( , 8px, orangeRed white) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND(white) @@ -230,6 +240,7 @@ static html_attr_t body_attrs[] = static html_attr_t div_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -240,6 +251,7 @@ static html_attr_t div_attrs[] = static html_attr_t h1_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -250,6 +262,7 @@ static html_attr_t h1_attrs[] = static html_attr_t h2_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -260,6 +273,7 @@ static html_attr_t h2_attrs[] = static html_attr_t h3_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -270,6 +284,7 @@ static html_attr_t h3_attrs[] = static html_attr_t h4_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -280,6 +295,7 @@ static html_attr_t h4_attrs[] = static html_attr_t h5_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -290,6 +306,7 @@ static html_attr_t h5_attrs[] = static html_attr_t h6_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -300,6 +317,7 @@ static html_attr_t h6_attrs[] = static html_attr_t p_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -318,6 +336,7 @@ static html_attr_t css_id_attrs[] = {list_style_pos_keys, "", ABC_CSS_LIST_STYLE_POSITION, ABC_HTML_FLAG_SHOW}, ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -331,6 +350,7 @@ static html_attr_t css_id_attrs[] = static html_attr_t b_attrs[] = { ABC_CSS_BOX( , , ) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -343,6 +363,7 @@ static html_attr_t b_attrs[] = static html_attr_t i_attrs[] = { ABC_CSS_BOX( , , ) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -355,6 +376,7 @@ static html_attr_t i_attrs[] = static html_attr_t a_attrs[] = { ABC_CSS_BOX( , , ) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -378,14 +400,16 @@ static html_attr_t link_attrs[] = static html_attr_t img_attrs[] = { ABC_CSS_BOX( , , ) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() - {src_keys, "", ABC_HTML_ATTR_SRC, ABC_HTML_FLAG_SHOW}, + {src_keys, "", ABC_HTML_ATTR_SRC, ABC_HTML_FLAG_SHOW}, }; static html_attr_t video_attrs[] = { ABC_CSS_BOX( , , ) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() {control_keys, "", ABC_HTML_ATTR_CONTROLS, 0}, @@ -405,32 +429,35 @@ static html_attr_t source_attrs[] = static html_attr_t input_attrs[] = { ABC_CSS_BOX(1px, 1px, 1px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() ABC_CSS_FONT(SimSong, 16, black, ) ABC_CSS_TEXT(left, ) - {type_keys, "text", ABC_HTML_ATTR_TYPE, ABC_HTML_FLAG_SHOW}, - {name_keys, "", ABC_HTML_ATTR_NAME, ABC_HTML_FLAG_SHOW}, - {value_keys, "", ABC_HTML_ATTR_VALUE, ABC_HTML_FLAG_SHOW}, + {type_keys, "text", ABC_HTML_ATTR_TYPE, ABC_HTML_FLAG_SHOW}, + {name_keys, "", ABC_HTML_ATTR_NAME, ABC_HTML_FLAG_SHOW}, + {value_keys, "", ABC_HTML_ATTR_VALUE, ABC_HTML_FLAG_SHOW}, }; static html_attr_t label_attrs[] = { ABC_CSS_BOX(1px, 1px, 1px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() ABC_CSS_FONT(SimSong, 16, black, ) ABC_CSS_TEXT(left, ) - {for_keys, "", ABC_HTML_ATTR_FOR, ABC_HTML_FLAG_SHOW}, + {for_keys, "", ABC_HTML_ATTR_FOR, ABC_HTML_FLAG_SHOW}, }; static html_attr_t form_attrs[] = { ABC_CSS_BOX(1px, 1px, 1px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -445,6 +472,7 @@ static html_attr_t form_attrs[] = static html_attr_t ol_attrs[] = { ABC_CSS_BOX(2px, , 2px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -456,6 +484,7 @@ static html_attr_t ol_attrs[] = static html_attr_t table_attrs[] = { ABC_CSS_BOX(2px, 2px, 4px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -468,6 +497,7 @@ static html_attr_t table_attrs[] = static html_attr_t th_attrs[] = { ABC_CSS_BOX(2px, 2px, 4px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -480,6 +510,7 @@ static html_attr_t th_attrs[] = static html_attr_t td_attrs[] = { ABC_CSS_BOX(2px, 2px, 4px) + ABC_CSS_SCROLL( , , ) ABC_CSS_SELECTOR() ABC_CSS_BACK_GROUND() @@ -971,6 +1002,7 @@ static int __html_parse_text(abc_html_t* html, abc_obj_t* obj) obj->text = NULL; \ mov->parent = obj; \ mov->flags = obj->flags; \ + mov->index = obj->n_childs++; \ scf_list_add_tail(&obj->childs, &mov->list); \ scf_logd("--- %s, %s\n", obj->keys[0], mov->text->data); \ } while (0) diff --git a/html/abc_obj.c b/html/abc_obj.c index 411572f..c6a661b 100644 --- a/html/abc_obj.c +++ b/html/abc_obj.c @@ -82,7 +82,18 @@ void abc_attr_free(abc_attr_t* attr) void abc_dfs_update_xy(abc_obj_t* root, int dx, int dy) { scf_list_t* l; + abc_attr_t* attr; abc_obj_t* obj; + abc_obj_t* html = root; + + while (html && ABC_HTML != html->type) + html = html->parent; + + int X0 = html->x + html->left; + int X1 = html->x + html->w - html->right; + + int Y0 = html->y + html->top; + int Y1 = html->y + html->h - html->bottom; for (l = scf_list_head(&root->childs); l != scf_list_sentinel(&root->childs); l = scf_list_next(l)) { obj = scf_list_data(l, abc_obj_t, list); @@ -90,6 +101,43 @@ void abc_dfs_update_xy(abc_obj_t* root, int dx, int dy) obj->x += dx; obj->y += dy; + switch (obj->position_type) + { + case ABC_POSITION_FIXED: + if (obj->css_left) + obj->x = X0 + obj->css_left; + else if (obj->right_set) + obj->x = X1 - obj->css_right - obj->w; + + if (obj->top_set) + obj->y = Y0 + obj->css_top; + else if (obj->bottom_set) + obj->y = Y1 - obj->css_bottom - obj->h; + break; + + case ABC_POSITION_STICKY: + if (obj->left_set) { + if (obj->x < X0 + obj->css_left) + obj->x = X0 + obj->css_left; + + } else if (obj->right_set) { + if (obj->x > X1 - obj->css_right - obj->w) + obj->x = X1 - obj->css_right - obj->w; + } + + if (obj->top_set) { + if (obj->y < Y0 + obj->css_top) + obj->y = Y0 + obj->css_top; + + } else if (obj->bottom_set) { + if (obj->y > Y1 - obj->css_bottom - obj->h) + obj->y = Y1 - obj->css_bottom - obj->h; + } + break; + default: + break; + }; + abc_dfs_update_xy(obj, dx, dy); } } diff --git a/html/abc_obj.h b/html/abc_obj.h index d775695..ff49d6a 100644 --- a/html/abc_obj.h +++ b/html/abc_obj.h @@ -182,14 +182,14 @@ enum abc_objs ABC_CSS_CLASS = ABC_HTML_ATTR_CLASS, }; -enum abc_border_style +enum abc_border_type { ABC_BORDER_SOLID, ABC_BORDER_DOTTED, ABC_BORDER_DASHED, }; -enum abc_line_style +enum abc_line_type { ABC_LINE_NONE, ABC_LINE_UNDER, @@ -197,16 +197,16 @@ enum abc_line_style ABC_LINE_THROUGH, }; -enum abc_position_style +enum abc_position_type { ABC_POSITION_STATIC, ABC_POSITION_RELATIVE, ABC_POSITION_ABSOLUTE, - ABC_POSITION_FIXED, ABC_POSITION_STICKY, + ABC_POSITION_FIXED, }; -enum abc_overflow_style +enum abc_overflow_type { ABC_OVERFLOW_VISIBLE, ABC_OVERFLOW_HIDDEN, @@ -295,6 +295,7 @@ struct abc_obj_s int padding_left; int padding_right; + // the sum of margin + border + padding for top, bottom, left, right int top; int bottom; int left; @@ -309,6 +310,13 @@ struct abc_obj_s int h; int overflow_type; + int position_type; + + int css_top; + int css_bottom; + int css_left; + int css_right; + // view area that object can see int view_x; int view_y; @@ -349,6 +357,11 @@ struct abc_obj_s uint32_t w_set:1; uint32_t h_set:1; + + uint32_t top_set:1; + uint32_t bottom_set:1; + uint32_t left_set:1; + uint32_t right_set:1; }; abc_obj_t* abc_obj_alloc(scf_string_t* file, int line, int pos, int type); diff --git a/ui/abc_layout.c b/ui/abc_layout.c index a1555f1..c03ef1a 100644 --- a/ui/abc_layout.c +++ b/ui/abc_layout.c @@ -23,9 +23,16 @@ int abc_layout_empty(abc_layout_t* layout, abc_obj_t* obj, int width, int height return 0; } +int abc_layout_html(abc_layout_t* layout, abc_obj_t* obj, int width, int height) +{ + obj->w = obj->w0; + obj->h = obj->h0; + return 0; +} + static abc_layout_pt abc_layouts[ABC_HTML_NB] = { - [ABC_HTML] = abc_layout_empty, + [ABC_HTML] = abc_layout_html, [ABC_HTML_TITLE] = abc_layout_empty, [ABC_HTML_META] = abc_layout_empty, [ABC_HTML_HEAD] = abc_layout_empty, @@ -86,31 +93,32 @@ int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height) return f(layout, obj, width, height); } -#define LAYOUT_POS_FIXED(X, W, SET, L, R) \ +#define LAYOUT_POS_FIXED(X, W, W_SET, L_SET, R_SET, L, R) \ do { \ - if (!obj->SET) { \ - if (L && R) { \ - obj->X = parent->X + L; \ - obj->W = parent->W - L - R; \ - } else if (L) \ - obj->X = parent->X + L; \ - else if (R) \ - obj->X = parent->X + parent->W - R - obj->W; \ - } else if (L) \ - obj->X = parent->X + L; \ - else if (R) \ - obj->X = parent->X + parent->W - R - obj->W; \ + abc_obj_t* tmp = parent; \ + while (tmp && ABC_HTML != tmp->type) \ + tmp = tmp->parent; \ + \ + if (tmp) { \ + if (!obj->W_SET && obj->L && obj->R) \ + obj->W = tmp->W - obj->L - obj->R; \ + \ + if (obj->L_SET) \ + obj->X = tmp->X + obj->L; \ + else if (obj->R_SET) \ + obj->X = tmp->X + tmp->W - obj->R - obj->W; \ + } \ } while (0) -#define LAYOUT_POS_RELATIVE(X, L, R) \ +#define LAYOUT_POS_RELATIVE(X, L_SET, R_SET, L, R) \ do { \ - if (L) \ - obj->X += L; \ - else if (R) \ - obj->X += R; \ + if (obj->L_SET) \ + obj->X += obj->L; \ + else if (obj->R_SET) \ + obj->X += obj->R; \ } while (0) -#define LAYOUT_POS_ABSOLUTE(X, W, L, R) \ +#define LAYOUT_POS_ABSOLUTE(X, W, L_SET, R_SET, L, R) \ do { \ abc_obj_t* tmp = parent; \ while (tmp && ABC_HTML != tmp->type) { \ @@ -122,10 +130,10 @@ int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height) tmp = tmp->parent; \ } \ if (tmp) { \ - if (L) \ - obj->X = tmp->X + L; \ - else if (R) \ - obj->X = tmp->X + tmp->W - R - obj->W; \ + if (obj->L_SET) \ + obj->X = tmp->X + obj->L; \ + else if (obj->R_SET) \ + obj->X = tmp->X + tmp->W - obj->R - obj->W; \ } \ } while (0) @@ -160,54 +168,61 @@ int abc_layout_css(abc_obj_t* obj) abc_dfs_update_xy(obj, obj->x - x, 0); } - attr = abc_obj_get_attr(obj, ABC_CSS_POSITION); - if (!attr || 0 == attr->value->len) + if (ABC_POSITION_STATIC == obj->position_type) return 0; - int pos_type = abc_css_position(attr->value->data); - if (ABC_POSITION_STATIC == pos_type) - return 0; + obj->css_top = 0; + obj->css_bottom = 0; + obj->css_left = 0; + obj->css_right = 0; - int top = 0; - int bottom = 0; - int left = 0; - int right = 0; + obj->top_set = 0; + obj->bottom_set = 0; + obj->left_set = 0; + obj->right_set = 0; attr = abc_obj_get_attr(obj, ABC_CSS_TOP); - if (attr) - top = abc_css_length(obj, obj->h, attr->value->data); + if (attr && attr->value && attr->value->len > 0) { + obj->top_set = 1; + obj->css_top = abc_css_length(obj, obj->h, attr->value->data); + } attr = abc_obj_get_attr(obj, ABC_CSS_BOTTOM); - if (attr) - bottom = abc_css_length(obj, obj->h, attr->value->data); + if (attr && attr->value && attr->value->len > 0) { + obj->bottom_set = 1; + obj->css_bottom = abc_css_length(obj, obj->h, attr->value->data); + } attr = abc_obj_get_attr(obj, ABC_CSS_LEFT); - if (attr) - left = abc_css_length(obj, obj->w, attr->value->data); + if (attr && attr->value && attr->value->len > 0) { + obj->left_set = 1; + obj->css_left = abc_css_length(obj, obj->w, attr->value->data); + } attr = abc_obj_get_attr(obj, ABC_CSS_RIGHT); - if (attr) - right = abc_css_length(obj, obj->w, attr->value->data); + if (attr && attr->value && attr->value->len > 0) { + obj->right_set = 1; + obj->css_right = abc_css_length(obj, obj->w, attr->value->data); + } int x = obj->x; int y = obj->y; - switch (pos_type) + switch (obj->position_type) { case ABC_POSITION_FIXED: - LAYOUT_POS_FIXED(x, w, w_set, left, right); - LAYOUT_POS_FIXED(y, h, h_set, top, bottom); + LAYOUT_POS_FIXED(x, w, w_set, left_set, right_set, css_left, css_right); + LAYOUT_POS_FIXED(y, h, h_set, top_set, bottom_set, css_top, css_bottom); break; case ABC_POSITION_RELATIVE: - scf_logd("top: %d, bottom: %d, left: %d, right: %d, obj->w: %d, parent->w: %d\n", top, bottom, left, right, obj->w, parent->w); - LAYOUT_POS_RELATIVE(x, left, right); - LAYOUT_POS_RELATIVE(y, top, bottom); + LAYOUT_POS_RELATIVE(x, left_set, right_set, css_left, css_right); + LAYOUT_POS_RELATIVE(y, top_set, bottom_set, css_top, css_bottom); break; case ABC_POSITION_ABSOLUTE: - LAYOUT_POS_ABSOLUTE(x, w, left, right); - LAYOUT_POS_ABSOLUTE(y, h, top, bottom); + LAYOUT_POS_ABSOLUTE(x, w, left_set, right_set, css_left, css_right); + LAYOUT_POS_ABSOLUTE(y, h, top_set, bottom_set, css_top, css_bottom); break; default: break; @@ -215,7 +230,7 @@ int abc_layout_css(abc_obj_t* obj) abc_dfs_update_xy(obj, obj->x - x, obj->y - y); - return pos_type; + return obj->position_type; } int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height) @@ -261,15 +276,15 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height) root->w_set = abc_css_width (root, width); root->h_set = abc_css_height(root, height); - if (root->w_set) { + root_w = root->w; + root_h = root->h; + + if (root->w_set) root->w0 = root->w; - root_w = root->w; - } - if (root->h_set) { + if (root->h_set) root->h0 = root->h; - root_h = root->h; - } else { + else { if (ABC_HTML_BODY != root->type) root->h = 0; } @@ -287,9 +302,16 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height) root->right = root->margin_right + root->border_right + root->padding_right; root->overflow_type = ABC_OVERFLOW_VISIBLE; + root->position_type = ABC_POSITION_STATIC; scf_list_t* l; abc_obj_t* child; + abc_attr_t* attr = abc_obj_get_attr(root, ABC_CSS_POSITION); + + if (attr && attr->value && attr->value->len > 0) + { + root->position_type = abc_css_position(attr->value->data); + } int x = root->x + root->left; int y = root->y + root->top; @@ -301,6 +323,9 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height) root_w -= root->left + root->right; root_h -= root->top + root->bottom; + scf_logd("w: %d, h: %d, top: %d, bottom: %d, left: %d, right: %d, root_w: %d, root_h: %d\n", + root->w, root->h, root->top, root->bottom, root->left, root->right, root_w, root_h); + for (l = scf_list_head(&root->childs); l != scf_list_sentinel(&root->childs); l = scf_list_next(l)) { child = scf_list_data(l, abc_obj_t, list); @@ -427,8 +452,8 @@ int abc_layout_root(abc_ctx_t* abc, abc_obj_t* root, int width, int height) scf_logw("key: %s, ", root->keys[0]); // if (root->text) // printf("%s, ", root->text->data); - printf("x: %d, y: %d, w: %d, h: %d, content_w: %d, content_h: %d: %d\n", - root->x, root->y, root->w, root->h, root->content_w, root->content_h, root->content_h - root->d * 2); + printf("x: %d, y: %d, w: %d, h: %d, bottom: %d, content_w: %d, content_h: %d\n", + root->x, root->y, root->w, root->h, root->bottom, root->content_w, root->content_h); #endif return 0; } diff --git a/ui/abc_layout_div.c b/ui/abc_layout_div.c index f1c0fe2..ea423e4 100644 --- a/ui/abc_layout_div.c +++ b/ui/abc_layout_div.c @@ -47,9 +47,9 @@ int abc_layout_div(abc_layout_t* layout, abc_obj_t* obj, int width, int height) obj->w = obj->w_set ? obj->w0 : w; obj->h = obj->h_set ? obj->h0 : h + obj->h; - 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, + scf_logd("%s, w: %d, h: %d, top: %d, bottom: %d, left: %d, right: %d, x_bearing: %lg, width: %lg, height: %lg, x_advance: %lg, y_advance: %lg, width: %d, height: %d\n", + obj->text->data, obj->w, obj->h, obj->top, obj->bottom, obj->left, obj->right, + extents.x_bearing, extents.width, extents.height, extents.x_advance, extents.y_advance, width, height); cairo_destroy(cr); diff --git a/ui/abc_render.c b/ui/abc_render.c index a8e375c..43a3d50 100644 --- a/ui/abc_render.c +++ b/ui/abc_render.c @@ -24,7 +24,7 @@ extern abc_render_t abc_render_empty; static abc_render_t* abc_renders[ABC_HTML_NB] = { - [ABC_HTML] = &abc_render_empty, + [ABC_HTML] = &abc_render_body, [ABC_HTML_HEAD] = &abc_render_empty, [ABC_HTML_META] = &abc_render_empty, [ABC_HTML_TITLE] = &abc_render_empty, @@ -104,6 +104,18 @@ int abc_render_draw(abc_obj_t* obj, int width, int height) return render->draw(render, obj, width, height); } +static int __obj_render_cmp(const void* v0, const void* v1) +{ + const abc_obj_t* obj0 = *(const abc_obj_t**)v0; + const abc_obj_t* obj1 = *(const abc_obj_t**)v1; + + if (obj0->position_type < obj1->position_type) + return -1; + else if (obj0->position_type > obj1->position_type) + return 1; + return 0; +} + static int __render_root(abc_ctx_t* ctx, abc_obj_t* root, int width, int height) { switch (root->type) @@ -119,20 +131,38 @@ static int __render_root(abc_ctx_t* ctx, abc_obj_t* root, int width, int height) scf_list_t* l; abc_obj_t* child; + abc_obj_t** childs; int ret = abc_render_draw(root, width, height); if (ret < 0) return ret; + childs = calloc(root->n_childs + 1, sizeof(abc_obj_t*)); + if (!childs) + return -ENOMEM; + + int i; + int n = 0; for (l = scf_list_head(&root->childs); l != scf_list_sentinel(&root->childs); l = scf_list_next(l)) { child = scf_list_data(l, abc_obj_t, list); - ret = __render_root(ctx, child, width, height); + childs[n++] = child; + + assert(n <= root->n_childs); + } + + qsort(childs, n, sizeof(abc_obj_t*), __obj_render_cmp); + + for (i = 0; i < n; i++) { + ret = __render_root(ctx, childs[i], width, height); if (ret < 0) - return ret; + goto error; } - return 0; + ret = 0; +error: + free(childs); + return ret; } int abc_render_root(abc_ctx_t* ctx, abc_obj_t* root, int width, int height) diff --git a/ui/main.c b/ui/main.c index b232f49..a5a2e99 100644 --- a/ui/main.c +++ b/ui/main.c @@ -94,7 +94,7 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y) prev->mouse_move_x = -1; prev->mouse_move_y = -1; - if (ABC_HTML_DIV == prev->type) + if (ABC_HTML == prev->type) scf_logw("prev: %p mouse down_x: %d, down_y: %d, move_x: %d, move_y: %d\n", prev, prev->mouse_down_x, prev->mouse_down_y, @@ -138,6 +138,8 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y) } break; + case ABC_HTML: + case ABC_HTML_BODY: case ABC_HTML_DIV: ret = 1; break; @@ -145,7 +147,7 @@ static int __do_button_move(abc_ctx_t* ctx, int x, int y) break; }; - if (ABC_HTML_DIV == obj->type) + if (ABC_HTML == obj->type) scf_logw("obj: %p, mouse down_x: %d, down_y: %d, move_x: %d, move_y: %d\n", obj, obj->mouse_down_x, obj->mouse_down_y, @@ -374,7 +376,7 @@ static gboolean button_press_event(GtkWidget* self, GdkEventButton* event, gpoin obj->mouse_move_x = -1; obj->mouse_move_y = -1; - if (ABC_HTML_DIV == obj->type) + if (ABC_HTML == obj->type) scf_logw("obj: %p mouse down_x: %d, down_y: %d, move_x: %d, move_y: %d\n", obj, obj->mouse_down_x, obj->mouse_down_y, -- 2.25.1