css: text-align & vertical-align ok for <table>, <th>, <td> master
authoryu.dongliang <18588496441@163.com>
Mon, 27 Apr 2026 10:53:38 +0000 (18:53 +0800)
committeryu.dongliang <18588496441@163.com>
Mon, 27 Apr 2026 10:53:38 +0000 (18:53 +0800)
examples/table.html
html/Makefile
html/abc_css_length.c [new file with mode: 0644]
html/abc_html.c
html/abc_html.h
html/abc_obj.h
ui/Makefile
ui/abc_layout_table.c
ui/abc_render_td.c

index 5c73bda6238871c8b6f2e6925330ee66932ed782..15b3ba14416b0cfda9de55f100f65fce7475390b 100644 (file)
@@ -2,13 +2,28 @@
 <html>
 <head>
 <style>
 <html>
 <head>
 <style>
+table,th,td
+{
+       border:1px solid red;
+}
+
 table
 {
 table
 {
-       border-collapse: collapse;
+       width:100%;
+/*     border-collapse:collapse;*/
 }
 }
-table,th,td
+
+th
 {
 {
-       border:1px solid red;
+       background-color:green;
+       color:white;
+}
+
+td
+{
+       height:50px;
+       text-align:center;
+       vertical-align:center;
 }
 </style>
 </head>
 }
 </style>
 </head>
index 88b09729347d8ee128d91e5cf78b90bae924a6dc..276d45830942d894cdeb66e248818674e1df5c26 100644 (file)
@@ -5,6 +5,7 @@ CFILES += abc_css.c
 CFILES += abc_css_color.c
 CFILES += abc_css_position.c
 CFILES += abc_css_border.c
 CFILES += abc_css_color.c
 CFILES += abc_css_position.c
 CFILES += abc_css_border.c
+CFILES += abc_css_length.c
 
 CFILES += abc_io_util.c
 CFILES += abc_io_file.c
 
 CFILES += abc_io_util.c
 CFILES += abc_io_file.c
diff --git a/html/abc_css_length.c b/html/abc_css_length.c
new file mode 100644 (file)
index 0000000..f51c989
--- /dev/null
@@ -0,0 +1,62 @@
+#include"abc_html.h"
+
+int abc_css_length(abc_obj_t* obj, const uint8_t* str, int len)
+{
+       const uint8_t* p    = str;
+       const uint8_t* unit = NULL;
+
+       int     x       = 0;
+       double  value   = 0.0;
+       int     dot     = 0;
+       int     percent = 0;
+       int     prev    = 0;
+       int     c       = 0;
+
+       do {
+               c = *str;
+
+               if ('.' == c)
+                       dot = 10;
+               else if ('%' == c)
+                       percent++;
+
+               else if ('a' <= c && 'z' >= c) {
+                       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)
+                               x = value * 0.01 * len;
+                       else if (unit) {
+                               // for other css units, ignore
+                               x = value;
+                       }
+
+                       unit    = NULL;
+                       value   = 0.0;
+                       dot     = 0;
+                       percent = 0;
+                       break;
+               }
+
+next:
+               prev = c;
+               str++;
+       } while (c);
+
+       return x;
+}
index 1fc771a1ee16d37214758a55fe21ad278ef4332a..af65462763b39d47b4191f7d42661a0205f14a88 100644 (file)
@@ -21,6 +21,8 @@ static char* text_decoration_keys[]  = {"text-decoration",     "下划线",
 static char* text_transform_keys[]   = {"text-transform",      "大小写",       NULL};
 static char* text_indent_keys[]      = {"text-transform",      "缩进",         NULL};
 
 static char* text_transform_keys[]   = {"text-transform",      "大小写",       NULL};
 static char* text_indent_keys[]      = {"text-transform",      "缩进",         NULL};
 
+static char* vertical_align_keys[]   = {"vertical-align",      "垂直对齐",     NULL};
+
 static char* bg_keys[]               = {"background",          "背景",         NULL};
 static char* bg_color_keys[]         = {"background-color",    "背景颜色",     NULL};
 static char* bg_image_keys[]         = {"background-image",    "背景图片",     NULL};
 static char* bg_keys[]               = {"background",          "背景",         NULL};
 static char* bg_color_keys[]         = {"background-color",    "背景颜色",     NULL};
 static char* bg_image_keys[]         = {"background-image",    "背景图片",     NULL};
@@ -295,6 +297,8 @@ static html_attr_t  css_id_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},
 
        {text_transform_keys,   "",     ABC_HTML_ATTR_TEXT_TRANSFORM,  ABC_HTML_FLAG_SHOW},
        {text_indent_keys,      "",     ABC_HTML_ATTR_TEXT_INDENT,     ABC_HTML_FLAG_SHOW},
 
+       {vertical_align_keys,   "",     ABC_HTML_ATTR_VERTICAL_ALIGN,  ABC_HTML_FLAG_SHOW},
+
        {list_style_keys,       "",     ABC_CSS_LIST_STYLE,            ABC_HTML_FLAG_SHOW},
        {list_style_type_keys,  "",     ABC_CSS_LIST_STYLE_TYPE,       ABC_HTML_FLAG_SHOW},
        {list_style_image_keys, "",     ABC_CSS_LIST_STYLE_IMAGE,      ABC_HTML_FLAG_SHOW},
        {list_style_keys,       "",     ABC_CSS_LIST_STYLE,            ABC_HTML_FLAG_SHOW},
        {list_style_type_keys,  "",     ABC_CSS_LIST_STYLE_TYPE,       ABC_HTML_FLAG_SHOW},
        {list_style_image_keys, "",     ABC_CSS_LIST_STYLE_IMAGE,      ABC_HTML_FLAG_SHOW},
@@ -444,6 +448,9 @@ static html_attr_t  table_attrs[] =
        {border_keys,      "1",        ABC_HTML_ATTR_BORDER,          ABC_HTML_FLAG_SHOW},
        {padding_keys,     "4",        ABC_HTML_ATTR_PADDING,         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},
 
+       {width_keys,       "",         ABC_HTML_ATTR_WIDTH,           ABC_HTML_FLAG_SHOW},
+       {height_keys,      "",         ABC_HTML_ATTR_HEIGHT,          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},
        {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},
@@ -463,6 +470,9 @@ static html_attr_t  th_attrs[] =
        {border_keys,      "1",        ABC_HTML_ATTR_BORDER,          ABC_HTML_FLAG_SHOW},
        {padding_keys,     "4",        ABC_HTML_ATTR_PADDING,         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},
 
+       {width_keys,       "",         ABC_HTML_ATTR_WIDTH,           ABC_HTML_FLAG_SHOW},
+       {height_keys,      "",         ABC_HTML_ATTR_HEIGHT,          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},
        {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},
@@ -472,6 +482,9 @@ static html_attr_t  th_attrs[] =
        {font_style_keys,  "",         ABC_HTML_ATTR_FONT_STYLE,      0},
 
        {bg_color_keys,    "",         ABC_HTML_ATTR_BG_COLOR,        ABC_HTML_FLAG_SHOW},
        {font_style_keys,  "",         ABC_HTML_ATTR_FONT_STYLE,      0},
 
        {bg_color_keys,    "",         ABC_HTML_ATTR_BG_COLOR,        ABC_HTML_FLAG_SHOW},
+
+       {text_align_keys,      "",     ABC_HTML_ATTR_TEXT_ALIGN,      ABC_HTML_FLAG_SHOW},
+       {vertical_align_keys,  "",     ABC_HTML_ATTR_VERTICAL_ALIGN,  ABC_HTML_FLAG_SHOW},
 };
 
 static html_attr_t  td_attrs[] =
 };
 
 static html_attr_t  td_attrs[] =
@@ -480,6 +493,9 @@ static html_attr_t  td_attrs[] =
        {border_keys,      "1",        ABC_HTML_ATTR_BORDER,          ABC_HTML_FLAG_SHOW},
        {padding_keys,     "4",        ABC_HTML_ATTR_PADDING,         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},
 
