diff options
Diffstat (limited to 'src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c')
-rw-r--r-- | src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c | 239 |
1 files changed, 208 insertions, 31 deletions
diff --git a/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c b/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c index 313d3eed15..e8c46ceb1f 100644 --- a/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c +++ b/src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c @@ -259,8 +259,6 @@ static struct { _PARSE_TAG(Efl_Gfx_Fill_Rule, fill_rule, fill_rule_tags, EFL_GFX_FILL_RULE_WINDING); -#if 0 -// unused at the moment /* parse the dash pattern used during stroking a path. * Value: none | <dasharray> | inherit * Initial: none @@ -269,7 +267,8 @@ _PARSE_TAG(Efl_Gfx_Fill_Rule, fill_rule, fill_rule_tags, EFL_GFX_FILL_RULE_WINDI static inline void _parse_dash_array(const char *str, Efl_Gfx_Dash** dash, int *length) { - double tmp[30]; + // It is assumed that the length of the dasharray string is 255 or less. + double tmp[255]; char *end = NULL; int leni, gapi, count = 0, index = 0; @@ -291,20 +290,21 @@ _parse_dash_array(const char *str, Efl_Gfx_Dash** dash, int *length) gapi = (2 * index + 1) % count; (*dash)[index].length = tmp[leni]; (*dash)[index].gap = tmp[gapi]; + index++; } } else { // even case *length = count/2; *dash = calloc(*length, sizeof(Efl_Gfx_Dash)); - while (index < count) + while (index < *length) { (*dash)[index].length = tmp[2 * index]; (*dash)[index].gap = tmp[2 * index + 1]; + index++; } } } -#endif static Eina_Stringshare * _id_from_url(const char *url) @@ -773,7 +773,7 @@ _attr_parse_svg_node(void *data, const char *key, const char *value) Svg_Doc_Node *doc = &(node->node.doc); Svg_Length_Type type; - // @TODO handle lenght unit. + // @TODO handle length unit. if (!strcmp(key, "width")) { doc->width = parse_length(value, &type); @@ -865,6 +865,13 @@ _handle_stroke_opacity_attr(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node* node, } static void +_handle_stroke_dasharray_attr(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node* node, const char *value) +{ + node->style->stroke.flags |= SVG_STROKE_FLAGS_DASH; + _parse_dash_array(value, &node->style->stroke.dash, &node->style->stroke.dash_count); +} + +static void _handle_stroke_width_attr(Evas_SVG_Loader *loader, Svg_Node* node, const char *value) { node->style->stroke.flags |= SVG_STROKE_FLAGS_WIDTH; @@ -911,6 +918,16 @@ _handle_transform_attr(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node* node, cons node->transform = _parse_transformation_matrix(value); } + +static void _handle_clip_path_attr(Evas_SVG_Loader* loader EINA_UNUSED, Svg_Node* node, const char* value) +{ + Svg_Style_Property* style = node->style; + style->comp.flags |= SVG_COMPOSITE_FLAGS_CLIP_PATH; + + int len = strlen(value); + if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _id_from_url((const char*)(value + 3)); +} + static void _handle_display_attr(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node* node, const char *value) { @@ -942,6 +959,7 @@ static const struct { STYLE_DEF(stroke-linejoin, stroke_linejoin), STYLE_DEF(stroke-linecap, stroke_linecap), STYLE_DEF(stroke-opacity, stroke_opacity), + STYLE_DEF(stroke-dasharray, stroke_dasharray), STYLE_DEF(transform, transform), STYLE_DEF(display, display) }; @@ -995,6 +1013,10 @@ _attr_parse_g_node(void *data, const char *key, const char *value) { node->transform = _parse_transformation_matrix(value); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else if (!strcmp(key, "id")) { node->id = _copy_id(value); @@ -1007,6 +1029,37 @@ _attr_parse_g_node(void *data, const char *key, const char *value) } +/* parse clipPath node + * https://www.w3.org/TR/SVG/struct.html#Groups + */ +static Eina_Bool _attr_parse_clip_path_node(void* data, const char* key, const char* value) +{ + Evas_SVG_Loader *loader = data; + Svg_Node* node = loader->svg_parse->node; + + if (!strcmp(key, "style")) + { + return _attr_style_node(loader, value); + } + else if (!strcmp(key, "transform")) + { + node->transform = _parse_transformation_matrix(value); + } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } + else if (!strcmp(key, "id")) + { + node->id = _copy_id(value); + } + else + { + _parse_style_attr(loader, key, value); + } + return EINA_TRUE; +} + static Svg_Node * _create_node(Svg_Node *parent, Svg_Node_Type type) { @@ -1091,6 +1144,25 @@ _create_switch_node(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node *parent EINA_U return NULL; } +static Svg_Node * +_create_mask_node(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED) +{ + Svg_Node *node = _create_node(NULL, SVG_NODE_UNKNOWN); + + node->display = EINA_FALSE; + return node; +} + +static Svg_Node * +_create_clipPath_node(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED) +{ + loader->svg_parse->node = _create_node(parent, SVG_NODE_CLIP_PATH); + + eina_simple_xml_attributes_parse(buf, buflen, + _attr_parse_clip_path_node, loader); + return loader->svg_parse->node; +} + static Eina_Bool _attr_parse_path_node(void *data, const char *key, const char *value) { @@ -1106,6 +1178,10 @@ _attr_parse_path_node(void *data, const char *key, const char *value) { _attr_style_node(loader, value); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else if (!strcmp(key, "id")) { node->id = _copy_id(value); @@ -1168,6 +1244,10 @@ _attr_parse_circle_node(void *data, const char *key, const char *value) { _attr_style_node(loader, value); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else if (!strcmp(key, "id")) { node->id = _copy_id(value); @@ -1230,6 +1310,10 @@ _attr_parse_ellipse_node(void *data, const char *key, const char *value) { node->id = _copy_id(value); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else if (!strcmp(key, "style")) { _attr_style_node(loader, value); @@ -1315,6 +1399,10 @@ _attr_parse_polygon_node(void *data, const char *key, const char *value) { _attr_style_node(loader, value); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else if (!strcmp(key, "id")) { node->id = _copy_id(value); @@ -1381,6 +1469,13 @@ _attr_parse_rect_node(void *data, const char *key, const char *value) if (rect_tags[i].sz - 1 == sz && !strncmp(rect_tags[i].tag, key, sz)) { *((double*) (array + rect_tags[i].offset)) = _to_double(loader->svg_parse, value, rect_tags[i].type); + + //Case if only rx or ry is declared + if (!strncmp(rect_tags[i].tag, "rx", sz)) rect->has_rx = EINA_TRUE; + if (!strncmp(rect_tags[i].tag, "ry", sz)) rect->has_ry = EINA_TRUE; + + if (!EINA_DBL_EQ(rect->rx, 0) && EINA_DBL_EQ(rect->ry, 0) && rect->has_rx && !rect->has_ry) rect->ry = rect->rx; + if (!EINA_DBL_EQ(rect->ry, 0) && EINA_DBL_EQ(rect->rx, 0) && !rect->has_rx && rect->has_ry) rect->rx = rect->ry; return EINA_TRUE; } @@ -1392,13 +1487,15 @@ _attr_parse_rect_node(void *data, const char *key, const char *value) { _attr_style_node(loader, value); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else { _parse_style_attr(loader, key, value); } - if (!EINA_DBL_EQ(rect->rx, 0) && EINA_DBL_EQ(rect->ry, 0)) rect->ry = rect->rx; - if (!EINA_DBL_EQ(rect->ry, 0) && EINA_DBL_EQ(rect->rx, 0)) rect->rx = rect->ry; return EINA_TRUE; } @@ -1408,6 +1505,10 @@ _create_rect_node(Evas_SVG_Loader *loader, Svg_Node *parent, const char *buf, un { loader->svg_parse->node = _create_node(parent, SVG_NODE_RECT); + if (loader->svg_parse->node) { + loader->svg_parse->node->node.rect.has_rx = loader->svg_parse->node->node.rect.has_ry = EINA_FALSE; + } + eina_simple_xml_attributes_parse(buf, buflen, _attr_parse_rect_node, loader); return loader->svg_parse->node; @@ -1457,6 +1558,10 @@ _attr_parse_line_node(void *data, const char *key, const char *value) { _attr_style_node(loader, value); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else { _parse_style_attr(loader, key, value); @@ -1515,6 +1620,20 @@ _find_child_by_id(Svg_Node *node, const char *id) return NULL; } +static Svg_Node* _find_node_by_id(Svg_Node *node, const char* id) +{ + Svg_Node *child, *result = NULL; + Eina_List *l; + if ((node->id) && !strcmp(node->id, id)) return node; + + EINA_LIST_FOREACH(node->child, l, child) + { + result = _find_node_by_id(child, id); + if (result) break; + } + return result; +} + static Eina_List * _clone_grad_stops(Eina_List *from) { @@ -1601,6 +1720,8 @@ _copy_attribute(Svg_Node *to, Svg_Node *from) to->node.rect.h = from->node.rect.h; to->node.rect.rx = from->node.rect.rx; to->node.rect.ry = from->node.rect.ry; + to->node.rect.has_rx = from->node.rect.has_rx; + to->node.rect.has_ry = from->node.rect.has_ry; break; case SVG_NODE_LINE: to->node.line.x1 = from->node.line.x1; @@ -1613,11 +1734,13 @@ _copy_attribute(Svg_Node *to, Svg_Node *from) break; case SVG_NODE_POLYGON: to->node.polygon.points_count = from->node.polygon.points_count; - to->node.polygon.points = calloc(to->node.polygon.points_count, sizeof(double)); + to->node.polygon.points = malloc(to->node.polygon.points_count * sizeof(double)); + memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.points_count * sizeof(double)); break; case SVG_NODE_POLYLINE: to->node.polyline.points_count = from->node.polyline.points_count; - to->node.polyline.points = calloc(to->node.polyline.points_count, sizeof(double)); + to->node.polyline.points = malloc(to->node.polyline.points_count * sizeof(double)); + memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.points_count * sizeof(double)); break; default: break; @@ -1659,6 +1782,10 @@ _attr_parse_use_node(void *data, const char *key, const char *value) _clone_node(node_from, node); eina_stringshare_del(id); } + else if (!strcmp(key, "clip-path")) + { + _handle_clip_path_attr(loader, node, value); + } else { _attr_parse_g_node(data, key, value); @@ -1703,7 +1830,9 @@ static const struct { TAG_DEF(defs), TAG_DEF(g), TAG_DEF(svg), - TAG_DEF(switch) + TAG_DEF(switch), + TAG_DEF(mask), + TAG_DEF(clipPath) }; #define FIND_FACTORY(Short_Name, Tags_Array) \ @@ -2112,9 +2241,18 @@ _find_gradient_factory(const char *name) return NULL; } +static Svg_Node* +_get_parent_node_from_loader(Evas_SVG_Loader *loader) +{ + if (eina_array_count(loader->stack) > 0) + return eina_array_data_get(loader->stack, eina_array_count(loader->stack) - 1); + else + return loader->doc; +} + static void _evas_svg_loader_xml_open_parser(Evas_SVG_Loader *loader, - const char *content, unsigned int length) + const char *content, unsigned int length, Eina_Bool empty) { const char *attrs = NULL; int attrs_length = 0; @@ -2141,6 +2279,7 @@ _evas_svg_loader_xml_open_parser(Evas_SVG_Loader *loader, attrs_length = length - sz; while ((sz > 0) && (isspace(content[sz - 1]))) sz--; + if ((unsigned int)sz > sizeof(tag_name)) return; strncpy(tag_name, content, sz); tag_name[sz] = '\0'; } @@ -2157,20 +2296,22 @@ _evas_svg_loader_xml_open_parser(Evas_SVG_Loader *loader, } else { - parent = eina_array_data_get(loader->stack, eina_array_count(loader->stack) - 1); + if (!strcmp(tag_name, "svg")) return; //Already loadded <svg>(SvgNodeType::Doc) tag + parent = _get_parent_node_from_loader(loader); node = method(loader, parent, attrs, attrs_length); } - eina_array_push(loader->stack, node); if (node->type == SVG_NODE_DEFS) - { - loader->doc->node.doc.defs = node; - loader->def = node; - } + { + loader->doc->node.doc.defs = node; + loader->def = node; + if (!empty) eina_array_push(loader->stack, node); + } + else eina_array_push(loader->stack, node); } else if ((method = _find_graphics_factory(tag_name))) { - parent = eina_array_data_get(loader->stack, eina_array_count(loader->stack) - 1); + parent = _get_parent_node_from_loader(loader); node = method(loader, parent, attrs, attrs_length); } else if ((gradient_method = _find_gradient_factory(tag_name))) @@ -2218,7 +2359,9 @@ static const struct { } pop_array[] = { POP_TAG(g), POP_TAG(svg), - POP_TAG(defs) + POP_TAG(defs), + POP_TAG(mask), + POP_TAG(clipPath) }; static void @@ -2250,10 +2393,10 @@ _evas_svg_loader_parser(void *data, Eina_Simple_XML_Type type, switch (type) { case EINA_SIMPLE_XML_OPEN: - _evas_svg_loader_xml_open_parser(loader, content, length); + _evas_svg_loader_xml_open_parser(loader, content, length, EINA_FALSE); break; case EINA_SIMPLE_XML_OPEN_EMPTY: - _evas_svg_loader_xml_open_parser(loader, content, length); + _evas_svg_loader_xml_open_parser(loader, content, length, EINA_TRUE); break; case EINA_SIMPLE_XML_CLOSE: _evas_svg_loader_xml_close_parser(loader, content, length); @@ -2279,7 +2422,7 @@ _inherit_style(Svg_Style_Property *child, Svg_Style_Property *parent) { if (parent == NULL) return; - // inherit the property of parent if not present in child. + // inherit the property of parent if not present in child. // fill if (!(child->fill.flags & SVG_FILL_FLAGS_PAINT)) { @@ -2324,6 +2467,22 @@ _inherit_style(Svg_Style_Property *child, Svg_Style_Property *parent) { child->stroke.join = parent->stroke.join; } + if (!(child->stroke.flags & SVG_STROKE_FLAGS_DASH)) + { + int i = 0; + int count = parent->stroke.dash_count; + if (count > 0) + { + if (child->stroke.dash) free(child->stroke.dash); + child->stroke.dash = calloc(count, sizeof(Efl_Gfx_Dash)); + child->stroke.dash_count = count; + for (i = 0; i < count; i++) + { + child->stroke.dash[i].length = parent->stroke.dash[i].length; + child->stroke.dash[i].gap = parent->stroke.dash[i].gap; + } + } + } } void @@ -2400,6 +2559,21 @@ _update_gradient(Svg_Node *node, Eina_List *grad_list) } } } + +static void _update_composite(Svg_Node* node, Svg_Node* root) +{ + Svg_Node *child; + Eina_List *l; + if (node->style->comp.url && !node->style->comp.node) { + Svg_Node *findResult = _find_node_by_id(root, node->style->comp.url); + if (findResult) node->style->comp.node = findResult; + } + EINA_LIST_FOREACH(node->child, l, child) + { + _update_composite(child, root); + } +} + static Eina_Bool evas_vg_load_file_data_svg(Vg_File_Data *vfd EINA_UNUSED) { @@ -2410,6 +2584,7 @@ static Eina_Bool evas_vg_load_file_close_svg(Vg_File_Data *vfd) { if (vfd->root) efl_unref(vfd->root); + free(vfd); return EINA_TRUE; } @@ -2444,16 +2619,16 @@ evas_vg_load_file_open_svg(Eina_File *file, defs = loader.doc->node.doc.defs; if (defs) _update_gradient(loader.doc, defs->node.defs.gradients); - else + if (loader.gradients) { - if (loader.gradients) - { - Eina_List* gradient_list = loader.gradients; - _update_gradient(loader.doc, gradient_list); - eina_list_free(gradient_list); - } + Eina_List* gradient_list = loader.gradients; + _update_gradient(loader.doc, gradient_list); + eina_list_free(gradient_list); } + _update_composite(loader.doc, loader.doc); + if (defs) _update_composite(loader.doc, defs); + *error = EVAS_LOAD_ERROR_NONE; } else @@ -2462,7 +2637,9 @@ evas_vg_load_file_open_svg(Eina_File *file, } free(loader.svg_parse); - return vg_common_svg_create_vg_node(loader.doc); + Vg_File_Data* result = vg_common_svg_create_vg_node(loader.doc); + vg_common_svg_node_free(loader.doc); + return result; } static Evas_Vg_Load_Func evas_vg_load_svg_func = |