+#include"abc.h"
+
+static const char* vert_shader =
+ "#version 330 core\n"
+ "layout(location = 0) in vec4 position; \n"
+ "layout(location = 1) in vec2 a_texCoord; \n"
+ "out vec2 v_texCoord; \n"
+ "uniform mat4 mvp; \n"
+ "void main() { \n"
+ "gl_Position = mvp * position; \n"
+ "v_texCoord = a_texCoord; \n"
+ "} \n";
+
+static const char* frag_shader =
+ "#version 330 core\n"
+ "in vec2 v_texCoord; \n"
+ "out vec4 outputColor; \n"
+ "uniform vec4 rect; \n"
+ "uniform sampler2D tex_rgba; \n"
+ "uniform sampler2D tex_img; \n"
+ "void main() { \n"
+ " vec2 xy = v_texCoord; \n"
+ " if (xy.x > rect.x && xy.x < rect.x + rect.z \n"
+ " && xy.y > rect.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"
+ " vec4 v = texture2D(tex_img, 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"
+ " } \n"
+ "} \n";
+
+
+static GLuint program = 0;
+
+static GLuint vao = 0;
+static GLuint buffers[2] = {0};
+static GLuint texture_rgba = 0;
+static GLuint texture_img = 0;
+
+static GLuint uniform_mvp;
+static GLuint uniform_rgba;
+static GLuint uniform_img;
+static GLuint uniform_rect;
+
+static int _render_fini_li(abc_render_t* render)
+{
+ return 0;
+}
+
+static int _render_draw_li(abc_render_t* render, abc_obj_t* obj, int width, int height)
+{
+ abc_obj_t* attr;
+ cairo_surface_t* surface;
+ cairo_t* cr;
+
+ uint8_t* bgra = calloc(1, obj->w * obj->h * 4);
+ if (!bgra)
+ return -ENOMEM;
+
+ double r = 0.0;
+ double g = 0.0;
+ double b = 0.0;
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_BG_COLOR);
+ if (attr)
+ abc_css_color(&r, &g, &b, attr->value->data);
+
+ surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4);
+ cr = cairo_create(surface);
+
+ cairo_set_line_width(cr, 1);
+ cairo_set_source_rgb(cr, r, g, b);
+ cairo_rectangle(cr, 0, 0, obj->w, obj->h);
+ cairo_fill(cr);
+ cairo_stroke(cr);
+
+ if (obj->text)
+ __init_text(cr, obj, 16);
+
+ if (ABC_HTML_UL == obj->parent->type) {
+ r = 0.0;
+ g = 0.0;
+ b = 0.0;
+ attr = abc_obj_find_attr(obj, ABC_HTML_ATTR_FONT_COLOR);
+ if (attr)
+ abc_css_color(&r, &g, &b, attr->value->data);
+
+ cairo_set_source_rgb(cr, r, g, b);
+
+ attr = abc_obj_find_attr(obj, ABC_CSS_LIST_STYLE_TYPE);
+ if (attr) {
+ if (!strcmp(attr->value->data, "circle"))
+ cairo_arc (cr, 8, 8, 3, 0, 2 * M_PI);
+
+ else if (!strcmp(attr->value->data, "square")) {
+ cairo_rectangle(cr, 5, 5, 6, 6);
+ cairo_fill(cr);
+
+ } else if (!strcmp(attr->value->data, "disc")) {
+ cairo_arc (cr, 8, 8, 3, 0, 2 * M_PI);
+ cairo_fill(cr);
+ }
+ } else {
+ cairo_arc (cr, 8, 8, 3, 0, 2 * M_PI);
+ cairo_fill(cr);
+ }
+
+ cairo_stroke(cr);
+ }
+// cairo_surface_write_to_png(surface, "tmp.png");
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+ surface = NULL;
+ cr = NULL;
+
+ abc_img_t* img = NULL;
+ uint8_t* bgra1 = NULL;
+
+ GLfloat x = 0.0;
+ GLfloat y = 0.0;
+ GLfloat w = 0.0;
+ GLfloat h = 0.0;
+
+ attr = abc_obj_find_attr(obj, ABC_CSS_LIST_STYLE_IMAGE);
+
+ if (attr && attr->value && attr->value->len > 0)
+ {
+ scf_string_t* spath = NULL;
+ abc_io_t* io = NULL;
+
+ int ret = __io_url_css(&io, &spath, obj->file->data, attr->value->data);
+ if (ret < 0) {
+ free(bgra);
+ return ret;
+ }
+
+ scf_logd("list-style-image: %s\n", spath->data);
+
+ ret = abc_img_open(&img, spath->data);
+
+ scf_string_free(spath);
+ spath = NULL;
+ if (ret < 0) {
+ free(bgra);
+ return ret;
+ }
+
+ bgra1 = calloc(1, img->width * img->height * 4);
+ if (!bgra1) {
+ abc_img_close(img);
+ free(bgra);
+ return -ENOMEM;
+ }
+
+ ret = abc_img_read(img, bgra1, img->width * img->height * 4);
+ if (ret < 0) {
+ abc_img_close(img);
+ free(bgra1);
+ free(bgra);
+ return ret;
+ }
+
+ x = obj->h * 0.333 / (float)obj->w;
+ y = 0.333;
+ w = x;
+ h = y;
+
+ if (0 == texture_img)
+ __init_texture(&texture_img, GL_RGBA, img->width, img->height, NULL);
+ }
+
+ if (0 == program)
+ __init_program(&program, vert_shader, frag_shader);
+
+ if (0 == vao)
+ __init_buffers(&vao, buffers);
+
+ if (0 == texture_rgba)
+ __init_texture(&texture_rgba, GL_RGBA, obj->w, obj->h, NULL);
+
+ float mvp[16];
+ __compute_mvp(mvp, 0, 0, 0);
+
+ scf_logd("%s, x: %d, y: %d, w: %d, h: %d\n", obj->text->data, obj->x, obj->y, obj->w, obj->h);
+
+ GLfloat vert_update[] =
+ {
+ 2.0 * obj->x / (float)width - 1.0,
+ -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+ 2.0 * (obj->x + obj->w) / (float)width - 1.0,
+ -2.0 * (obj->y + obj->h) / (float)height + 1.0,
+
+ 2.0 * obj->x / (float)width - 1.0,
+ -2.0 * obj->y / (float)height + 1.0,
+
+ 2.0 * (obj->x + obj->w) / (float)width - 1.0,
+ -2.0 * obj->y / (float)height + 1.0,
+ };
+
+ glUseProgram(program);
+
+ uniform_mvp = glGetUniformLocation(program, "mvp");
+ uniform_rgba = glGetUniformLocation(program, "tex_rgba");
+ uniform_img = glGetUniformLocation(program, "tex_img");
+ uniform_rect = glGetUniformLocation(program, "rect");
+
+ glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture (GL_TEXTURE_2D, texture_rgba);
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra);
+ glUniform1i(uniform_rgba, 0);
+
+ if (img) {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture (GL_TEXTURE_2D, texture_img);
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra1);
+ glUniform1i(uniform_img, 1);
+ }
+
+ glUniform4f(uniform_rect, x, y, w, h);
+
+ // draw
+ glBindBuffer (GL_ARRAY_BUFFER, buffers[0]);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update);
+
+ glBindVertexArray(vao);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glBindVertexArray(0);
+ glUseProgram(0);
+
+ abc_img_close(img);
+ free(bgra);
+ return 0;
+}
+
+abc_render_t abc_render_li =
+{
+ .type = ABC_HTML_LI,
+
+ .draw = _render_draw_li,
+ .fini = _render_fini_li,
+};