+       {width_keys,       "",         ABC_HTML_ATTR_WIDTH,           ABC_HTML_FLAG_SHOW},
+       {height_keys,      "",         ABC_HTML_ATTR_HEIGHT,          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},
        {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},
@@ -489,6 +505,9 @@ static html_attr_t  td_attrs[] =
        {font_style_keys,  "",         ABC_HTML_ATTR_FONT_STYLE,      0},
 
        {bg_color_keys,    "",         ABC_HTML_ATTR_BG_COLOR,        ABC_HTML_FLAG_SHOW},
        {font_style_keys,  "",         ABC_HTML_ATTR_FONT_STYLE,      0},
 
        {bg_color_keys,    "",         ABC_HTML_ATTR_BG_COLOR,        ABC_HTML_FLAG_SHOW},
+
+       {text_align_keys,      "",     ABC_HTML_ATTR_TEXT_ALIGN,      ABC_HTML_FLAG_SHOW},
+       {vertical_align_keys,  "",     ABC_HTML_ATTR_VERTICAL_ALIGN,  ABC_HTML_FLAG_SHOW},
 };
 
 static html_attr_t  script_attrs[] =
 };
 
 static html_attr_t  script_attrs[] =
index 2058468122eb4dca814e9ee66ab2959d3d4de0cf..8d5ea2329bb3280d0587f8c240c8af995d105614 100644 (file)
@@ -59,5 +59,6 @@ int  abc_css_position(float*  x, float*  y, float   w, float h, abc_obj_t* obj,
 
 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);
 
 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);
+int  abc_css_length(abc_obj_t* obj, const uint8_t* str, int len);
 
 #endif
 
 #endif
index 816fa7b64252b3c8076fe78f9951ca12e21c895c..ee84845be70e4871ae03eb30c33ae39319591a86 100644 (file)
@@ -95,6 +95,8 @@ enum abc_objs
        ABC_HTML_ATTR_TEXT_TRANSFORM,
        ABC_HTML_ATTR_TEXT_INDENT,
 
        ABC_HTML_ATTR_TEXT_TRANSFORM,
        ABC_HTML_ATTR_TEXT_INDENT,
 
+       ABC_HTML_ATTR_VERTICAL_ALIGN,
+
        ABC_HTML_ATTR_BG,
        ABC_HTML_ATTR_BG_COLOR,
        ABC_HTML_ATTR_BG_IMAGE,
        ABC_HTML_ATTR_BG,
        ABC_HTML_ATTR_BG_COLOR,
        ABC_HTML_ATTR_BG_IMAGE,
index 7ca2beada88c5ab578bb7a7b38f3f5eee1b9dc7a..91bc65ccd3b33df01516d0ef69f0773505918a33 100644 (file)
@@ -50,6 +50,7 @@ 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_css_color.c
 CFILES += ../html/abc_css_position.c
 CFILES += ../html/abc_css_border.c
+CFILES += ../html/abc_css_length.c
 
 CFILES += ../html/abc_io_util.c
 CFILES += ../html/abc_io_file.c
 
 CFILES += ../html/abc_io_util.c
 CFILES += ../html/abc_io_file.c
index 8c4124d1da05186a286f928a7fd5a91707161225..b877475b21433d1f08701a2dbcbf4d03d0a32452 100644 (file)
@@ -18,13 +18,42 @@ int abc_layout_table(abc_layout_t* layout, abc_obj_t* obj, int width, int height
                }
        }
 
                }
        }
 
-       int d = abc_css_margin(obj);
+       int w_set = 0;
+       int h_set = 0;
+       int d     = abc_css_margin(obj);
+
+       attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_WIDTH);
+       if (attr && attr->value && attr->value->len > 0)
+       {
+               obj->w  = abc_css_length(obj, attr->value->data, width);
+               obj->w += d * 2;
+
+               if (obj->w > width - obj->x)
+                       obj->w = width - obj->x;
+
+               w_set = 1;
+       }
+
+       attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_HEIGHT);
+       if (attr && attr->value && attr->value->len > 0)
+       {
+               obj->h  = abc_css_length(obj, attr->value->data, height);
+               obj->h += d * 2;
+
+               if (obj->h > height - obj->y)
+                       obj->h = height - obj->y;
+
+               h_set = 1;
+       }
+
        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 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 w  = obj->td_width;
+               int h  = obj->td_height;
                int d2 = d;
 
                for (l2 = scf_list_head(&tr->childs); l2 != scf_list_sentinel(&tr->childs); l2 = scf_list_next(l2)) {
                int d2 = d;
 
                for (l2 = scf_list_head(&tr->childs); l2 != scf_list_sentinel(&tr->childs); l2 = scf_list_next(l2)) {
@@ -35,18 +64,39 @@ int abc_layout_table(abc_layout_t* layout, abc_obj_t* obj, int width, int height
 
                        d2 = abc_css_margin(td);
 
 
                        d2 = abc_css_margin(td);
 
+                       if (w_set) {
+                               w_set = 0;
+                               obj->td_width = (obj->w - d * 2) / tr->n_childs - d2 * 2;
+                       }
+
+                       if (h_set) {
+                               h_set = 0;
+                               obj->td_height = (obj->h - d * 2) / obj->n_childs - d2 * 2;
+                       }
+
+                       w = obj->td_width;
+                       h = obj->td_height;
+
+                       attr = abc_obj_get_attr(td, ABC_HTML_ATTR_WIDTH);
+                       if (attr && attr->value && attr->value->len > 0)
+                               w = abc_css_length(td, attr->value->data, obj->w);
+
+                       attr = abc_obj_get_attr(td, ABC_HTML_ATTR_HEIGHT);
+                       if (attr && attr->value && attr->value->len > 0)
+                               h = abc_css_length(td, attr->value->data, obj->h);
+
                        td->x = x;
                        td->y = y;
                        td->x = x;
                        td->y = y;
-                       td->w = obj->td_width  + d2 * 2;
-                       td->h = obj->td_height + d2 * 2;
+                       td->w = w + d2 * 2;
+                       td->h = h + d2 * 2;
 
                        x += td->w;
                }
 
                obj->w = x + d - obj->x;
 
 
                        x += td->w;
                }
 
                obj->w = x + d - obj->x;
 
-               x  = obj->x         + d;
-               y += obj->td_height + d2 * 2;
+               x  = obj->x + d;
+               y += h + d2 * 2;
        }
 
        obj->h = y + d - obj->y;
        }
 
        obj->h = y + d - obj->y;
index 08670eeb8efaebcfa02c0bee3d94646fe89ce137..558e87e90f29111c5d3b9a66cdb351cca4c1f78b 100644 (file)
@@ -123,9 +123,30 @@ static int _render_draw_td(abc_render_t* render, abc_obj_t* obj, int width, int
        if (attr)
                cairo_set_font_size(cr, atoi(attr->value->data));
 
        if (attr)
                cairo_set_font_size(cr, atoi(attr->value->data));
 
-       cairo_text_extents(cr, obj->text->data,   &extents);
-       cairo_move_to     (cr, extents.x_bearing, -extents.y_bearing);
-       cairo_show_text   (cr, obj->text->data);
+       cairo_text_extents(cr, obj->text->data, &extents);
+       double x_bearing =  extents.x_bearing;
+       double y_bearing = -extents.y_bearing;
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_TEXT_ALIGN);
+       if (attr) {
+               if (!__html_strcmp(attr->value->data, "right"))
+                       x_bearing = w - extents.width - x_bearing;
+
+               else if (!__html_strcmp(attr->value->data, "center"))
+                       x_bearing = (w - extents.width) / 2 - x_bearing;
+       }
+
+       attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_VERTICAL_ALIGN);
+       if (attr) {
+               if (!__html_strcmp(attr->value->data, "bottom"))
+                       y_bearing += h - extents.height;
+
+               else if (!__html_strcmp(attr->value->data, "center"))
+                       y_bearing += (h - extents.height) / 2;
+       }
+
+       cairo_move_to  (cr, x_bearing, y_bearing);
+       cairo_show_text(cr, obj->text->data);
 
 //     cairo_surface_write_to_png(surface, "tmp.png");
 
 
 //     cairo_surface_write_to_png(surface, "tmp.png");