From 58af1588b87682b86900deccf94f08258b5ff495 Mon Sep 17 00:00:00 2001
From: "yu.dongliang" <18588496441@163.com>
Date: Sat, 25 Apr 2026 18:39:41 +0800
Subject: [PATCH] css: border, margin, padding of
---
examples/table.html | 6 +-
html/Makefile | 1 +
html/abc_css.c | 45 +++++++++++-
html/abc_css_border.c | 154 ++++++++++++++++++++++++++++++++++++++++++
html/abc_html.c | 44 +++++++++---
html/abc_html.h | 3 +
html/abc_obj.h | 9 +++
ui/Makefile | 1 +
ui/abc_layout_table.c | 37 +++++-----
ui/abc_render_table.c | 20 +++---
10 files changed, 281 insertions(+), 39 deletions(-)
create mode 100644 html/abc_css_border.c
diff --git a/examples/table.html b/examples/table.html
index 326065b..5c73bda 100644
--- a/examples/table.html
+++ b/examples/table.html
@@ -2,9 +2,13 @@
diff --git a/html/Makefile b/html/Makefile
index 7e04712..88b0972 100644
--- a/html/Makefile
+++ b/html/Makefile
@@ -4,6 +4,7 @@ CFILES += abc_html.c
CFILES += abc_css.c
CFILES += abc_css_color.c
CFILES += abc_css_position.c
+CFILES += abc_css_border.c
CFILES += abc_io_util.c
CFILES += abc_io_file.c
diff --git a/html/abc_css.c b/html/abc_css.c
index b00f26b..fe9ca42 100644
--- a/html/abc_css.c
+++ b/html/abc_css.c
@@ -56,6 +56,7 @@ static int __css_parse_value(abc_obj_t* css, abc_obj_t* attr)
abc_char_t* c = NULL;
abc_char_t* c2 = NULL;
+ int c0 = ' ';
while (1) {
c = __io_pop_char(&css->io);
@@ -87,8 +88,17 @@ static int __css_parse_value(abc_obj_t* css, abc_obj_t* attr)
if (';' == c->c || '}' == c->c || EOF == c->c)
break;
- else
- scf_string_cat_cstr_len(value, c->utf8, c->len);
+
+ if (' ' == c0) {
+ if (' ' == c->c || '\t' == c->c || '\r' == c->c || '\n' == c->c) {
+ free(c);
+ continue;
+ }
+
+ c0 = c->c;
+ }
+
+ scf_string_cat_cstr_len(value, c->utf8, c->len);
free(c);
c = NULL;
@@ -798,6 +808,37 @@ int abc_css_use(abc_html_t* html, abc_obj_t* obj)
continue;
}
+ } else if (ABC_CSS_COMMA == css->type) {
+ int c;
+ int c0 = ' ';
+ uint8_t* p0 = NULL;
+ uint8_t* p = css->text->data;
+
+ do {
+ c = *p;
+
+ if (!c || ' ' == c || '\t' == c || '\r' == c || '\n' == c || ',' == c) {
+ if ( ' ' == c0 || '\t' == c0 || '\r' == c0 || '\n' == c0 || ',' == c0)
+ goto next;
+
+ if (__html_strncmp(obj->keys[0], p0, (size_t)(p - p0))) {
+ p0 = NULL;
+ goto next;
+ }
+
+ abc_obj_set_css(obj, css);
+ break;
+ } else {
+ if (!p0)
+ p0 = p;
+ }
+next:
+ c0 = c;
+ p++;
+ } while (c);
+
+ continue;
+
} else if (ABC_CSS_LINK == css->type
|| ABC_CSS_VISITED == css->type
|| ABC_CSS_HOVER == css->type
diff --git a/html/abc_css_border.c b/html/abc_css_border.c
new file mode 100644
index 0000000..f2ef57b
--- /dev/null
+++ b/html/abc_css_border.c
@@ -0,0 +1,154 @@
+#include"abc_html.h"
+
+typedef struct css_border_s
+{
+ char** names;
+ int type;
+} css_border_t;
+
+static char* css_solid [] = {"solid", "å®çº¿", NULL};
+static char* css_dotted[] = {"dotted", "ç¹çº¿", NULL};
+static char* css_dashed[] = {"dashed", "è线", NULL};
+
+static css_border_t css_borders[] =
+{
+ {css_solid, ABC_BORDER_SOLID},
+ {css_dotted, ABC_BORDER_DOTTED},
+ {css_dashed, ABC_BORDER_DASHED},
+};
+
+static void __css_border_type(int* type, const char* name, size_t name_len)
+{
+ int i;
+ for (i = 0; i < sizeof(css_borders) / sizeof(css_borders[0]); i++) {
+ css_border_t* b = &css_borders[i];
+
+ int j;
+ for (j = 0; b->names[j]; j++) {
+ if (!__html_strncmp(b->names[j], name, name_len)) {
+ *type = b->type;
+ return;
+ }
+ }
+ }
+}
+
+int abc_css_border(double* r, double* g, double* b, int* width, int* type, abc_obj_t* obj, const uint8_t* str)
+{
+ *r = 0.0;
+ *g = 0.0;
+ *b = 0.0;
+ *width = 1;
+ *type = ABC_BORDER_SOLID;
+
+ const uint8_t* p = str;
+ const uint8_t* unit = NULL;
+
+ double value = 0.0;
+ int dot = 0;
+ int percent = 0;
+ int prev = 0;
+ int i = 0;
+ int c = 0;
+
+ do {
+ c = *str;
+
+ if ('.' == c)
+ dot = 10;
+ else if ('%' == c)
+ percent++;
+
+ else if ('#' == c) {
+ if (' ' == prev || '\t' == prev || '\r' == prev || '\n' == prev)
+ p = str;
+
+ } else if ('a' <= c && 'z' >= c) {
+
+ if (' ' == prev || '\t' == prev || '\r' == prev || '\n' == prev)
+ p = str;
+ else if (!unit)
+ unit = str;
+
+ } else if ('0' <= c && '9' >= c) {
+
+ if (dot > 0) {
+ value += (c - '0') / (double)dot;
+ dot *= 10;
+ } else {
+ value *= 10.0;
+ value += c - '0';
+ }
+
+ } else if ('\0' == c || ' ' == c || '\t' == c || '\r' == c || '\n' == c) {
+
+ if (' ' == prev || '\t' == prev || '\r' == prev || '\n' == prev)
+ goto next;
+
+ if (percent) {
+ value *= 0.01;
+
+ if (0 == i)
+ *width = value;
+
+ } else if ('a' <= *p && *p <= 'z') {
+ if (1 == i)
+ __css_border_type(type, p, (size_t)(str - p));
+ else if (i > 1)
+ abc_css_color(r, g, b, p);
+
+ } else if ('#' == *p) {
+ if (i > 1)
+ abc_css_color(r, g, b, p);
+
+ } else if (unit) {
+ // for other css units, ignore
+
+ if (0 == i)
+ *width = value;
+ }
+
+ p = str;
+ unit = NULL;
+ value = 0.0;
+ dot = 0;
+ percent = 0;
+ i++;
+
+ if (i > 2)
+ break;
+ }
+
+next:
+ prev = c;
+ str++;
+ } while (c);
+
+ return 0;
+}
+
+int abc_css_margin(abc_obj_t* obj)
+{
+ int type = ABC_BORDER_SOLID;
+ int margin = 2;
+ int border = 0;
+ int padding = 2;
+
+ double r = 0.0;
+ double g = 0.0;
+ double b = 0.0;
+
+ abc_obj_t* attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_MARGIN);
+ if (attr)
+ margin = atoi(attr->value->data);
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BORDER);
+ if (attr)
+ abc_css_border(&r, &g, &b, &border, &type, obj, attr->value->data);
+
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_PADDING);
+ if (attr)
+ padding = atoi(attr->value->data);
+
+ return margin + border + padding;
+}
diff --git a/html/abc_html.c b/html/abc_html.c
index c33a917..1fc771a 100644
--- a/html/abc_html.c
+++ b/html/abc_html.c
@@ -32,6 +32,8 @@ static char* list_style_type_keys[] = {"list-style-type", "å表æ è®°",
static char* list_style_image_keys[] = {"list-style-image", "å表æ è®°å¾ç", NULL};
static char* list_style_pos_keys[] = {"list-style-position", "å表æ è®°ä½ç½®", NULL};
+static char* border_collapse_keys[] = {"border-collapse", "è¾¹æ¡æå ", NULL};
+
static char* class_keys[] = {"class", "ç±»å", NULL};
static char* type_keys[] = {"type", "ç±»å", NULL};
static char* name_keys[] = {"name", "åå", NULL};
@@ -255,6 +257,10 @@ static html_attr_t h6_attrs[] =
static html_attr_t p_attrs[] =
{
+ {margin_keys, "", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
+ {border_keys, "", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
+ {padding_keys, "", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+
{class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW},
{style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW},
{id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW},
@@ -273,6 +279,10 @@ static html_attr_t p_attrs[] =
static html_attr_t css_id_attrs[] =
{
+ {margin_keys, "2", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
+ {border_keys, "1", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
+ {padding_keys, "4", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+
{font_keys, "SimSong", ABC_HTML_ATTR_FONT, 0},
{font_size_keys, "16", ABC_HTML_ATTR_FONT_SIZE, 0},
{font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW},
@@ -280,8 +290,6 @@ static html_attr_t css_id_attrs[] =
{bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW},
- {border_keys, "", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
-
{text_align_keys, "left", ABC_HTML_ATTR_TEXT_ALIGN, ABC_HTML_FLAG_SHOW},
{text_decoration_keys, "", ABC_HTML_ATTR_TEXT_DECORATION, ABC_HTML_FLAG_SHOW},
{text_transform_keys, "", ABC_HTML_ATTR_TEXT_TRANSFORM, ABC_HTML_FLAG_SHOW},
@@ -352,13 +360,21 @@ static html_attr_t link_attrs[] =
static html_attr_t img_attrs[] =
{
- {src_keys, "", ABC_HTML_ATTR_SRC, ABC_HTML_FLAG_SHOW},
- {width_keys, "100", ABC_HTML_ATTR_WIDTH, ABC_HTML_FLAG_SHOW},
- {height_keys, "100", ABC_HTML_ATTR_HEIGHT, ABC_HTML_FLAG_SHOW},
+ {margin_keys, "", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
+ {border_keys, "", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
+ {padding_keys, "", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+
+ {src_keys, "", ABC_HTML_ATTR_SRC, ABC_HTML_FLAG_SHOW},
+ {width_keys, "100", ABC_HTML_ATTR_WIDTH, ABC_HTML_FLAG_SHOW},
+ {height_keys, "100", ABC_HTML_ATTR_HEIGHT, ABC_HTML_FLAG_SHOW},
};
static html_attr_t video_attrs[] =
{
+ {margin_keys, "", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
+ {border_keys, "", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
+ {padding_keys, "", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+
{width_keys, "100", ABC_HTML_ATTR_WIDTH, ABC_HTML_FLAG_SHOW},
{height_keys, "100", ABC_HTML_ATTR_HEIGHT, ABC_HTML_FLAG_SHOW},
{control_keys, "", ABC_HTML_ATTR_CONTROLS, 0},
@@ -424,6 +440,10 @@ static html_attr_t ol_attrs[] =
static html_attr_t table_attrs[] =
{
+ {margin_keys, "2", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
+ {border_keys, "1", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
+ {padding_keys, "4", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+
{class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW},
{style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW},
{id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW},
@@ -434,18 +454,20 @@ static html_attr_t table_attrs[] =
{bg_color_keys, "", ABC_HTML_ATTR_BG_COLOR, ABC_HTML_FLAG_SHOW},
- {margin_keys, "2", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
- {border_keys, "1", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
- {padding_keys, "4", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+ {border_collapse_keys, "", ABC_CSS_BORDER_COLLAPSE, ABC_HTML_FLAG_SHOW},
};
static html_attr_t th_attrs[] =
{
+ {margin_keys, "2", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
+ {border_keys, "1", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
+ {padding_keys, "4", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+
{class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW},
{style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW},
{id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW},
{font_keys, "SimHei", ABC_HTML_ATTR_FONT, 0},
- {font_size_keys, "16", ABC_HTML_ATTR_FONT_SIZE, 0},
+ {font_size_keys, "18", ABC_HTML_ATTR_FONT_SIZE, 0},
{font_color_keys, "black", ABC_HTML_ATTR_FONT_COLOR, ABC_HTML_FLAG_SHOW},
{font_style_keys, "", ABC_HTML_ATTR_FONT_STYLE, 0},
@@ -454,6 +476,10 @@ static html_attr_t th_attrs[] =
static html_attr_t td_attrs[] =
{
+ {margin_keys, "2", ABC_HTML_ATTR_MARGIN, ABC_HTML_FLAG_SHOW},
+ {border_keys, "1", ABC_HTML_ATTR_BORDER, ABC_HTML_FLAG_SHOW},
+ {padding_keys, "4", ABC_HTML_ATTR_PADDING, ABC_HTML_FLAG_SHOW},
+
{class_keys, "", ABC_HTML_ATTR_CLASS, ABC_HTML_FLAG_SHOW},
{style_keys, "", ABC_HTML_ATTR_STYLE, ABC_HTML_FLAG_SHOW},
{id_keys, "", ABC_HTML_ATTR_ID, ABC_HTML_FLAG_SHOW},
diff --git a/html/abc_html.h b/html/abc_html.h
index 4f59ebe..2058468 100644
--- a/html/abc_html.h
+++ b/html/abc_html.h
@@ -57,4 +57,7 @@ int abc_css_use (abc_html_t* html, abc_obj_t* obj);
int abc_css_color (double* r, double* g, double* b, const uint8_t* str);
int abc_css_position(float* x, float* y, float w, float h, abc_obj_t* obj, const uint8_t* str);
+int abc_css_border(double* r, double* g, double* b, int* width, int* type, abc_obj_t* obj, const uint8_t* str);
+int abc_css_margin(abc_obj_t* obj);
+
#endif
diff --git a/html/abc_obj.h b/html/abc_obj.h
index f157ec8..816fa7b 100644
--- a/html/abc_obj.h
+++ b/html/abc_obj.h
@@ -131,6 +131,8 @@ enum abc_objs
ABC_CSS_LIST_STYLE_IMAGE,
ABC_CSS_LIST_STYLE_POSITION,
+ ABC_CSS_BORDER_COLLAPSE,
+
ABC_CSS_COMMA,
// ... new css add here
@@ -140,6 +142,13 @@ enum abc_objs
ABC_CSS_CLASS = ABC_HTML_ATTR_CLASS,
};
+enum abc_border_style
+{
+ ABC_BORDER_SOLID,
+ ABC_BORDER_DOTTED,
+ ABC_BORDER_DASHED,
+};
+
struct abc_obj_s
{
scf_list_t list;
diff --git a/ui/Makefile b/ui/Makefile
index 7962f38..7ca2bea 100644
--- a/ui/Makefile
+++ b/ui/Makefile
@@ -49,6 +49,7 @@ CFILES += ../html/abc_obj.c
CFILES += ../html/abc_css.c
CFILES += ../html/abc_css_color.c
CFILES += ../html/abc_css_position.c
+CFILES += ../html/abc_css_border.c
CFILES += ../html/abc_io_util.c
CFILES += ../html/abc_io_file.c
diff --git a/ui/abc_layout_table.c b/ui/abc_layout_table.c
index 41da221..8c4124d 100644
--- a/ui/abc_layout_table.c
+++ b/ui/abc_layout_table.c
@@ -8,36 +8,37 @@ int abc_layout_table(abc_layout_t* layout, abc_obj_t* obj, int width, int height
abc_obj_t* td;
abc_obj_t* attr;
- int margin = 0;
- int border = 1;
- int padding = 4;
+ int collapse = 0;
- attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_MARGIN);
- if (attr)
- margin = atoi(attr->value->data);
-
- attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BORDER);
- if (attr)
- border = atoi(attr->value->data);
-
- attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_PADDING);
- if (attr)
- padding = atoi(attr->value->data);
+ attr = abc_obj_find_attr(obj, ABC_CSS_BORDER_COLLAPSE);
+ if (attr) {
+ if (!__html_strcmp(attr->value->data, "collapse")) {
+ collapse = 1;
+ abc_obj_set_attr(obj, ABC_HTML_ATTR_PADDING, "0", 1);
+ }
+ }
- int d = margin + border + padding;
+ int d = abc_css_margin(obj);
int x = obj->x + d;
int y = obj->y + d;
for (l = scf_list_head(&obj->childs); l != scf_list_sentinel(&obj->childs); l = scf_list_next(l)) {
tr = scf_list_data(l, abc_obj_t, list);
+ int d2 = d;
+
for (l2 = scf_list_head(&tr->childs); l2 != scf_list_sentinel(&tr->childs); l2 = scf_list_next(l2)) {
td = scf_list_data(l2, abc_obj_t, list);
+ if (collapse)
+ abc_obj_set_attr(td, ABC_HTML_ATTR_MARGIN, "0", 1);
+
+ d2 = abc_css_margin(td);
+
td->x = x;
td->y = y;
- td->w = obj->td_width + d * 2;
- td->h = obj->td_height + d * 2;
+ td->w = obj->td_width + d2 * 2;
+ td->h = obj->td_height + d2 * 2;
x += td->w;
}
@@ -45,7 +46,7 @@ int abc_layout_table(abc_layout_t* layout, abc_obj_t* obj, int width, int height
obj->w = x + d - obj->x;
x = obj->x + d;
- y += obj->td_height + d * 2;
+ y += obj->td_height + d2 * 2;
}
obj->h = y + d - obj->y;
diff --git a/ui/abc_render_table.c b/ui/abc_render_table.c
index 295ddf0..732d3f7 100644
--- a/ui/abc_render_table.c
+++ b/ui/abc_render_table.c
@@ -63,8 +63,9 @@ static int _render_draw_table(abc_render_t* render, abc_obj_t* obj, int width, i
if (0 == vao)
__init_buffers(&vao, buffers);
- double margin = 0.0;
- double border = 1.0;
+ int margin = 0;
+ int border = 1;
+ int border_type = ABC_BORDER_SOLID;
double r0 = 0.0;
double g0 = 0.0;
@@ -74,21 +75,22 @@ static int _render_draw_table(abc_render_t* render, abc_obj_t* obj, int width, i
double g1 = 0.0;
double b1 = 0.0;
- abc_obj_t* attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_COLOR);
- if (attr)
- abc_css_color(&r0, &g0, &b0, attr->value->data);
-
- attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BG_COLOR);
+ abc_obj_t* attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BG_COLOR);
if (attr)
abc_css_color(&r1, &g1, &b1, attr->value->data);
attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_MARGIN);
if (attr)
- margin = atof(attr->value->data);
+ margin = atoi(attr->value->data);
attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BORDER);
if (attr)
- border = atof(attr->value->data);
+ abc_css_border(&r0, &g0, &b0, &border, &border_type, obj, attr->value->data);
+ else {
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_COLOR);
+ if (attr)
+ abc_css_color(&r0, &g0, &b0, attr->value->data);
+ }
float mvp[16];
__compute_mvp(mvp, 0, 0, 0);
--
2.25.1