summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunsuChoi <jsuya.choi@samsung.com>2020-10-14 19:16:53 +0900
committerHermet Park <chuneon.park@samsung.com>2020-10-14 19:16:53 +0900
commit3274390f7324b561739bdf2b620c939b6e0508fd (patch)
tree0ae5f3d12a09854c7dc00aa59459b2b5c132909c
parent25e64a9a4e3adc259e81093a223c12996e424bf1 (diff)
vg_load_svg: Implement ClipPath feature
Summary: Supports case of using style attribute for defined <clipPath> and node. In SVG, <clipPath> can be used as a "clipPath" attribute or a style "clip-path". If there is a clip-path node, save it as a composition node and use composition method(matte_alpha) to compose it. Below node types support clip-path. <circle> <ellipse> <g> <path> <polygon> <polyline> <rect> Test Plan: Please see attached svg files {F4026162} Reviewers: Hermet, smohanty Reviewed By: Hermet Subscribers: #reviewers, #committers, cedric, herb, kimcinoo Tags: #efl Differential Revision: https://phab.enlightenment.org/D12179
-rw-r--r--src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c113
-rw-r--r--src/static_libs/vg_common/vg_common.h17
-rw-r--r--src/static_libs/vg_common/vg_common_svg.c41
3 files changed, 167 insertions, 4 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 2e78e87834..e68edbb0c9 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
@@ -918,6 +918,16 @@ _handle_transform_attr(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node* node, cons
918 node->transform = _parse_transformation_matrix(value); 918 node->transform = _parse_transformation_matrix(value);
919} 919}
920 920
921
922static void _handle_clip_path_attr(Evas_SVG_Loader* loader EINA_UNUSED, Svg_Node* node, const char* value)
923{
924 Svg_Style_Property* style = node->style;
925 style->comp.flags |= SVG_COMPOSITE_FLAGS_CLIP_PATH;
926
927 int len = strlen(value);
928 if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _id_from_url((const char*)(value + 3));
929}
930
921static void 931static void
922_handle_display_attr(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node* node, const char *value) 932_handle_display_attr(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node* node, const char *value)
923{ 933{
@@ -1003,6 +1013,10 @@ _attr_parse_g_node(void *data, const char *key, const char *value)
1003 { 1013 {
1004 node->transform = _parse_transformation_matrix(value); 1014 node->transform = _parse_transformation_matrix(value);
1005 } 1015 }
1016 else if (!strcmp(key, "clip-path"))
1017 {
1018 _handle_clip_path_attr(loader, node, value);
1019 }
1006 else if (!strcmp(key, "id")) 1020 else if (!strcmp(key, "id"))
1007 { 1021 {
1008 node->id = _copy_id(value); 1022 node->id = _copy_id(value);
@@ -1015,6 +1029,37 @@ _attr_parse_g_node(void *data, const char *key, const char *value)
1015} 1029}
1016 1030
1017 1031
1032/* parse clipPath node
1033 * https://www.w3.org/TR/SVG/struct.html#Groups
1034 */
1035static Eina_Bool _attr_parse_clip_path_node(void* data, const char* key, const char* value)
1036{
1037 Evas_SVG_Loader *loader = data;
1038 Svg_Node* node = loader->svg_parse->node;
1039
1040 if (!strcmp(key, "style"))
1041 {
1042 return _attr_style_node(loader, value);
1043 }
1044 else if (!strcmp(key, "transform"))
1045 {
1046 node->transform = _parse_transformation_matrix(value);
1047 }
1048 else if (!strcmp(key, "clip-path"))
1049 {
1050 _handle_clip_path_attr(loader, node, value);
1051 }
1052 else if (!strcmp(key, "id"))
1053 {
1054 node->id = _copy_id(value);
1055 }
1056 else
1057 {
1058 _parse_style_attr(loader, key, value);
1059 }
1060 return EINA_TRUE;
1061}
1062
1018static Svg_Node * 1063static Svg_Node *
1019_create_node(Svg_Node *parent, Svg_Node_Type type) 1064_create_node(Svg_Node *parent, Svg_Node_Type type)
1020{ 1065{
@@ -1111,10 +1156,11 @@ _create_mask_node(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node *parent EINA_UNU
1111static Svg_Node * 1156static Svg_Node *
1112_create_clipPath_node(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED) 1157_create_clipPath_node(Evas_SVG_Loader *loader EINA_UNUSED, Svg_Node *parent EINA_UNUSED, const char *buf EINA_UNUSED, unsigned buflen EINA_UNUSED)
1113{ 1158{
1114 Svg_Node *node = _create_node(NULL, SVG_NODE_UNKNOWN); 1159 loader->svg_parse->node = _create_node(parent, SVG_NODE_CLIP_PATH);
1115 1160
1116 node->display = EINA_FALSE; 1161 eina_simple_xml_attributes_parse(buf, buflen,
1117 return node; 1162 _attr_parse_clip_path_node, loader);
1163 return loader->svg_parse->node;
1118} 1164}
1119 1165
1120static Eina_Bool 1166static Eina_Bool
@@ -1132,6 +1178,10 @@ _attr_parse_path_node(void *data, const char *key, const char *value)
1132 { 1178 {
1133 _attr_style_node(loader, value); 1179 _attr_style_node(loader, value);
1134 } 1180 }
1181 else if (!strcmp(key, "clip-path"))
1182 {
1183 _handle_clip_path_attr(loader, node, value);
1184 }
1135 else if (!strcmp(key, "id")) 1185 else if (!strcmp(key, "id"))
1136 { 1186 {
1137 node->id = _copy_id(value); 1187 node->id = _copy_id(value);
@@ -1194,6 +1244,10 @@ _attr_parse_circle_node(void *data, const char *key, const char *value)
1194 { 1244 {
1195 _attr_style_node(loader, value); 1245 _attr_style_node(loader, value);
1196 } 1246 }
1247 else if (!strcmp(key, "clip-path"))
1248 {
1249 _handle_clip_path_attr(loader, node, value);
1250 }
1197 else if (!strcmp(key, "id")) 1251 else if (!strcmp(key, "id"))
1198 { 1252 {
1199 node->id = _copy_id(value); 1253 node->id = _copy_id(value);
@@ -1256,6 +1310,10 @@ _attr_parse_ellipse_node(void *data, const char *key, const char *value)
1256 { 1310 {
1257 node->id = _copy_id(value); 1311 node->id = _copy_id(value);
1258 } 1312 }
1313 else if (!strcmp(key, "clip-path"))
1314 {
1315 _handle_clip_path_attr(loader, node, value);
1316 }
1259 else if (!strcmp(key, "style")) 1317 else if (!strcmp(key, "style"))
1260 { 1318 {
1261 _attr_style_node(loader, value); 1319 _attr_style_node(loader, value);
@@ -1341,6 +1399,10 @@ _attr_parse_polygon_node(void *data, const char *key, const char *value)
1341 { 1399 {
1342 _attr_style_node(loader, value); 1400 _attr_style_node(loader, value);
1343 } 1401 }
1402 else if (!strcmp(key, "clip-path"))
1403 {
1404 _handle_clip_path_attr(loader, node, value);
1405 }
1344 else if (!strcmp(key, "id")) 1406 else if (!strcmp(key, "id"))
1345 { 1407 {
1346 node->id = _copy_id(value); 1408 node->id = _copy_id(value);
@@ -1425,6 +1487,10 @@ _attr_parse_rect_node(void *data, const char *key, const char *value)
1425 { 1487 {
1426 _attr_style_node(loader, value); 1488 _attr_style_node(loader, value);
1427 } 1489 }
1490 else if (!strcmp(key, "clip-path"))
1491 {
1492 _handle_clip_path_attr(loader, node, value);
1493 }
1428 else 1494 else
1429 { 1495 {
1430 _parse_style_attr(loader, key, value); 1496 _parse_style_attr(loader, key, value);
@@ -1492,6 +1558,10 @@ _attr_parse_line_node(void *data, const char *key, const char *value)
1492 { 1558 {
1493 _attr_style_node(loader, value); 1559 _attr_style_node(loader, value);
1494 } 1560 }
1561 else if (!strcmp(key, "clip-path"))
1562 {
1563 _handle_clip_path_attr(loader, node, value);
1564 }
1495 else 1565 else
1496 { 1566 {
1497 _parse_style_attr(loader, key, value); 1567 _parse_style_attr(loader, key, value);
@@ -1550,6 +1620,20 @@ _find_child_by_id(Svg_Node *node, const char *id)
1550 return NULL; 1620 return NULL;
1551} 1621}
1552 1622
1623static Svg_Node* _find_node_by_id(Svg_Node *node, const char* id)
1624{
1625 Svg_Node *child, *result = NULL;
1626 Eina_List *l;
1627 if ((node->id) && !strcmp(node->id, id)) return node;
1628
1629 EINA_LIST_FOREACH(node->child, l, child)
1630 {
1631 result = _find_node_by_id(child, id);
1632 if (result) break;
1633 }
1634 return result;
1635}
1636
1553static Eina_List * 1637static Eina_List *
1554_clone_grad_stops(Eina_List *from) 1638_clone_grad_stops(Eina_List *from)
1555{ 1639{
@@ -1698,6 +1782,10 @@ _attr_parse_use_node(void *data, const char *key, const char *value)
1698 _clone_node(node_from, node); 1782 _clone_node(node_from, node);
1699 eina_stringshare_del(id); 1783 eina_stringshare_del(id);
1700 } 1784 }
1785 else if (!strcmp(key, "clip-path"))
1786 {
1787 _handle_clip_path_attr(loader, node, value);
1788 }
1701 else 1789 else
1702 { 1790 {
1703 _attr_parse_g_node(data, key, value); 1791 _attr_parse_g_node(data, key, value);
@@ -2207,6 +2295,7 @@ _evas_svg_loader_xml_open_parser(Evas_SVG_Loader *loader,
2207 } 2295 }
2208 else 2296 else
2209 { 2297 {
2298 if (!strcmp(tag_name, "svg")) return; //Already loadded <svg>(SvgNodeType::Doc) tag
2210 parent = _get_parent_node_from_loader(loader); 2299 parent = _get_parent_node_from_loader(loader);
2211 node = method(loader, parent, attrs, attrs_length); 2300 node = method(loader, parent, attrs, attrs_length);
2212 } 2301 }
@@ -2469,6 +2558,21 @@ _update_gradient(Svg_Node *node, Eina_List *grad_list)
2469 } 2558 }
2470 } 2559 }
2471} 2560}
2561
2562static void _update_composite(Svg_Node* node, Svg_Node* root)
2563{
2564 Svg_Node *child;
2565 Eina_List *l;
2566 if (node->style->comp.url && !node->style->comp.node) {
2567 Svg_Node *findResult = _find_node_by_id(root, node->style->comp.url);
2568 if (findResult) node->style->comp.node = findResult;
2569 }
2570 EINA_LIST_FOREACH(node->child, l, child)
2571 {
2572 _update_composite(child, root);
2573 }
2574}
2575
2472static Eina_Bool 2576static Eina_Bool
2473evas_vg_load_file_data_svg(Vg_File_Data *vfd EINA_UNUSED) 2577evas_vg_load_file_data_svg(Vg_File_Data *vfd EINA_UNUSED)
2474{ 2578{
@@ -2521,6 +2625,9 @@ evas_vg_load_file_open_svg(Eina_File *file,
2521 eina_list_free(gradient_list); 2625 eina_list_free(gradient_list);
2522 } 2626 }
2523 2627
2628 _update_composite(loader.doc, loader.doc);
2629 if (defs) _update_composite(loader.doc, defs);
2630
2524 *error = EVAS_LOAD_ERROR_NONE; 2631 *error = EVAS_LOAD_ERROR_NONE;
2525 } 2632 }
2526 else 2633 else
diff --git a/src/static_libs/vg_common/vg_common.h b/src/static_libs/vg_common/vg_common.h
index 43e36df4d8..e9cbb4f475 100644
--- a/src/static_libs/vg_common/vg_common.h
+++ b/src/static_libs/vg_common/vg_common.h
@@ -25,12 +25,14 @@ typedef struct _Svg_Ellipse_Node Svg_Ellipse_Node;
25typedef struct _Svg_Polygon_Node Svg_Polygon_Node; 25typedef struct _Svg_Polygon_Node Svg_Polygon_Node;
26typedef struct _Svg_Rect_Node Svg_Rect_Node; 26typedef struct _Svg_Rect_Node Svg_Rect_Node;
27typedef struct _Svg_Path_Node Svg_Path_Node; 27typedef struct _Svg_Path_Node Svg_Path_Node;
28typedef struct _Svg_Composite Svg_Composite;
28typedef struct _Svg_Style_Property Svg_Style_Property; 29typedef struct _Svg_Style_Property Svg_Style_Property;
29typedef struct _Svg_Line_Node Svg_Line_Node; 30typedef struct _Svg_Line_Node Svg_Line_Node;
30typedef struct _Svg_Custom_Command_Node Svg_Custom_Command_Node; 31typedef struct _Svg_Custom_Command_Node Svg_Custom_Command_Node;
31 32
32typedef struct _Svg_Style_Stroke Svg_Style_Stroke; 33typedef struct _Svg_Style_Stroke Svg_Style_Stroke;
33typedef struct _Svg_Style_Fill Svg_Style_Fill; 34typedef struct _Svg_Style_Fill Svg_Style_Fill;
35typedef enum _Svg_Composite_Flags Svg_Composite_Flags;
34typedef enum _Svg_Fill_Flags Svg_Fill_Flags; 36typedef enum _Svg_Fill_Flags Svg_Fill_Flags;
35typedef enum _Svg_Stroke_Flags Svg_Stroke_Flags; 37typedef enum _Svg_Stroke_Flags Svg_Stroke_Flags;
36 38
@@ -62,6 +64,7 @@ enum _Svg_Node_Type
62 SVG_NODE_USE, 64 SVG_NODE_USE,
63 SVG_NODE_VIDEO, 65 SVG_NODE_VIDEO,
64 SVG_NODE_CUSTOME_COMMAND, 66 SVG_NODE_CUSTOME_COMMAND,
67 SVG_NODE_CLIP_PATH,
65 SVG_NODE_UNKNOWN 68 SVG_NODE_UNKNOWN
66}; 69};
67 70
@@ -224,6 +227,12 @@ struct _Svg_Paint
224 Eina_Stringshare *url; 227 Eina_Stringshare *url;
225}; 228};
226 229
230enum _Svg_Composite_Flags
231{
232 SVG_COMPOSITE_FLAGS_CLIP_PATH = 0x01,
233};
234
235
227enum _Svg_Fill_Flags 236enum _Svg_Fill_Flags
228{ 237{
229 SVG_FILL_FLAGS_PAINT = 0x1, 238 SVG_FILL_FLAGS_PAINT = 0x1,
@@ -266,10 +275,18 @@ struct _Svg_Style_Stroke
266 int dash_count; 275 int dash_count;
267}; 276};
268 277
278struct _Svg_Composite
279{
280 Svg_Composite_Flags flags;
281 const char *url;
282 Svg_Node* node;
283};
284
269struct _Svg_Style_Property 285struct _Svg_Style_Property
270{ 286{
271 Svg_Style_Fill fill; 287 Svg_Style_Fill fill;
272 Svg_Style_Stroke stroke; 288 Svg_Style_Stroke stroke;
289 Svg_Composite comp;
273 // the color property indirectly 290 // the color property indirectly
274 // used by fill and stroke 291 // used by fill and stroke
275 int r; 292 int r;
diff --git a/src/static_libs/vg_common/vg_common_svg.c b/src/static_libs/vg_common/vg_common_svg.c
index 38e203b205..30fc0c0eb5 100644
--- a/src/static_libs/vg_common/vg_common_svg.c
+++ b/src/static_libs/vg_common/vg_common_svg.c
@@ -763,7 +763,7 @@ _apply_vg_property(Svg_Node *node, Efl_VG *vg, Efl_VG *parent, Vg_File_Data *vg_
763 efl_gfx_color_set(vg, ((float) r) * fa, ((float) g) * fa, ((float) b) * fa, ((float) a) * fa); 763 efl_gfx_color_set(vg, ((float) r) * fa, ((float) g) * fa, ((float) b) * fa, ((float) a) * fa);
764 } 764 }
765 765
766 if (node->type == SVG_NODE_G) return; 766 if (node->type == SVG_NODE_G || node->type == SVG_NODE_CLIP_PATH) return;
767 767
768 // apply the fill style property 768 // apply the fill style property
769 efl_gfx_shape_fill_rule_set(vg, style->fill.fill_rule); 769 efl_gfx_shape_fill_rule_set(vg, style->fill.fill_rule);
@@ -829,12 +829,51 @@ _add_polyline(Efl_VG *vg, double *array, int size, Eina_Bool polygon)
829} 829}
830 830
831static Efl_VG * 831static Efl_VG *
832_create_vg_container(Efl_VG *parent)
833{
834 if (!parent)
835 return efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
836 else
837 return efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, parent);
838}
839
840static Efl_VG *
832vg_common_create_vg_node_helper(Svg_Node *node, Efl_VG *parent, Vg_File_Data *vg_data) 841vg_common_create_vg_node_helper(Svg_Node *node, Efl_VG *parent, Vg_File_Data *vg_data)
833{ 842{
834 Efl_VG *vg = NULL; 843 Efl_VG *vg = NULL;
835 Svg_Node *child; 844 Svg_Node *child;
836 Eina_List *l; 845 Eina_List *l;
837 846
847 // apply composite node
848 if (node->style->comp.node)
849 {
850 // composite ClipPath
851 if (node->style->comp.flags & SVG_COMPOSITE_FLAGS_CLIP_PATH)
852 {
853 Svg_Node *comp_node = node->style->comp.node;
854 Efl_VG *comp_parent = NULL ,*comp_vg_container = NULL;
855
856 //NOTE:: If node has a composition node, add a container to use VG_COMPOSITION_METHOD.
857 // The composition method is applied to the newly added container.
858 comp_parent = _create_vg_container(parent);
859 comp_vg_container = _create_vg_container(parent);
860
861 // apply the transformation
862 if (comp_node->transform) efl_canvas_vg_node_transformation_set(comp_vg_container, comp_node->transform);
863
864 EINA_LIST_FOREACH(comp_node->child, l, child)
865 {
866 Efl_VG *vg = vg_common_create_vg_node_helper(child, comp_vg_container, vg_data);
867 // clippath does not require color blending. That's why we keep 255 opacity.
868 efl_gfx_color_set(vg, 255, 255, 255, 255);
869 }
870
871 // Composition matte alpha
872 efl_canvas_vg_node_comp_method_set(comp_parent, comp_vg_container, EFL_GFX_VG_COMPOSITE_METHOD_MATTE_ALPHA);
873
874 parent = comp_parent; // replace parent
875 }
876 }
838 switch (node->type) 877 switch (node->type)
839 { 878 {
840 case SVG_NODE_DOC: 879 case SVG_NODE_DOC: