css: background-image with repeat status master
authoryu.dongliang <18588496441@163.com>
Fri, 10 Apr 2026 13:04:03 +0000 (21:04 +0800)
committeryu.dongliang <18588496441@163.com>
Fri, 10 Apr 2026 13:04:03 +0000 (21:04 +0800)
examples/style.css
html/Makefile
html/abc_css_position.c [new file with mode: 0644]
html/abc_html.c
html/abc_html.h
html/abc_obj.h
ui/Makefile
ui/abc_render_bg_image.c

index 16354c1b7868b730de5e9763064584ee41ed4e4b..ae78f896b47eb09b97f23e5473415dee13c9bcc4 100644 (file)
@@ -2,6 +2,8 @@ body
 {
        background-color:#b0c4de;
        background-image:url('img.png');
 {
        background-color:#b0c4de;
        background-image:url('img.png');
+       background-position:right top;
+       background-repeat:no-repeat;
 }
 h1 {background-color:#6495ed;}
 
 }
 h1 {background-color:#6495ed;}
 
index 51ddf3ea9e0036f976ce2ee50aca962be5367852..7e047129abd6078a4c91855522a36f8a0fe8efcf 100644 (file)
@@ -3,6 +3,7 @@ CFILES += abc_obj.c
 CFILES += abc_html.c
 CFILES += abc_css.c
 CFILES += abc_css_color.c
 CFILES += abc_html.c
 CFILES += abc_css.c
 CFILES += abc_css_color.c
+CFILES += abc_css_position.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_position.c b/html/abc_css_position.c
new file mode 100644 (file)
index 0000000..18e1c54
--- /dev/null
@@ -0,0 +1,119 @@
+#include"abc_html.h"
+
+typedef struct css_pos_s
+{
+       char**  names;
+       float   value;
+} css_pos_t;
+
+static char* css_left[]   = {"left",   "左", NULL};
+static char* css_right[]  = {"right",  "右", NULL};
+static char* css_top[]    = {"top",    "上", NULL};
+static char* css_bottom[] = {"bottom", "下", NULL};
+
+static css_pos_t  css_poss[] =
+{
+       {css_left,   0.0},
+       {css_right,  1.0},
+       {css_top,    0.0},
+       {css_bottom, 1.0},
+};
+
+static void __css_pos_value(float* value, const char* name, size_t name_len)
+{
+       int i;
+       for (i = 0; i < sizeof(css_poss) / sizeof(css_poss[0]); i++) {
+               css_pos_t* c = &css_poss[i];
+
+               int j;
+               for (j = 0; c->names[j]; j++) {
+                       if (!strncmp(c->names[j], name, name_len)) {
+                               *value = c->value;
+                               return;
+                       }
+               }
+       }
+}
+
+int abc_css_position(float* x, float* y, float w, float h, abc_obj_t* obj, const uint8_t* str)
+{
+       *x = 0.5 - w / 2;
+       *y = 0.5 - h / 2;
+
+       const uint8_t* p    = str;
+       const uint8_t* unit = NULL;
+
+       double  value   = 0.0;
+       int     dot     = 0;
+       int     percent = 0;
+       int     prev    = 0;
+       int     n       = 0;
+       int     c       = 0;
+
+       do {
+               c = *str;
+
+               if ('.' == c)
+                       dot = 10;
+               else if ('%' == c)
+                       percent++;
+
+               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 (c) {
+                               if (' ' == prev || '\t' == prev || '\r' == prev || '\n' == prev) {
+                                       prev = c;
+                                       str++;
+                                       continue;
+                               }
+                       }
+
+                       if (percent) {
+                               value *= 0.01;
+
+                               if (n > 0)
+                                       *y = value;
+                               else
+                                       *x = value;
+
+                       } else if ('a' <= *p && *p <= 'z') {
+                               if (n > 0)
+                                       __css_pos_value(y, p, (size_t)(str - p));
+                               else
+                                       __css_pos_value(x, p, (size_t)(str - p));
+
+                       } else if (unit) {
+                               // for other css units, ignore
+                       }
+
+                       p       = str;
+                       unit    = NULL;
+                       value   = 0.0;
+                       dot     = 0;
+                       percent = 0;
+                       n++;
+               }
+
+               prev = c;
+               str++;
+       } while (c);
+
+       return 0;
+}
index 5cf717176ffd18616c688789b06111eeb789daf7..855b2c217b37296a7414c2dfc6599b34d4c81127 100644 (file)
@@ -15,10 +15,13 @@ static char* font_color_keys[] = {"font-color", "字体颜色", "color", "颜色
 static char* font_bold_keys[]   = {"bold",      "加粗",     NULL};
 static char* font_italic_keys[] = {"italic",    "斜体",     NULL};
 
 static char* font_bold_keys[]   = {"bold",      "加粗",     NULL};
 static char* font_italic_keys[] = {"italic",    "斜体",     NULL};
 
-static char* text_align_keys[] = {"text-align", "对齐",     NULL};
+static char* text_align_keys[]  = {"text-align", "对齐",     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};
+static char* bg_repeat_keys[]   = {"background-repeat",   "背景重复", NULL};
+static char* bg_position_keys[] = {"background-position", "背景位置", NULL};
 
 static char* class_keys[]      = {"class",      "类名",     NULL};
 static char* type_keys[]       = {"type",       "类型",     NULL};
 
 static char* class_keys[]      = {"class",      "类名",     NULL};
 static char* type_keys[]       = {"type",       "类型",     NULL};
@@ -105,10 +108,14 @@ static html_attr_t  meta_attrs[] =
 
 static html_attr_t  body_attrs[] =
 {
 
 static html_attr_t  body_attrs[] =
 {
-       {font_keys,        "SimSong",    ABC_HTML_ATTR_FONT,       0},
-       {font_size_keys,   "16",         ABC_HTML_ATTR_FONT_SIZE,  0},
-       {bg_color_keys,    "white",      ABC_HTML_ATTR_BG_COLOR,   ABC_HTML_FLAG_SHOW},
-       {bg_image_keys,    "",           ABC_HTML_ATTR_BG_IMAGE,   ABC_HTML_FLAG_SHOW},
+       {font_keys,        "SimSong",    ABC_HTML_ATTR_FONT,        0},
+       {font_size_keys,   "16",         ABC_HTML_ATTR_FONT_SIZE,   0},
+
+       {bg_keys,          "",           ABC_HTML_ATTR_BG,          ABC_HTML_FLAG_SHOW},
+       {bg_color_keys,    "white",      ABC_HTML_ATTR_BG_COLOR,    ABC_HTML_FLAG_SHOW},
+       {bg_image_keys,    "",           ABC_HTML_ATTR_BG_IMAGE,    ABC_HTML_FLAG_SHOW},
+       {bg_repeat_keys,   "",           ABC_HTML_ATTR_BG_REPEAT,   ABC_HTML_FLAG_SHOW},
+       {bg_position_keys, "",           ABC_HTML_ATTR_BG_POSITION, ABC_HTML_FLAG_SHOW},
 };
 
 static html_attr_t  h1_attrs[] =
 };
 
 static html_attr_t  h1_attrs[] =
index 54aa23a72765b1742f8e6118098991d15b0c07b1..dd071ea4d627ab14033cee038a314a5515171980 100644 (file)
@@ -52,6 +52,7 @@ int  abc_html_parse(abc_html_t* html);
 int  abc_css_parse (abc_obj_t*  css);
 int  abc_css_use   (abc_html_t* html, abc_obj_t* obj);
 
 int  abc_css_parse (abc_obj_t*  css);
 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_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);
 
 #endif
 
 #endif
index c114b4a36e0314dfdafd67f152581e973ad840cb..a7a680e1a4edb69ee9134d14e973899801a40d8d 100644 (file)
@@ -88,8 +88,11 @@ enum abc_objs
 
        ABC_HTML_ATTR_TEXT_ALIGN,
 
 
        ABC_HTML_ATTR_TEXT_ALIGN,
 
+       ABC_HTML_ATTR_BG,
        ABC_HTML_ATTR_BG_COLOR,
        ABC_HTML_ATTR_BG_IMAGE,
        ABC_HTML_ATTR_BG_COLOR,
        ABC_HTML_ATTR_BG_IMAGE,
+       ABC_HTML_ATTR_BG_REPEAT,
+       ABC_HTML_ATTR_BG_POSITION,
 
        ABC_HTML_ATTR_WIDTH,
        ABC_HTML_ATTR_HEIGHT,
 
        ABC_HTML_ATTR_WIDTH,
        ABC_HTML_ATTR_HEIGHT,
index 6b097916e881c6c61dcec7cd472d2aa4a528fd97..d154fd43b072955026d57b068830c528fb6cce3f 100644 (file)
@@ -49,6 +49,7 @@ CFILES += ../html/abc_html.c
 CFILES += ../html/abc_obj.c
 CFILES += ../html/abc_css.c
 CFILES += ../html/abc_css_color.c
 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_io_util.c
 CFILES += ../html/abc_io_file.c
 
 CFILES += ../html/abc_io_util.c
 CFILES += ../html/abc_io_file.c
index 4ac866760ccfe3e421b25b45a87a76f4f0077f72..6dd4802924f6b60cc83ce34c4592eb48283ef1f0 100644 (file)
@@ -17,13 +17,20 @@ static const char* frag_shader =
        "out vec4 outputColor; \n"
        "uniform vec4 bgColor; \n"
        "uniform vec4 rect; \n"
        "out vec4 outputColor; \n"
        "uniform vec4 bgColor; \n"
        "uniform vec4 rect; \n"
+       "uniform int repeat_x; \n"
+       "uniform int repeat_y; \n"
+       "uniform int index_x; \n"
+       "uniform int index_y; \n"
        "uniform sampler2D tex_rgba; \n"
        "void main() { \n"
        "    vec2 xy = v_texCoord; \n"
        "uniform sampler2D tex_rgba; \n"
        "void main() { \n"
        "    vec2 xy = v_texCoord; \n"
-       "    if (rect.x < xy.x && xy.x < rect.x + rect.z \n"
-       "     && rect.y < xy.y && xy.y < rect.y + rect.w) { \n"
-       "        xy.x = (xy.x - rect.x) / rect.z; \n"
-       "        xy.y = (xy.y - rect.y) / rect.w; \n"
+       "    float i = floor((xy.x - rect.x) / rect.z); \n"
+       "    float j = floor((xy.y - rect.y) / rect.w); \n"
+       "    if ((repeat_x > 0 || int(round(i)) == index_x) && (repeat_y > 0 || int(round(j)) == index_y)) { \n"
+       "        float x = rect.x + i * rect.z; \n"
+       "        float y = rect.y + j * rect.w; \n"
+       "        xy.x = (xy.x - x) / rect.z; \n"
+       "        xy.y = (xy.y - y) / rect.w; \n"
        "        vec4 v = texture2D(tex_rgba, xy).rgba; \n"
        "        outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
        "    } else { \n"
        "        vec4 v = texture2D(tex_rgba, xy).rgba; \n"
        "        outputColor = vec4(v.b, v.g, v.r, 1.0); \n"
        "    } else { \n"
@@ -42,6 +49,10 @@ static GLuint uniform_mvp;
 static GLuint uniform_rgba;
 static GLuint uniform_rect;
 static GLuint uniform_color;
 static GLuint uniform_rgba;
 static GLuint uniform_rect;
 static GLuint uniform_color;
+static GLuint uniform_repeat_x;
+static GLuint uniform_repeat_y;
+static GLuint uniform_index_x;
+static GLuint uniform_index_y;
 
 static int _render_fini_bg_image(abc_render_t* render)
 {
 
 static int _render_fini_bg_image(abc_render_t* render)
 {
@@ -135,11 +146,50 @@ static int _render_draw_bg_image(abc_render_t* render, abc_obj_t* obj, int width
                h /= max;
        }
 
                h /= max;
        }
 
+       GLint repeat_x = 1;
+       GLint repeat_y = 1;
+       GLint index_x  = 0;
+       GLint index_y  = 0;
+
+       attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_BG_POSITION);
+       if (attr) {
+               abc_css_position(&x, &y, w, h, obj, attr->value->data);
+
+               scf_logi("background-position: %s, x: %f, y: %f, w: %f, h: %f\n", attr->value->data, x, y, w, h);
+
+               if (x + w > 1.0)
+                       index_x = -1;
+
+               if (y + h > 1.0)
+                       index_y = -1;
+       }
+
+       attr = abc_obj_get_attr(obj, ABC_HTML_ATTR_BG_REPEAT);
+       if (attr) {
+               if (!strcmp(attr->value->data, "repeat-x"))
+                       repeat_y = 0;
+
+               else if (!strcmp(attr->value->data, "repeat-y"))
+                       repeat_x = 0;
+
+               else if (!strcmp(attr->value->data, "no-repeat")) {
+                       repeat_x = 0;
+                       repeat_y = 0;
+               }
+       }
+
+       scf_logi("repeat_x: %d, repeat_y: %d, index_x: %d, index_y: %d\n", repeat_x, repeat_y, index_x, index_y);
+
        glUseProgram(program);
        glUseProgram(program);
-       uniform_color = glGetUniformLocation(program, "bgColor");
-       uniform_rgba  = glGetUniformLocation(program, "tex_rgba");
-       uniform_rect  = glGetUniformLocation(program, "rect");
-       uniform_mvp   = glGetUniformLocation(program, "mvp");
+
+       uniform_mvp      = glGetUniformLocation(program, "mvp");
+       uniform_rgba     = glGetUniformLocation(program, "tex_rgba");
+       uniform_rect     = glGetUniformLocation(program, "rect");
+       uniform_color    = glGetUniformLocation(program, "bgColor");
+       uniform_repeat_x = glGetUniformLocation(program, "repeat_x");
+       uniform_repeat_y = glGetUniformLocation(program, "repeat_y");
+       uniform_index_x  = glGetUniformLocation(program, "index_x");
+       uniform_index_y  = glGetUniformLocation(program, "index_y");
 
        glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
 
 
        glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
 
@@ -147,9 +197,15 @@ static int _render_draw_bg_image(abc_render_t* render, abc_obj_t* obj, int width
        glBindTexture  (GL_TEXTURE_2D, texture_rgba);
        glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
        glUniform1i(uniform_rgba,  0);
        glBindTexture  (GL_TEXTURE_2D, texture_rgba);
        glTexImage2D   (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
        glUniform1i(uniform_rgba,  0);
+
        glUniform4f(uniform_rect,  x, y, w, h);
        glUniform4f(uniform_color, r, g, b, 1.0);
 
        glUniform4f(uniform_rect,  x, y, w, h);
        glUniform4f(uniform_color, r, g, b, 1.0);
 
+       glUniform1i(uniform_repeat_x, repeat_x);
+       glUniform1i(uniform_repeat_y, repeat_y);
+       glUniform1i(uniform_index_x,  index_x);
+       glUniform1i(uniform_index_y,  index_y);
+
        // draw
        glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
        // draw
        glBindBuffer   (GL_ARRAY_BUFFER, buffers[0]);
        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);