cedric pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=698135b8e4a59ef08dc0c0e957ef073df2ef5296
commit 698135b8e4a59ef08dc0c0e957ef073df2ef5296 Author: Subhransu Mohanty <sub.moha...@samsung.com> Date: Wed Jun 8 10:26:38 2016 -0700 edje: add svg support to parse and store a svg file as a vector object in .edj. Summary: This is the svg loader which will parse the svg file and store it in a intermediate structure. It provides the helper function to get EET descriptor to save the structure into eet file. NOTE: Not all svg attributes are handled yet. but most common attributes are handled . Reviewers: Hermet, cedric Subscribers: Hermet, cedric, jpeg Differential Revision: https://phab.enlightenment.org/D3868 Signed-off-by: Cedric BAIL <ced...@osg.samsung.com> --- src/Makefile_Edje.am | 3 +- src/bin/edje/edje_cc.h | 3 + src/bin/edje/edje_svg_loader.c | 1472 ++++++++++++++++++++++++++++++++++++++++ src/lib/edje/edje_data.c | 409 +++++++++++ src/lib/edje/edje_private.h | 225 ++++++ 5 files changed, 2111 insertions(+), 1 deletion(-) diff --git a/src/Makefile_Edje.am b/src/Makefile_Edje.am index 8dc400c..f85f7d9 100644 --- a/src/Makefile_Edje.am +++ b/src/Makefile_Edje.am @@ -163,7 +163,8 @@ bin/edje/edje_cc_parse.c \ bin/edje/edje_cc_mem.c \ bin/edje/edje_cc_handlers.c \ bin/edje/edje_cc_sources.c \ -bin/edje/edje_multisense_convert.c +bin/edje/edje_multisense_convert.c \ +bin/edje/edje_svg_loader.c bin_edje_edje_cc_CPPFLAGS = -I$(top_builddir)/src/lib/efl $(EDJE_COMMON_CPPFLAGS) bin_edje_edje_cc_LDADD = $(USE_EDJE_BIN_LIBS) bin_edje_edje_cc_DEPENDENCIES = \ diff --git a/src/bin/edje/edje_cc.h b/src/bin/edje/edje_cc.h index a097d8e..ad930c9 100644 --- a/src/bin/edje/edje_cc.h +++ b/src/bin/edje/edje_cc.h @@ -257,6 +257,9 @@ int get_param_index(char *str); void color_tree_root_free(void); void convert_color_code(char *str, int *r, int *g, int *b, int *a); +Svg_Node* _svg_load(Eina_File *f, const char *key EINA_UNUSED); + + /* global vars */ extern Eina_List *ext_dirs; extern Eina_List *img_dirs; diff --git a/src/bin/edje/edje_svg_loader.c b/src/bin/edje/edje_svg_loader.c new file mode 100644 index 0000000..2ab2b4d --- /dev/null +++ b/src/bin/edje/edje_svg_loader.c @@ -0,0 +1,1472 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <edje_private.h> +#include <ctype.h> + +#include <Eet.h> +#include <Eina.h> +#include <Evas.h> +#include <eina_matrix.h> + +#ifndef A_VAL +#ifndef WORDS_BIGENDIAN +/* x86 */ +#define A_VAL(p) (((uint8_t *)(p))[3]) +#define R_VAL(p) (((uint8_t *)(p))[2]) +#define G_VAL(p) (((uint8_t *)(p))[1]) +#define B_VAL(p) (((uint8_t *)(p))[0]) +#define AR_VAL(p) ((uint16_t *)(p)[1]) +#define GB_VAL(p) ((uint16_t *)(p)[0]) +#else +/* ppc */ +#define A_VAL(p) (((uint8_t *)(p))[0]) +#define R_VAL(p) (((uint8_t *)(p))[1]) +#define G_VAL(p) (((uint8_t *)(p))[2]) +#define B_VAL(p) (((uint8_t *)(p))[3]) +#define AR_VAL(p) ((uint16_t *)(p)[0]) +#define GB_VAL(p) ((uint16_t *)(p)[1]) +#endif +#endif + +#define ARGB_JOIN(a,r,g,b) \ + (((a) << 24) + ((r) << 16) + ((g) << 8) + (b)) + + +typedef Svg_Node *(*Factory_Method)(Svg_Node *parent, const char *buf, unsigned buflen); + +typedef Svg_Style_Gradient *(*Gradient_Factory_Method)(const char *buf, unsigned buflen); + +typedef struct _Evas_SVG_Loader Evas_SVG_Loader; +struct _Evas_SVG_Loader +{ + Eina_Array *stack; + Svg_Node *doc; + Svg_Node *def; + Svg_Style_Gradient *gradient; + int level; + Eina_Bool result:1; +}; + +char * +_skip_space(const char *str, const char *end) +{ + while (((end != NULL && str < end) || (end == NULL && *str != '\0')) && isspace(*str)) + ++str; + return (char *)str; +} + +static inline char * +_copy_id(const char* str) +{ + char *id = malloc(strlen(str)); + + strcpy(id, str); + return id; +} + +static const char * +_skipcomma(const char *content) +{ + content = _skip_space(content, NULL); + if (*content == ',') return content + 1; + return content; +} + +static inline Eina_Bool +_parse_number(const char **content, double *number) +{ + char *end = NULL; + + *number = strtod(*content, &end); + // if the start of string is not number + if ((*content) == end) return EINA_FALSE; + //skip comma if any + *content = _skipcomma(end); + return EINA_TRUE; +} + +static inline double +_to_double(const char *str) +{ + char *end = NULL; + + return strtod(str, &end); +} + +static inline int +_to_opacity(const char *str) +{ + char *end = NULL; + int a = 0; + double opacity = strtod(str, &end); + + if (*end == '\0') + a = lrint(opacity * 255); + return a; +} + +/* parse the line cap used during stroking a path. + * Value: butt | round | square | inherit + * Initial: butt + * https://www.w3.org/TR/SVG/painting.html + */ +static inline Efl_Gfx_Cap +_to_line_cap(const char *str) +{ + Efl_Gfx_Cap cap = EFL_GFX_CAP_LAST; + + if (!strcmp(str, "butt")) + { + cap = EFL_GFX_CAP_BUTT; + } + else if (!strcmp(str, "round")) + { + cap = EFL_GFX_CAP_ROUND; + } + else if (!strcmp(str, "square")) + { + cap = EFL_GFX_CAP_SQUARE; + } + return cap; +} + +/* parse the line join used during stroking a path. + * Value: miter | round | bevel | inherit + * Initial: miter + * https://www.w3.org/TR/SVG/painting.html + */ +static inline Efl_Gfx_Join +_to_line_join(const char *str) +{ + Efl_Gfx_Join join = EFL_GFX_JOIN_LAST; + + if (!strcmp(str, "miter")) + { + join = EFL_GFX_JOIN_MITER; + } + else if (!strcmp(str, "round")) + { + join = EFL_GFX_JOIN_ROUND; + } + else if (!strcmp(str, "bevel")) + { + join = EFL_GFX_JOIN_BEVEL; + } + return join; +} + +/* parse the fill rule used during filling a path. + * Value: nonzero | evenodd | inherit + * Initial: nonzero + * https://www.w3.org/TR/SVG/painting.html + */ +static inline Efl_Gfx_Fill_Rule +_to_fill_rule(const char *str) +{ + Efl_Gfx_Fill_Rule rule = EFL_GFX_FILL_RULE_WINDING; + + if (!strcmp(str, "evenodd")) + { + rule = EFL_GFX_FILL_RULE_ODD_EVEN; + } + return rule; +} + +/* parse the dash pattern used during stroking a path. + * Value: none | <dasharray> | inherit + * Initial: none + * https://www.w3.org/TR/SVG/painting.html + */ +static inline void +_parse_dash_array(const char *str, Efl_Gfx_Dash** dash, int *length) +{ + double tmp[30]; + char *end = NULL; + int leni, gapi, count = 0, index = 0; + + while (*str) + { + // skip white space, comma + str = _skipcomma(str); + tmp[count++] = strtod(str, &end); + str = _skipcomma(end); + } + + if (count & 0x1) + { // odd case. + *length = count; + *dash = calloc(*length, sizeof(Efl_Gfx_Dash)); + while (index < count) + { + leni = (2 * index) % count; + gapi = (2 * index + 1) % count; + (*dash)[index].length = tmp[leni]; + (*dash)[index].gap = tmp[gapi]; + } + } + else + { // even case + *length = count/2; + *dash = calloc(*length, sizeof(Efl_Gfx_Dash)); + while (index < count) + { + (*dash)[index].length = tmp[2 * index]; + (*dash)[index].gap = tmp[2 * index + 1]; + } + } +} + +static char * + _id_from_url(const char *url) +{ + char tmp[50]; + int i = 0; + char * id; + + url = _skip_space(url, NULL); + if ((*url) == '(') + ++url; + url = _skip_space(url, NULL); + if ((*url) == '#') + ++url; + + while ((*url) != ')') + { + tmp[i++] = *url; + ++url; + } + tmp[i] = '\0'; + id = malloc(strlen(tmp)); + strcpy(id, tmp); + return id; +} + +static unsigned char +_color_parser(const char *value, char **end) +{ + double r; + + r = strtod(value + 4, end); + *end = _skip_space(*end, NULL); + if (**end == '%') + r = 255 * r / 100; + *end = _skip_space(*end, NULL); + + if (r < 0 || r > 255) + { + *end = NULL; + return 0; + } + + return lrint(r); +} + +static inline void +_to_color(const char *str, int *r, int *g, int *b, char** ref) +{ + unsigned int len = strlen(str); + char *red, *green, *blue; + unsigned char tr, tg, tb; + + if (len == 4 && str[0] == '#') + { + if (isxdigit(str[1]) && + isxdigit(str[2]) && + isxdigit(str[3])) + { + char tmp[2] = { '\0', '\0' }; + tmp[0] = str[1]; *r = strtol(tmp, NULL, 16); + tmp[0] = str[2]; *g = strtol(tmp, NULL, 16); + tmp[0] = str[3]; *b = strtol(tmp, NULL, 16); + } + } + else if (len == 7 && str[0] == '#') + { + if (isxdigit(str[1]) && + isxdigit(str[2]) && + isxdigit(str[3]) && + isxdigit(str[4]) && + isxdigit(str[5]) && + isxdigit(str[6])) + { + char tmp[3] = { '\0', '\0', '\0' }; + tmp[0] = str[1]; tmp[1] = str[2]; *r = strtol(tmp, NULL, 16); + tmp[0] = str[3]; tmp[1] = str[4]; *g = strtol(tmp, NULL, 16); + tmp[0] = str[5]; tmp[1] = str[6]; *b = strtol(tmp, NULL, 16); + } + } + else if (len >= 10 && + (str[0] == 'r' || str[0] == 'R') && + (str[1] == 'g' || str[1] == 'G') && + (str[2] == 'b' || str[2] == 'B') && + str[3] == '(' && + str[len - 1] == ')') + { + tr = _color_parser(str + 4, &red); + if (red && *red == ',') + { + tg = _color_parser(red + 1, &green); + if (green && *green == ',') + { + tb = _color_parser(green + 1, &blue); + if (blue && blue[0] == ')' && blue[1] == '\0') + { + *r = tr; *g = tg; *b = tb; + } + } + } + } + else if (len >= 3 && !strncmp(str, "url",3)) + { + *ref = _id_from_url(str+3); + } + else + { + // TODO handle named color + } +} + +static inline char * +parse_numbers_array(char *str, double *points, int *pt_count) +{ + int count = 0; + char *end = NULL; + + str = _skip_space(str, NULL); + while (isdigit(*str) || + *str == '-' || + *str == '+' || + *str == '.') + { + points[count++] = strtod(str, &end); + str = end; + str = _skip_space(str, NULL); + if (*str == ',') + ++str; + //eat the rest of space + str = _skip_space(str, NULL); + } + *pt_count = count; + return str; +} + +typedef enum _Matrix_State +{ + SVG_MATRIX_UNKNOWN, + SVG_MATRIX_MATRIX, + SVG_MATRIX_TRANSLATE, + SVG_MATRIX_ROTATE, + SVG_MATRIX_SCALE, + SVG_MATRIX_SKEWX, + SVG_MATRIX_SKEWY +} Matrix_State; + +#define MATRIX_DEF(Name, Value) \ + { #Name, sizeof (#Name), Value} + +static const struct { + const char *tag; + int sz; + Matrix_State state; +} matrix_tags[] = { + MATRIX_DEF(matrix, SVG_MATRIX_MATRIX), + MATRIX_DEF(translate, SVG_MATRIX_TRANSLATE), + MATRIX_DEF(rotate, SVG_MATRIX_ROTATE), + MATRIX_DEF(scale, SVG_MATRIX_SCALE), + MATRIX_DEF(skewX, SVG_MATRIX_SKEWX), + MATRIX_DEF(skewY, SVG_MATRIX_SKEWY) +}; + +/* parse transform attribute + * https://www.w3.org/TR/SVG/coords.html#TransformAttribute + */ +static Eina_Matrix3 * +_parse_transformation_matrix(const char *value) +{ + unsigned int i; + double points[8]; + int sz, pt_count = 0; + double sx, sy; + Matrix_State state = SVG_MATRIX_UNKNOWN; + Eina_Matrix3 *matrix = calloc(1, sizeof(Eina_Matrix3)); + char *str = (char *)value; + char *end = str + strlen(str); + + eina_matrix3_identity(matrix); + while (str < end) + { + if (isspace(*str) || (*str == ',')) + { + ++str; + continue; + } + sz = end - str; + for (i = 0; i < sizeof (matrix_tags) / sizeof(matrix_tags[0]); i++) + if (matrix_tags[i].sz - 1 == sz && !strncmp(matrix_tags[i].tag, str, sz)) + { + state = matrix_tags[i].state; + str += (matrix_tags[i].sz -1); + } + if ( state == SVG_MATRIX_UNKNOWN) + goto error; + + str = _skip_space(str, end); + if (*str != '(') + goto error; + ++str; + str = parse_numbers_array(str, points, &pt_count); + if (*str != ')') + goto error; + ++str; + + if (state == SVG_MATRIX_MATRIX) + { + Eina_Matrix3 tmp; + + if (pt_count != 6) goto error; + + eina_matrix3_identity(&tmp); + eina_matrix3_values_set(&tmp, + points[0], points[2], points[4], + points[1], points[3], points[5], + 0, 0, 1); + eina_matrix3_compose(matrix, &tmp, matrix); + } + else if (state == SVG_MATRIX_TRANSLATE) + { + if (pt_count == 1) + eina_matrix3_translate(matrix, points[0], 0); + else if (pt_count == 2) + eina_matrix3_translate(matrix, points[0], points[1]); + else + goto error; + } + else if (state == SVG_MATRIX_ROTATE) + { + if (pt_count == 1) + { + eina_matrix3_rotate(matrix, points[0]); + } + else if (pt_count == 3) + { + eina_matrix3_translate(matrix, points[1], points[2]); + eina_matrix3_rotate(matrix, points[0]); + eina_matrix3_translate(matrix, -points[1], -points[2]); + } + else + { + goto error; + } + } + else if (state == SVG_MATRIX_SCALE) + { + if (pt_count < 1 || pt_count > 2) goto error; + + sx = points[0]; + sy = sx; + if (pt_count == 2) + sy = points[1]; + eina_matrix3_scale(matrix, sx, sy); + } + } + error: + return matrix; +} + +#define LENGTH_DEF(Name, Value) \ + { #Name, sizeof (#Name), Value} + +static const struct { + const char *tag; + int sz; + Svg_Length_Type type; +} length_tags[] = { + LENGTH_DEF(%, SVG_LT_PERCENT), + LENGTH_DEF(px, SVG_LT_PX), + LENGTH_DEF(pc, SVG_LT_PC), + LENGTH_DEF(pt, SVG_LT_PT), + LENGTH_DEF(mm, SVG_LT_MM), + LENGTH_DEF(cm, SVG_LT_CM), + LENGTH_DEF(in, SVG_LT_IN) +}; + +static double +parse_length(const char *str, Svg_Length_Type *type) +{ + unsigned int i; + double value; + int sz = strlen(str); + + *type = SVG_LT_PX; + for (i = 0; i < sizeof (length_tags) / sizeof(length_tags[0]); i++) + if (length_tags[i].sz - 1 == sz && !strncmp(length_tags[i].tag, str, sz)) + { + *type = length_tags[i].type; + } + value = strtod(str, NULL); + return value; +} + +static +Efl_Gfx_Fill_Rule +_parse_fill_rule(const char *str) +{ + Efl_Gfx_Fill_Rule fill = EFL_GFX_FILL_RULE_WINDING; + + if (!strcmp(str, "evenodd")) + { + fill = EFL_GFX_FILL_RULE_ODD_EVEN; + } + return fill; +} + +static Eina_Bool +_attr_parse_svg_node(void *data, const char *key, const char *value) +{ + Svg_Doc_Node *node = data; + Svg_Length_Type type; + + // @TODO handle lenght unit. + if (!strcmp(key, "width")) + { + node->width = parse_length(value, &type); + } + else if (!strcmp(key, "height")) + { + node->height = parse_length(value, &type); + } + else if (!strcmp(key, "viewBox")) + { + if (_parse_number(&value, &node->vx)) + if (_parse_number(&value, &node->vy)) + if (_parse_number(&value, &node->vw)) + _parse_number(&value, &node->vh); + } + return EINA_TRUE; +} + +static void +_handle_color_attr(Svg_Node* node, const char *value) +{ + Svg_Style_Property *style = node->style; + char *use = NULL; + + _to_color(value, &style->fill.r, &style->fill.g, &style->fill.b, &use); + if (use) + { + // update the gradient field + } +} + +static void +_handle_fill_attr(Svg_Node* node, const char *value) +{ + Svg_Style_Property *style = node->style; + char *use = NULL; + + _to_color(value, &style->fill.r, &style->fill.g, &style->fill.b, &use); + if (use) + { + // update the gradient field + } +} + +static void +_handle_stroke_attr(Svg_Node* node, const char *value) +{ + Svg_Style_Property *style = node->style; + char *use = NULL; + + _to_color(value, &style->stroke.r, &style->stroke.g, &style->stroke.b, &use); + if (use) + { + // update the gradient field + } +} + +static void +_handle_stroke_opacity_attr(Svg_Node* node, const char *value) +{ + node->style->stroke.a = _to_opacity(value); +} + +static void +_handle_stroke_width_attr(Svg_Node* node, const char *value) +{ + node->style->stroke.width = _to_double(value); +} + +static void +_handle_stroke_linecap_attr(Svg_Node* node, const char *value) +{ + node->style->stroke.cap = _to_line_cap(value); +} + +static void +_handle_stroke_linejoin_attr(Svg_Node* node, const char *value) +{ + node->style->stroke.join = _to_line_join(value); +} + +static void +_handle_color_opacity_attr(Svg_Node* node, const char *value) +{ + node->style->fill.a = _to_opacity(value); +} + +static void +_handle_fill_rule_attr(Svg_Node* node, const char *value) +{ + node->style->fill.fill_rule = _parse_fill_rule(value); +} + +static void +_handle_fill_opacity_attr(Svg_Node* node, const char *value) +{ + node->style->fill.a = _to_opacity(value); +} + +static void +_handle_transform_attr(Svg_Node* node, const char *value) +{ + node->transform = _parse_transformation_matrix(value); +} + + +typedef void (*Style_Method)(Svg_Node *node, const char *value); + +#define STYLE_DEF(Name, Name1) \ + { #Name, sizeof (#Name), _handle_##Name1##_attr} + +static const struct { + const char *tag; + int sz; + Style_Method tag_handler;; +} style_tags[] = { + STYLE_DEF(color, color), + STYLE_DEF(color-opacity, color_opacity), + STYLE_DEF(fill, fill), + STYLE_DEF(fill-rule, fill_rule), + STYLE_DEF(fill-opacity, fill_opacity), + STYLE_DEF(stroke, stroke), + STYLE_DEF(stroke-width, stroke_width), + STYLE_DEF(stroke-linejoin, stroke_linejoin), + STYLE_DEF(stroke-linecap, stroke_linecap), + STYLE_DEF(stroke-opacity, stroke_opacity), + STYLE_DEF(transform, transform) +}; + +static Eina_Bool +_parse_style_attr(void *data, const char *key, const char *value) +{ + Svg_Node* node = data; + unsigned int i; + int sz; + + // trim the white space + key = _skip_space(key, NULL); + + value = _skip_space(value, NULL); + + sz = strlen(key); + for (i = 0; i < sizeof (style_tags) / sizeof(style_tags[0]); i++) + if (style_tags[i].sz - 1 == sz && !strncmp(style_tags[i].tag, key, sz)) + { + style_tags[i].tag_handler(node, value); + return EINA_TRUE; + } + + return EINA_TRUE; +} + +static Eina_Bool +_attr_style_node(void *data, const char *str) +{ + eina_simple_xml_attribute_w3c_parse(str, + _parse_style_attr, data); + return EINA_TRUE; +} + +/* parse g node + * https://www.w3.org/TR/SVG/struct.html#Groups + */ +static Eina_Bool +_attr_parse_g_node(void *data, const char *key, const char *value) +{ + Svg_Node *node = data; + + if (!strcmp(key, "style")) + { + return _attr_style_node(node->style, value); + } + else if (!strcmp(key, "transform")) + { + node->transform = _parse_transformation_matrix(value); + } + else if (!strcmp(key, "id")) + { + node->id = _copy_id(value); + } + return EINA_TRUE; +} + + +static Svg_Node * +_create_node(Svg_Node *parent, Svg_Node_Type type) +{ + Svg_Node *node = calloc(1, sizeof(Svg_Node)); + + // default fill property + node->style = calloc(1, sizeof(Svg_Style_Property)); + node->style->fill.a = 255; + node->style->fill.fill_rule = EFL_GFX_FILL_RULE_WINDING; + + //default stroke property + node->style->stroke.cap = EFL_GFX_CAP_BUTT; + node->style->stroke.join = EFL_GFX_JOIN_MITER; + node->style->stroke.join = EFL_GFX_JOIN_MITER; + node->style->stroke.scale = 1.0; + + node->parent = parent; + node->type = type; + node->child = NULL; + + if (parent) + parent->child = eina_list_append(parent->child, node); + return node; +} + +static Svg_Node * +_create_defs_node(Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED) +{ + Svg_Node *node = _create_node(NULL, SVG_NODE_DEFS); + + return node; +} + +static Svg_Node * +_create_g_node(Svg_Node *parent, const char *buf, unsigned buflen) +{ + Svg_Node *node = _create_node(parent, SVG_NODE_G); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_g_node, node); + return node; +} + +static Svg_Node * +_create_svg_node(Svg_Node *parent, const char *buf, unsigned buflen) +{ + Svg_Node *node = _create_node(parent, SVG_NODE_DOC); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_svg_node, &node->node.doc); + return node; +} + +static Svg_Node * +_create_switch_node(Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED) +{ + return NULL; +} + +static Eina_Bool +_attr_parse_path_node(void *data, const char *key, const char *value) +{ + Svg_Node *node = data; + Svg_Path_Node *path = &(node->node.path); + + if (!strcmp(key, "d")) + { + path->path = malloc(strlen(value)); + strcpy(path->path, value); + } + else if (!strcmp(key, "style")) + { + _attr_style_node(node->style, value); + } + else if (!strcmp(key, "id")) + { + node->id = _copy_id(value); + } + else + { + _parse_style_attr(node, key, value); + } + return EINA_TRUE; +} + +static Svg_Node * +_create_path_node(Svg_Node *parent, const char *buf, unsigned buflen) +{ + Svg_Node *node = _create_node(parent, SVG_NODE_PATH); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_path_node, node); + return node; +} + +#define CIRCLE_DEF(Name, Field) \ + { #Name, sizeof (#Name), offsetof(Svg_Circle_Node, Field)} + +static const struct { + const char *tag; + int sz; + size_t offset; +} circle_tags[] = { + CIRCLE_DEF(cx, cx), + CIRCLE_DEF(cy, cy), + CIRCLE_DEF(r, r) +}; + +/* parse the attributes for a circle element. + * https://www.w3.org/TR/SVG/shapes.html#CircleElement + */ +static Eina_Bool +_attr_parse_circle_node(void *data, const char *key, const char *value) +{ + Svg_Node *node = data; + Svg_Circle_Node *circle = &(node->node.circle); + unsigned int i; + unsigned char *array; + int sz = strlen(key); + + array = (unsigned char*) circle; + for (i = 0; i < sizeof (circle_tags) / sizeof(circle_tags[0]); i++) + if (circle_tags[i].sz - 1 == sz && !strncmp(circle_tags[i].tag, key, sz)) + { + *((double*) (array + circle_tags[i].offset)) = _to_double(value); + return EINA_TRUE; + } + + if (!strcmp(key, "style")) + { + _attr_style_node(node->style, value); + } + else if (!strcmp(key, "id")) + { + node->id = _copy_id(value); + } + else + { + _parse_style_attr(node, key, value); + } + return EINA_TRUE; +} + +static Svg_Node * +_create_circle_node(Svg_Node *parent, const char *buf, unsigned buflen) +{ + Svg_Node *node = _create_node(parent, SVG_NODE_CIRCLE); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_circle_node, node); + return node; +} + +#define ELLIPSE_DEF(Name, Field) \ + { #Name, sizeof (#Name), offsetof(Svg_Ellipse_Node, Field)} + +static const struct { + const char *tag; + int sz; + size_t offset; +} ellipse_tags[] = { + ELLIPSE_DEF(cx,cx), + ELLIPSE_DEF(cy,cy), + ELLIPSE_DEF(rx,rx), + ELLIPSE_DEF(ry,ry) +}; + +/* parse the attributes for an ellipse element. + * https://www.w3.org/TR/SVG/shapes.html#EllipseElement + */ +static Eina_Bool +_attr_parse_ellipse_node(void *data, const char *key, const char *value) +{ + Svg_Node *node = data; + Svg_Ellipse_Node *ellipse = &(node->node.ellipse); + unsigned int i; + unsigned char *array; + int sz = strlen(key); + + array = (unsigned char*) ellipse; + for (i = 0; i < sizeof (ellipse_tags) / sizeof(ellipse_tags[0]); i++) + if (ellipse_tags[i].sz - 1 == sz && !strncmp(ellipse_tags[i].tag, key, sz)) + { + *((double*) (array + ellipse_tags[i].offset)) = _to_double(value); + return EINA_TRUE; + } + + if (!strcmp(key, "id")) + { + node->id = _copy_id(value); + } + else if (!strcmp(key, "style")) + { + _attr_style_node(node->style, value); + } + else + { + _parse_style_attr(node, key, value); + } + return EINA_TRUE; +} + +static Svg_Node * +_create_ellipse_node(Svg_Node *parent, const char *buf, unsigned buflen) +{ + Svg_Node *node = _create_node(parent, SVG_NODE_ELLIPSE); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_ellipse_node, node); + return node; +} + +static void +_attr_parse_polygon_points(const char *str, double **points, int *point_count) +{ + double tmp[50]; + int tmp_count=0; + int count = 0; + double num; + double *point_array = NULL; + + while (_parse_number(&str, &num)) + { + tmp[tmp_count++] = num; + if (tmp_count == 50) + { + point_array = realloc(point_array, (count + tmp_count) * sizeof(double)); + memcpy(&point_array[count], tmp, tmp_count * sizeof(double)); + count += tmp_count; + } + } + + if (tmp_count > 0) + { + point_array = realloc(point_array, (count + tmp_count) * sizeof(double)); + memcpy(&point_array[count], tmp, tmp_count * sizeof(double)); + count += tmp_count; + } + *point_count = count; + *points = point_array; +} + +/* parse the attributes for a polygon element. + * https://www.w3.org/TR/SVG/shapes.html#PolylineElement + */ +static Eina_Bool +_attr_parse_polygon_node(void *data, const char *key, const char *value) +{ + Svg_Node *node = data; + Svg_Polygon_Node *polygon = &(node->node.polygon); + + if (!strcmp(key, "points")) + { + _attr_parse_polygon_points(value, &polygon->points, &polygon->points_count); + } + else if (!strcmp(key, "style")) + { + _attr_style_node(node->style, value); + } + else if (!strcmp(key, "id")) + { + node->id = _copy_id(value); + } + else + { + _parse_style_attr(node, key, value); + } + return EINA_TRUE; +} + +static Svg_Node * +_create_polygon_node(Svg_Node *parent, const char *buf, unsigned buflen) +{ + Svg_Node *node = _create_node(parent, SVG_NODE_POLYGON); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_polygon_node, node); + return node; +} + +#define RECT_DEF(Name, Field) \ + { #Name, sizeof (#Name), offsetof(Svg_Rect_Node, Field)} + +static const struct { + const char *tag; + int sz; + size_t offset; +} rect_tags[] = { + RECT_DEF(x,x), + RECT_DEF(y, y), + RECT_DEF(width, w), + RECT_DEF(height, h), + RECT_DEF(rx, rx), + RECT_DEF(ry, ry) +}; + +/* parse the attributes for a rect element. + * https://www.w3.org/TR/SVG/shapes.html#RectElement + */ +static Eina_Bool +_attr_parse_rect_node(void *data, const char *key, const char *value) +{ + Svg_Node *node = data; + Svg_Rect_Node *rect = & (node->node.rect); + unsigned int i; + unsigned char *array; + int sz = strlen(key); + + array = (unsigned char*) rect; + for (i = 0; i < sizeof (rect_tags) / sizeof(rect_tags[0]); i++) + if (rect_tags[i].sz - 1 == sz && !strncmp(rect_tags[i].tag, key, sz)) + { + *((double*) (array + rect_tags[i].offset)) = _to_double(value); + return EINA_TRUE; + } + + if (!strcmp(key, "id")) + { + node->id = _copy_id(value); + } + else if (!strcmp(key, "style")) + { + _attr_style_node(node->style, value); + } + else + { + _parse_style_attr(node, key, value); + } + + if (rect->rx != 0 && rect->ry == 0) rect->ry = rect->rx; + if (rect->ry != 0 && rect->rx == 0) rect->rx = rect->ry; + + return EINA_TRUE; +} + +static Svg_Node * +_create_rect_node(Svg_Node *parent, const char *buf, unsigned buflen) +{ + Svg_Node *node = _create_node(parent, SVG_NODE_RECT); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_rect_node, node); + return node; +} + +#define TAG_DEF(Name) \ + { #Name, sizeof (#Name), _create_##Name##_node } + +static const struct { + const char *tag; + int sz; + Factory_Method tag_handler; +} graphics_tags[] = { + TAG_DEF(circle), + TAG_DEF(ellipse), + TAG_DEF(path), + TAG_DEF(polygon), + TAG_DEF(rect) +}; + +static const struct { + const char *tag; + int sz; + Factory_Method tag_handler; +} group_tags[] = { + TAG_DEF(defs), + TAG_DEF(g), + TAG_DEF(svg), + TAG_DEF(switch) +}; + +static Factory_Method +_find_group_factory(const char *name) +{ + unsigned int i; + int sz = strlen(name); + + for (i = 0; i < sizeof (group_tags) / sizeof(group_tags[0]); i++) + if (group_tags[i].sz - 1 == sz && !strncmp(group_tags[i].tag, name, sz)) + { + return group_tags[i].tag_handler; + } + return NULL; +} + +static Factory_Method +_find_graphics_factory(const char *name) +{ + unsigned int i; + int sz = strlen(name); + + for (i = 0; i < sizeof (graphics_tags) / sizeof(graphics_tags[0]); i++) + if (graphics_tags[i].sz - 1 == sz && !strncmp(graphics_tags[i].tag, name, sz)) + { + return graphics_tags[i].tag_handler; + } + return NULL; +} + +static void +_handle_radial_cx_attr(Svg_Radial_Gradient* radial, const char *value) +{ + radial->cx = _to_double(value); +} + +static void +_handle_radial_cy_attr(Svg_Radial_Gradient* radial, const char *value) +{ + radial->cy = _to_double(value); +} + +static void +_handle_radial_fx_attr(Svg_Radial_Gradient* radial, const char *value) +{ + radial->fx = _to_double(value); +} + +static void +_handle_radial_fy_attr(Svg_Radial_Gradient* radial, const char *value) +{ + radial->fy = _to_double(value); +} + +static void +_handle_radial_r_attr(Svg_Radial_Gradient* radial, const char *value) +{ + radial->r = _to_double(value); +} + + +typedef void (*Radial_Method)(Svg_Radial_Gradient *radial, const char *value); + +#define RADIAL_DEF(Name) \ + { #Name, sizeof (#Name), _handle_radial_##Name##_attr} + +static const struct { + const char *tag; + int sz; + Radial_Method tag_handler;; +} radial_tags[] = { + RADIAL_DEF(cx), + RADIAL_DEF(cy), + RADIAL_DEF(fx), + RADIAL_DEF(fy), + RADIAL_DEF(r) +}; + +static Eina_Bool +_attr_parse_radial_gradient_node(void *data, const char *key, const char *value) +{ + Svg_Style_Gradient *grad = data; + Svg_Radial_Gradient *radial = grad->radial; + unsigned int i; + int sz = strlen(key); + + for (i = 0; i < sizeof (radial_tags) / sizeof(radial_tags[0]); i++) + if (radial_tags[i].sz - 1 == sz && !strncmp(radial_tags[i].tag, key, sz)) + { + radial_tags[i].tag_handler(radial, value); + return EINA_TRUE; + } + + if (!strcmp(key, "id")) + grad->id = _copy_id(value); + + return EINA_TRUE; +} + +static Svg_Style_Gradient * +_create_radialGradient(const char *buf, unsigned buflen) +{ + Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient)); + + grad->type = SVG_RADIAL_GRADIENT; + grad->radial = calloc(1, sizeof(Svg_Radial_Gradient)); + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_radial_gradient_node, grad); + return grad; + +} + +static Eina_Bool +_attr_parse_stops(void *data, const char *key, const char *value) +{ + Efl_Gfx_Gradient_Stop *stop = data; + + if (!strcmp(key, "offset")) + { + stop->offset = _to_double(value); + } + else if (!strcmp(key, "stop-opacity")) + { + stop->a = _to_opacity(value); + } + else if (!strcmp(key, "stop-color")) + { + _to_color(value, &stop->r, &stop->g, &stop->b, NULL); + } + return EINA_TRUE; +} + +static void +_handle_linear_x1_attr(Svg_Linear_Gradient* linear, const char *value) +{ + linear->x1 = _to_double(value); +} + +static void +_handle_linear_y1_attr(Svg_Linear_Gradient* linear, const char *value) +{ + linear->y1 = _to_double(value); +} + +static void +_handle_linear_x2_attr(Svg_Linear_Gradient* linear, const char *value) +{ + linear->x2 = _to_double(value); +} + +static void +_handle_linear_y2_attr(Svg_Linear_Gradient* linear, const char *value) +{ + linear->y2 = _to_double(value); +} + + +typedef void (*Linear_Method)(Svg_Linear_Gradient *linear, const char *value); + +#define LINEAR_DEF(Name) \ + { #Name, sizeof (#Name), _handle_linear_##Name##_attr} + +static const struct { + const char *tag; + int sz; + Linear_Method tag_handler;; +} linear_tags[] = { + LINEAR_DEF(x1), + LINEAR_DEF(y1), + LINEAR_DEF(x2), + LINEAR_DEF(y2) +}; + +static Eina_Bool +_attr_parse_linear_gradient_node(void *data, const char *key, const char *value) +{ + Svg_Style_Gradient *grad = data; + Svg_Linear_Gradient *linear = grad->linear; + unsigned int i; + int sz = strlen(key); + + for (i = 0; i < sizeof (radial_tags) / sizeof(linear_tags[0]); i++) + if (linear_tags[i].sz - 1 == sz && !strncmp(linear_tags[i].tag, key, sz)) + { + linear_tags[i].tag_handler(linear, value); + return EINA_TRUE; + } + + if (!strcmp(key, "id")) + { + grad->id = _copy_id(value); + } + + return EINA_TRUE; +} + +static Svg_Style_Gradient * +_create_linearGradient(const char *buf, unsigned buflen) +{ + Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient)); + + grad->type = SVG_LINEAR_GRADIENT; + grad->linear = calloc(1, sizeof(Svg_Linear_Gradient)); + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_linear_gradient_node, grad); + return grad; + +} + +#define GRADIENT_DEF(Name) \ + { #Name, sizeof (#Name), _create_##Name } + +static const struct { + const char *tag; + int sz; + Gradient_Factory_Method tag_handler; +} gradient_tags[] = { + GRADIENT_DEF(linearGradient), + GRADIENT_DEF(radialGradient) +}; + +static Gradient_Factory_Method +_find_gradient_factory(const char *name) +{ + unsigned int i; + int sz = strlen(name); + + for (i = 0; i < sizeof (gradient_tags) / sizeof(gradient_tags[0]); i++) + if (gradient_tags[i].sz - 1 == sz && !strncmp(gradient_tags[i].tag, name, sz)) + { + return gradient_tags[i].tag_handler; + } + return NULL; +} + +static void +_evas_svg_loader_xml_open_parser(Evas_SVG_Loader *loader, + const char *content, unsigned int length) +{ + const char *attrs = NULL; + int attrs_length = 0; + int sz = length; + char tag_name[20]; + Factory_Method method; + Gradient_Factory_Method gradient_method; + Svg_Node *node = NULL, *parent; + loader->level++; + attrs = eina_simple_xml_tag_attributes_find(content, length); + + // find out the tag name starting from content till sz length + if (attrs) + { + sz = attrs - content; + attrs_length = length - sz; + while ((sz > 0) && (isspace(content[sz - 1]))) + sz--; + strncpy(tag_name, content, sz); + tag_name[sz] = '\0'; + } + + if ((method = _find_group_factory(tag_name))) + { + //group + if (!loader->doc) + { + if (strcmp(tag_name, "svg")) + return; // Not a valid svg document + node = method(NULL, attrs, attrs_length); + loader->doc = node; + } + else + { + parent = eina_array_data_get(loader->stack, eina_array_count(loader->stack) - 1); + node = method(parent, attrs, attrs_length); + } + eina_array_push(loader->stack, node); + + if (node->type == SVG_NODE_DEFS) + loader->def = node; + } + else if ((method = _find_graphics_factory(tag_name))) + { + parent = eina_array_data_get(loader->stack, eina_array_count(loader->stack) - 1); + node = method(parent, attrs, attrs_length); + } + else if ((gradient_method = _find_gradient_factory(tag_name))) + { + Svg_Style_Gradient *gradient; + gradient = gradient_method(attrs, attrs_length); + if (loader->def) + { + loader->def->node.defs.gradients = eina_list_append(loader->def->node.defs.gradients, gradient); + } + loader->gradient = gradient; + } + else if (!strcmp(tag_name, "stop")) + { + Efl_Gfx_Gradient_Stop *stop = calloc(1, sizeof(Efl_Gfx_Gradient_Stop)); + eina_simple_xml_attributes_parse(attrs, attrs_length, + _attr_parse_stops, stop); + if (loader->gradient) + loader->gradient->stops = eina_list_append(loader->gradient->stops, stop); + } + +} + +static void +_evas_svg_loader_xml_close_parser(Evas_SVG_Loader *loader, + const char *content, unsigned int length EINA_UNUSED) +{ + content = _skip_space(content, NULL); + if (!strncmp(content, "g", 1)) + { + eina_array_pop(loader->stack); + } + else if (!strncmp(content, "svg", 3)) + { + eina_array_pop(loader->stack); + } + else if (!strncmp(content, "defs", 3)) + { + eina_array_pop(loader->stack); + } + else if (!strncmp(content, "linearGradient", 13)) + { + //TODO + } + + loader->level--; +} + +static Eina_Bool +_evas_svg_loader_parser(void *data, Eina_Simple_XML_Type type, + const char *content, + unsigned int offset EINA_UNUSED, unsigned int length) +{ + Evas_SVG_Loader *loader = data; + + switch (type) + { + case EINA_SIMPLE_XML_OPEN: + _evas_svg_loader_xml_open_parser(loader, content, length); + break; + case EINA_SIMPLE_XML_OPEN_EMPTY: + _evas_svg_loader_xml_open_parser(loader, content, length); + case EINA_SIMPLE_XML_CLOSE: + _evas_svg_loader_xml_close_parser(loader, content, length); + break; + case EINA_SIMPLE_XML_DATA: + case EINA_SIMPLE_XML_CDATA: + case EINA_SIMPLE_XML_DOCTYPE_CHILD: + break; + case EINA_SIMPLE_XML_IGNORED: + case EINA_SIMPLE_XML_COMMENT: + case EINA_SIMPLE_XML_DOCTYPE: + break; + + default: + break; + } + + return EINA_TRUE; +} + +EAPI Svg_Node * +_svg_load(Eina_File *f, const char *key EINA_UNUSED) +{ + Evas_SVG_Loader loader = { + NULL, NULL,NULL,0 + }; + const char *content; + unsigned int length; + + if (!f) return NULL; + + length = eina_file_size_get(f); + content = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); + if (content) + { + loader.stack = eina_array_new(8); + eina_simple_xml_parse(content, length, EINA_TRUE, + _evas_svg_loader_parser, &loader); + + eina_array_free(loader.stack); + eina_file_map_free(f, (void*) content); + } + return loader.doc; +} diff --git a/src/lib/edje/edje_data.c b/src/lib/edje/edje_data.c index c229f6a..154c2ed 100644 --- a/src/lib/edje/edje_data.c +++ b/src/lib/edje/edje_data.c @@ -83,6 +83,414 @@ Eet_Data_Descriptor *_edje_edd_edje_map_colors_pointer = NULL; Eet_Data_Descriptor *_edje_edd_edje_filter = NULL; Eet_Data_Descriptor *_edje_edd_edje_filter_directory = NULL; +Eet_Data_Descriptor *_edje_edd_edje_rect_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_circle_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_ellipse_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_gradient_stops_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_linear_gradient_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_radial_gradient_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_style_gradient_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_style_property_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_matrix3_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_doc_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_defs_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_g_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_arc_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_path_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_polygon_node = NULL; +Eet_Data_Descriptor *_edje_edd_edje_vg_node = NULL; + +#define FREE_DESCRIPTOR(eed) \ + if (eed) \ + { \ + eet_data_descriptor_free((eed)); \ + (eed) = NULL; \ + } + + +static inline Eet_Data_Descriptor* +_eet_for_rect_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Rect_Node); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "x", x, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "y", y, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "w", w, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "h", h, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "rx", rx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Rect_Node, "ry", ry, EET_T_DOUBLE); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_circle_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Circle_Node); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Circle_Node, "cx", cx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Circle_Node, "cy", cy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Circle_Node, "r", r, EET_T_DOUBLE); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_ellipse_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Ellipse_Node); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "cx", cx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "cy", cy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "rx", rx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Ellipse_Node, "ry", ry, EET_T_DOUBLE); + return eet; +} + + +static inline Eet_Data_Descriptor* +_eet_for_gradient_stops(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Efl_Gfx_Gradient_Stop); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "offset", offset, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "r", r, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "g", g, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "b", b, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Efl_Gfx_Gradient_Stop, "a", a, EET_T_INT); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_linear_gradient(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Linear_Gradient); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "x1", x1, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "y1", y1, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "x2", x2, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Linear_Gradient, "y2", y2, EET_T_DOUBLE); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_radial_gradient(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Radial_Gradient); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "cx", cx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "cy", cy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "fx", fx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "fy", fy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Radial_Gradient, "r", r, EET_T_DOUBLE); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_style_gradient(void) +{ + Eet_Data_Descriptor_Class eetc; + + if (_edje_edd_edje_style_gradient_node) return _edje_edd_edje_style_gradient_node; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Style_Gradient); + _edje_edd_edje_style_gradient_node = eet_data_descriptor_stream_new(&eetc); + _edje_edd_edje_gradient_stops_node = _eet_for_gradient_stops(); + _edje_edd_edje_linear_gradient_node = _eet_for_linear_gradient(); + _edje_edd_edje_radial_gradient_node = _eet_for_radial_gradient(); + + EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "type", type, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "id", id, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "spread", spread, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "stops", stops, _edje_edd_edje_gradient_stops_node); + EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "radial", radial, _edje_edd_edje_radial_gradient_node); + EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_style_gradient_node, Svg_Style_Gradient, "linear", linear, _edje_edd_edje_linear_gradient_node); + + return _edje_edd_edje_style_gradient_node; +} + +static inline Eet_Data_Descriptor* +_eet_for_style_property(void) +{ + Eet_Data_Descriptor *eet, *eet_gradient, *eet_dash; + Eet_Data_Descriptor_Class eetc, eetc_dash; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Style_Property); + eet = eet_data_descriptor_stream_new(&eetc); + eet_gradient = _eet_for_style_gradient(); + + eet_dash = eet_data_descriptor_stream_new(&eetc_dash); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet_dash, Efl_Gfx_Dash, "length", length, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet_dash, Efl_Gfx_Dash, "gap", gap, EET_T_DOUBLE); + + // for fill + EET_DATA_DESCRIPTOR_ADD_SUB(eet, Svg_Style_Property, "fill.gradient", fill.gradient, eet_gradient); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.fill_rule", fill.fill_rule, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.r", fill.r, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.g", fill.g, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.b", fill.b, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.a", fill.a, EET_T_INT); + + // for stroke + EET_DATA_DESCRIPTOR_ADD_SUB(eet, Svg_Style_Property, "stroke.gradient", stroke.gradient, eet_gradient); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.scale", stroke.scale, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.width", stroke.width, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.centered", stroke.centered, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.r", stroke.r, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.g", stroke.g, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.b", stroke.b, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.a", stroke.a, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.cap", stroke.cap, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.join", stroke.join, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(eet, Svg_Style_Property, "stroke.dash", stroke.dash, eet_dash); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.dash_count", stroke.dash_count, EET_T_INT); + + return eet; +} + +static Eet_Data_Descriptor* +_eet_for_eina_matrix3(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Eina_Matrix3); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "xx", xx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "xy", xy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "xz", xz, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "yx", yx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "yy", yy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "yz", yz, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "zx", zx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "zy", zy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Eina_Matrix3, "zz", zz, EET_T_DOUBLE); + + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_doc_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Doc_Node); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "width", width, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "height", height, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vx", vx, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vy", vy, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vw", vw, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "vh", vh, EET_T_DOUBLE); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_defs_node(void) +{ + Eet_Data_Descriptor *eet, *eet_gradient; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Defs_Node); + eet = eet_data_descriptor_stream_new(&eetc); + eet_gradient = _eet_for_style_gradient(); + + EET_DATA_DESCRIPTOR_ADD_LIST(eet, Svg_Defs_Node, "gradients", gradients, eet_gradient); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_g_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_G_Node); + eet = eet_data_descriptor_stream_new(&eetc); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_arc_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Arc_Node); + eet = eet_data_descriptor_stream_new(&eetc); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_polygon_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Polygon_Node); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC_VAR_ARRAY(eet, Svg_Polygon_Node, "points", points, EET_T_DOUBLE); + return eet; +} + +static inline Eet_Data_Descriptor* +_eet_for_path_node(void) +{ + Eet_Data_Descriptor *eet; + Eet_Data_Descriptor_Class eetc; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Path_Node); + eet = eet_data_descriptor_stream_new(&eetc); + EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Path_Node, "path", path, EET_T_STRING); + return eet; +} + +struct +{ + Svg_Node_Type u; + const char *name; +} eet_mapping[] = { + { SVG_NODE_DOC, "doc" }, + { SVG_NODE_G, "g" }, + { SVG_NODE_DEFS, "defs" }, + { SVG_NODE_ARC, "arc" }, + { SVG_NODE_CIRCLE, "circle" }, + { SVG_NODE_ELLIPSE, "ellipse" }, + { SVG_NODE_POLYGON, "polygon" }, + { SVG_NODE_RECT, "rect" }, + { SVG_NODE_PATH, "path" }, + { SVG_NODE_UNKNOWN, NULL } +}; + +static const char * +/* union + type_get() */ +_union_type_get(const void *data, + Eina_Bool *unknow) +{ + const Svg_Node_Type *u = data; + int i; + + if (unknow) + *unknow = EINA_FALSE; + + for (i = 0; eet_mapping[i].name != NULL; ++i) + if (*u == eet_mapping[i].u) + return eet_mapping[i].name; + + if (unknow) + *unknow = EINA_TRUE; + return NULL; +} /* _union_type_get */ + +static Eina_Bool +_union_type_set(const char *type, + void *data, + Eina_Bool unknow) +{ + Svg_Node_Type *u = data; + int i; + + if (unknow) + return EINA_FALSE; + + for (i = 0; eet_mapping[i].name != NULL; ++i) + if (strcmp(eet_mapping[i].name, type) == 0) + { + *u = eet_mapping[i].u; + return EINA_TRUE; + } + return EINA_FALSE; +} /* _union_type_set */ + +EAPI Eet_Data_Descriptor * +_edje_svg_node_eet(void) +{ + Eet_Data_Descriptor *eet_union; + Eet_Data_Descriptor_Class eetc; + + if (_edje_edd_edje_vg_node) return _edje_edd_edje_vg_node; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Node); + _edje_edd_edje_vg_node = eet_data_descriptor_stream_new(&eetc); + + eetc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION; + eetc.func.type_get = _union_type_get; + eetc.func.type_set = _union_type_set; + eet_union = eet_data_descriptor_stream_new(&eetc); + + _edje_edd_edje_doc_node = _eet_for_doc_node(); + _edje_edd_edje_g_node = _eet_for_g_node(); + _edje_edd_edje_defs_node = _eet_for_defs_node(); + _edje_edd_edje_arc_node = _eet_for_arc_node(); + _edje_edd_edje_circle_node = _eet_for_circle_node(); + _edje_edd_edje_ellipse_node = _eet_for_ellipse_node(); + _edje_edd_edje_rect_node = _eet_for_rect_node(); + _edje_edd_edje_path_node = _eet_for_path_node(); + _edje_edd_edje_polygon_node = _eet_for_polygon_node(); + _edje_edd_edje_style_property_node = _eet_for_style_property(); + _edje_edd_edje_matrix3_node = _eet_for_eina_matrix3(); + + + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "doc", _edje_edd_edje_doc_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "g", _edje_edd_edje_g_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "defs", _edje_edd_edje_defs_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "arc", _edje_edd_edje_arc_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "circle", _edje_edd_edje_circle_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "ellipse", _edje_edd_edje_ellipse_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "rect", _edje_edd_edje_rect_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "path", _edje_edd_edje_path_node); + EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "polygon", _edje_edd_edje_polygon_node); + + EET_DATA_DESCRIPTOR_ADD_UNION(_edje_edd_edje_vg_node, Svg_Node, "node", node, type, eet_union); + + + EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_vg_node, Svg_Node, "child", child, _edje_edd_edje_vg_node); + EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_vg_node, Svg_Node, "id", id, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_vg_node, Svg_Node, "style", style, _edje_edd_edje_style_property_node); + EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_vg_node, Svg_Node, "transform", transform, _edje_edd_edje_matrix3_node); + + return _edje_edd_edje_vg_node; +} + +EAPI void +_edje_svg_node_destroy_eet(void) +{ + FREE_DESCRIPTOR(_edje_edd_edje_rect_node); + FREE_DESCRIPTOR(_edje_edd_edje_circle_node); + FREE_DESCRIPTOR(_edje_edd_edje_ellipse_node); + FREE_DESCRIPTOR(_edje_edd_edje_gradient_stops_node); + FREE_DESCRIPTOR(_edje_edd_edje_linear_gradient_node); + FREE_DESCRIPTOR(_edje_edd_edje_radial_gradient_node); + FREE_DESCRIPTOR(_edje_edd_edje_style_gradient_node); + FREE_DESCRIPTOR(_edje_edd_edje_style_property_node); + FREE_DESCRIPTOR(_edje_edd_edje_matrix3_node); + FREE_DESCRIPTOR(_edje_edd_edje_doc_node); + FREE_DESCRIPTOR(_edje_edd_edje_defs_node); + FREE_DESCRIPTOR(_edje_edd_edje_g_node); + FREE_DESCRIPTOR(_edje_edd_edje_arc_node); + FREE_DESCRIPTOR(_edje_edd_edje_path_node); + FREE_DESCRIPTOR(_edje_edd_edje_polygon_node); + FREE_DESCRIPTOR(_edje_edd_edje_vg_node); +} + /* allocate a description struct. * this initializes clip_to_id as this field will not be present in most * edje files. @@ -308,6 +716,7 @@ _edje_edd_shutdown(void) FREED(_edje_edd_edje_file); FREED(_edje_edd_edje_part_collection); + _edje_svg_node_destroy_eet(); } #define EDJE_DEFINE_POINTER_TYPE(Type, Name) \ diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index 05b0b64..f5c3bb8 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -2966,6 +2966,231 @@ Eina_Bool _edje_efl_container_content_set(Edje *ed, const char *part, Efl_Gfx *o void _edje_internal_proxy_shutdown(void); +// Svg loader +typedef enum _Svg_Node_Type Svg_Node_Type; +typedef enum _Svg_Length_Type Svg_Length_Type; + +typedef struct _Svg_Node Svg_Node; +typedef struct _Svg_Doc_Node Svg_Doc_Node; +typedef struct _Svg_G_Node Svg_G_Node; +typedef struct _Svg_Defs_Node Svg_Defs_Node; +typedef struct _Svg_Arc_Node Svg_Arc_Node; +typedef struct _Svg_Circle_Node Svg_Circle_Node; +typedef struct _Svg_Ellipse_Node Svg_Ellipse_Node; +typedef struct _Svg_Polygon_Node Svg_Polygon_Node; +typedef struct _Svg_Rect_Node Svg_Rect_Node; +typedef struct _Svg_Path_Node Svg_Path_Node; +typedef struct _Svg_Style_Property Svg_Style_Property; + +typedef struct _Svg_Style_Stroke Svg_Style_Stroke; +typedef struct _Svg_Style_Fill Svg_Style_Fill; + +typedef enum _Svg_Gradient_Type Svg_Gradient_Type; +typedef struct _Svg_Style_Gradient Svg_Style_Gradient; +typedef struct _Svg_Linear_Gradient Svg_Linear_Gradient; +typedef struct _Svg_Radial_Gradient Svg_Radial_Gradient; + +enum _Svg_Node_Type +{ + SVG_NODE_DOC, + SVG_NODE_G, + SVG_NODE_DEFS, + SVG_NODE_SWITCH, + SVG_NODE_ANIMATION, + SVG_NODE_ARC, + SVG_NODE_CIRCLE, + SVG_NODE_ELLIPSE, + SVG_NODE_IMAGE, + SVG_NODE_LINE, + SVG_NODE_PATH, + SVG_NODE_POLYGON, + SVG_NODE_POLYLINE, + SVG_NODE_RECT, + SVG_NODE_TEXT, + SVG_NODE_TEXTAREA, + SVG_NODE_TSPAN, + SVG_NODE_USE, + SVG_NODE_VIDEO, + SVG_NODE_UNKNOWN +}; + +enum _Svg_Length_Type +{ + SVG_LT_PERCENT, + SVG_LT_PX, + SVG_LT_PC, + SVG_LT_PT, + SVG_LT_MM, + SVG_LT_CM, + SVG_LT_IN, +}; + +struct _Svg_Doc_Node +{ + double width; + double height; + double vx; + double vy; + double vw; + double vh; +}; + +struct _Svg_G_Node +{ + +}; + +struct _Svg_Defs_Node +{ + Eina_List *gradients; +}; + +struct _Svg_Arc_Node +{ + +}; + +struct _Svg_Ellipse_Node +{ + double cx; + double cy; + double rx; + double ry; +}; + +struct _Svg_Circle_Node +{ + double cx; + double cy; + double r; +}; + +struct _Svg_Rect_Node +{ + double x; + double y; + double w; + double h; + double rx; + double ry; +}; + +struct _Svg_Path_Node +{ + char *path; +}; + +struct _Svg_Polygon_Node +{ + int points_count; + double *points; +}; + + +enum _Svg_Gradient_Type +{ + SVG_LINEAR_GRADIENT, + SVG_RADIAL_GRADIENT +}; +struct _Svg_Linear_Gradient +{ + double x1; + double y1; + double x2; + double y2; +}; + +struct _Svg_Radial_Gradient +{ + double cx; + double cy; + double fx; + double fy; + double r; +}; + +struct _Svg_Style_Gradient +{ + Svg_Gradient_Type type; + char *id; + Efl_Gfx_Gradient_Spread spread; + Eina_List *stops; // Efl_Gfx_Gradient_Stop + Svg_Radial_Gradient *radial; + Svg_Linear_Gradient *linear; +}; + + +struct _Svg_Style_Fill +{ + Svg_Style_Gradient *gradient; + Efl_Gfx_Fill_Rule fill_rule; + int r; + int g; + int b; + int a; +}; + +struct _Svg_Style_Stroke +{ + Svg_Style_Gradient *gradient; + double scale; + double width; + double centered; + int r; + int g; + int b; + int a; + Efl_Gfx_Cap cap; + Efl_Gfx_Join join; + Efl_Gfx_Dash *dash; + int dash_count; +}; + +struct _Svg_Style_Property +{ + Svg_Style_Fill fill; + Svg_Style_Stroke stroke; +}; + +struct _Svg_Node +{ + Svg_Node_Type type; + Svg_Node *parent; + Eina_List *child; + char *id; + Svg_Style_Property *style; + Eina_Matrix3 *transform; + union + { + Svg_G_Node g; + Svg_Doc_Node doc; + Svg_Defs_Node defs; + Svg_Arc_Node arc; + Svg_Circle_Node circle; + Svg_Ellipse_Node ellipse; + Svg_Polygon_Node polygon; + Svg_Rect_Node rect; + Svg_Path_Node path; + }node; +}; + +enum _Svg_Style_Type +{ + SVG_STYLE_QUALITY, + SVG_STYLE_FILL, + SVG_STYLE_VIEWPORT_FILL, + SVG_STYLE_FONT, + SVG_STYLE_STROKE, + SVG_STYLE_SOLID_COLOR, + SVG_STYLE_GRADIENT, + SVG_STYLE_TRANSFORM, + SVG_STYLE_OPACITY, + SVG_STYLE_COMP_OP +}; + +EAPI Eet_Data_Descriptor * _edje_svg_node_eet(void); +void _edje_svg_node_destroy_eet(void); + #ifdef HAVE_LIBREMIX #include <remix/remix.h> #endif --