efl/src/static_libs/vg_common/vg_common_svg.c

1176 lines
42 KiB
C
Raw Normal View History

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "vg_common.h"
#include <Eet.h>
#include <Evas.h>
Eet_Data_Descriptor *_eet_rect_node = NULL;
Eet_Data_Descriptor *_eet_circle_node = NULL;
Eet_Data_Descriptor *_eet_ellipse_node = NULL;
Eet_Data_Descriptor *_eet_gradient_stops_node = NULL;
Eet_Data_Descriptor *_eet_linear_gradient_node = NULL;
Eet_Data_Descriptor *_eet_radial_gradient_node = NULL;
Eet_Data_Descriptor *_eet_style_gradient_node = NULL;
Eet_Data_Descriptor *_eet_style_property_node = NULL;
Eet_Data_Descriptor *_eet_matrix3_node = NULL;
Eet_Data_Descriptor *_eet_doc_node = NULL;
Eet_Data_Descriptor *_eet_defs_node = NULL;
Eet_Data_Descriptor *_eet_g_node = NULL;
Eet_Data_Descriptor *_eet_arc_node = NULL;
Eet_Data_Descriptor *_eet_path_node = NULL;
Eet_Data_Descriptor *_eet_polygon_node = NULL;
Eet_Data_Descriptor *_eet_vg_node = NULL;
Eet_Data_Descriptor *_eet_line_node = NULL;
Eet_Data_Descriptor *_eet_custom_command_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_line_node(void)
{
Eet_Data_Descriptor *eet;
Eet_Data_Descriptor_Class eetc;
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Line_Node);
eet = eet_data_descriptor_stream_new(&eetc);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Line_Node, "x1", x1, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Line_Node, "y1", y1, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Line_Node, "x2", x2, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Line_Node, "y2", y2, 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 (_eet_style_gradient_node) return _eet_style_gradient_node;
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Style_Gradient);
_eet_style_gradient_node = eet_data_descriptor_stream_new(&eetc);
_eet_gradient_stops_node = _eet_for_gradient_stops();
_eet_linear_gradient_node = _eet_for_linear_gradient();
_eet_radial_gradient_node = _eet_for_radial_gradient();
EET_DATA_DESCRIPTOR_ADD_BASIC(_eet_style_gradient_node, Svg_Style_Gradient, "type", type, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(_eet_style_gradient_node, Svg_Style_Gradient, "id", id, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_eet_style_gradient_node, Svg_Style_Gradient, "spread", spread, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_LIST(_eet_style_gradient_node, Svg_Style_Gradient, "stops", stops, _eet_gradient_stops_node);
EET_DATA_DESCRIPTOR_ADD_SUB(_eet_style_gradient_node, Svg_Style_Gradient, "radial", radial, _eet_radial_gradient_node);
EET_DATA_DESCRIPTOR_ADD_SUB(_eet_style_gradient_node, Svg_Style_Gradient, "linear", linear, _eet_linear_gradient_node);
EET_DATA_DESCRIPTOR_ADD_BASIC(_eet_style_gradient_node, Svg_Style_Gradient, "user_space", user_space, EET_T_INT);
return _eet_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_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc_dash, Efl_Gfx_Dash);
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);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "r", r, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "g", g, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "b", b, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "opacity", opacity, EET_T_INT);
// for fill
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.flags", fill.flags, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.r", fill.paint.r, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.g", fill.paint.g, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.b", fill.paint.b, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.none", fill.paint.none, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.cur_color", fill.paint.cur_color, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_SUB(eet, Svg_Style_Property, "fill.paint.gradient", fill.paint.gradient, eet_gradient);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.paint.url", fill.paint.url, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.opacity", fill.opacity, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "fill.fill_rule", fill.fill_rule, EET_T_INT);
// for stroke
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.flags", stroke.flags, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.r", stroke.paint.r, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.g", stroke.paint.g, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.b", stroke.paint.b, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.none", stroke.paint.none, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.cur_color", stroke.paint.cur_color, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_SUB(eet, Svg_Style_Property, "stroke.paint.gradient", stroke.paint.gradient, eet_gradient);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.paint.url", stroke.paint.url, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Style_Property, "stroke.opacity", stroke.opacity, EET_T_INT);
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.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);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Doc_Node, "preserve_aspect", preserve_aspect, EET_T_INT);
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(eet, Svg_Polygon_Node, "points_count", points_count, EET_T_INT);
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_custom_command_node(void)
{
Eet_Data_Descriptor *eet;
Eet_Data_Descriptor_Class eetc;
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Custom_Command_Node);
eet = eet_data_descriptor_stream_new(&eetc);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Custom_Command_Node, "points_count", points_count, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC_VAR_ARRAY(eet, Svg_Custom_Command_Node, "points", points, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(eet, Svg_Custom_Command_Node, "commands_count", commands_count, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC_VAR_ARRAY(eet, Svg_Custom_Command_Node, "commands", commands, EET_T_INT);
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;
}
static 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_POLYLINE, "polyline" },
{ SVG_NODE_RECT, "rect" },
{ SVG_NODE_PATH, "path" },
{ SVG_NODE_LINE, "line" },
{ SVG_NODE_CUSTOME_COMMAND, "command" },
{ SVG_NODE_UNKNOWN, NULL }
};
static const char *
_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;
}
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;
}
Eet_Data_Descriptor *
vg_common_svg_node_eet(void)
{
Eet_Data_Descriptor *eet_union;
Eet_Data_Descriptor_Class eetc;
if (_eet_vg_node) return _eet_vg_node;
EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eetc, Svg_Node);
_eet_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);
_eet_doc_node = _eet_for_doc_node();
_eet_g_node = _eet_for_g_node();
_eet_defs_node = _eet_for_defs_node();
_eet_arc_node = _eet_for_arc_node();
_eet_circle_node = _eet_for_circle_node();
_eet_ellipse_node = _eet_for_ellipse_node();
_eet_rect_node = _eet_for_rect_node();
_eet_line_node = _eet_for_line_node();
_eet_path_node = _eet_for_path_node();
_eet_polygon_node = _eet_for_polygon_node();
_eet_custom_command_node = _eet_for_custom_command_node();
_eet_style_property_node = _eet_for_style_property();
_eet_matrix3_node = _eet_for_eina_matrix3();
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "doc", _eet_doc_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "g", _eet_g_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "defs", _eet_defs_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "arc", _eet_arc_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "circle", _eet_circle_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "ellipse", _eet_ellipse_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "rect", _eet_rect_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "line", _eet_line_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "path", _eet_path_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "polygon", _eet_polygon_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "polyline", _eet_polygon_node);
EET_DATA_DESCRIPTOR_ADD_MAPPING(eet_union, "command", _eet_custom_command_node);
EET_DATA_DESCRIPTOR_ADD_UNION(_eet_vg_node, Svg_Node, "node", node, type, eet_union);
EET_DATA_DESCRIPTOR_ADD_LIST(_eet_vg_node, Svg_Node, "child", child, _eet_vg_node);
EET_DATA_DESCRIPTOR_ADD_BASIC(_eet_vg_node, Svg_Node, "id", id, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_SUB(_eet_vg_node, Svg_Node, "style", style, _eet_style_property_node);
EET_DATA_DESCRIPTOR_ADD_SUB(_eet_vg_node, Svg_Node, "transform", transform, _eet_matrix3_node);
evas_vg_load_svg: Support "display" attribute. Summary: If the display attribute is "none", VG object is not show. The default is "inline" which means visible and "none" means invisible. Depending on the type of node, additional functionality may be required. refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display Test Plan: [SVG] <svg viewBox="0 0 220 100" xmlns="http://www.w3.org/2000/svg"> <!-- Here the yellow rectangle is displayed --> <g display="none"> <rect x="0" y="0" width="100" height="100" fill="skyblue"></rect> </g> <rect x="20" y="20" width="60" height="60" fill="yellow"></rect> <!-- Here the yellow rectangle is not displayed --> <rect x="120" y="0" width="100" height="100" fill="skyblue"></rect> <rect x="140" y="20" width="60" height="60" fill="yellow" display="none"></rect> </svg> [C CODE] int main(int argc, char **argv) { setenv("ECTOR_BACKEND", "default", 1); elm_init(argc, argv); Evas_Object *win = elm_win_util_standard_add(NULL, "test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); elm_win_autodel_set(win, 1); Evas *evas = evas_object_evas_get(win); Evas_Object *vg = evas_object_vg_add(evas); evas_object_show(vg); Evas_Object *container = evas_vg_container_add(vg); evas_object_vg_root_node_set(vg, container); Evas_Object *svg = efl_add(EFL_CANVAS_VG_OBJECT_CLASS, container); efl_file_simple_load(svg, "./test.svg", NULL); efl_gfx_entity_size_set(svg, EINA_SIZE2D(600, 600)); efl_gfx_entity_visible_set(svg, EINA_TRUE); evas_object_size_hint_weight_set(svg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(svg, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(win, vg); evas_object_resize(win, WIDTH, HEIGHT); evas_object_show(win); elm_run(); elm_shutdown(); return 0; } Reviewers: Hermet, smohanty, kimcinoo Reviewed By: Hermet Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9640
2019-08-20 04:32:15 -07:00
EET_DATA_DESCRIPTOR_ADD_BASIC(_eet_vg_node, Svg_Node, "display", display, EET_T_INT);
return _eet_vg_node;
}
void
vg_common_svg_node_eet_destroy(void)
{
FREE_DESCRIPTOR(_eet_rect_node);
FREE_DESCRIPTOR(_eet_circle_node);
FREE_DESCRIPTOR(_eet_ellipse_node);
FREE_DESCRIPTOR(_eet_gradient_stops_node);
FREE_DESCRIPTOR(_eet_linear_gradient_node);
FREE_DESCRIPTOR(_eet_radial_gradient_node);
FREE_DESCRIPTOR(_eet_style_gradient_node);
FREE_DESCRIPTOR(_eet_style_property_node);
FREE_DESCRIPTOR(_eet_matrix3_node);
FREE_DESCRIPTOR(_eet_doc_node);
FREE_DESCRIPTOR(_eet_defs_node);
FREE_DESCRIPTOR(_eet_g_node);
FREE_DESCRIPTOR(_eet_arc_node);
FREE_DESCRIPTOR(_eet_path_node);
FREE_DESCRIPTOR(_eet_polygon_node);
FREE_DESCRIPTOR(_eet_vg_node);
FREE_DESCRIPTOR(_eet_line_node);
FREE_DESCRIPTOR(_eet_custom_command_node);
}
static void
_svg_style_gradient_free(Svg_Style_Gradient *grad)
{
Efl_Gfx_Gradient_Stop *stop;
if (!grad) return;
eina_stringshare_del(grad->id);
eina_stringshare_del(grad->ref);
free(grad->radial);
free(grad->linear);
if (grad->transform) free(grad->transform);
EINA_LIST_FREE(grad->stops, stop)
{
free(stop);
}
free(grad);
}
static void
_node_style_free(Svg_Style_Property *style)
{
if (!style) return;
_svg_style_gradient_free(style->fill.paint.gradient);
eina_stringshare_del(style->fill.paint.url);
_svg_style_gradient_free(style->stroke.paint.gradient);
eina_stringshare_del(style->stroke.paint.url);
if (style->stroke.dash) free(style->stroke.dash);
free(style);
}
void
vg_common_svg_node_free(Svg_Node *node)
{
Svg_Node *child;
Svg_Style_Gradient *grad;
if (!node) return;
EINA_LIST_FREE(node->child, child)
{
vg_common_svg_node_free(child);
}
eina_stringshare_del(node->id);
free(node->transform);
_node_style_free(node->style);
switch (node->type)
{
case SVG_NODE_PATH:
eina_stringshare_del(node->node.path.path);
break;
case SVG_NODE_POLYGON:
free(node->node.polygon.points);
break;
case SVG_NODE_POLYLINE:
free(node->node.polyline.points);
break;
case SVG_NODE_DOC:
vg_common_svg_node_free(node->node.doc.defs);
break;
case SVG_NODE_DEFS:
EINA_LIST_FREE(node->node.defs.gradients, grad)
{
_svg_style_gradient_free(grad);
}
2020-06-01 17:59:51 -07:00
break;
case SVG_NODE_CUSTOME_COMMAND:
if (node->node.command.commands) free(node->node.command.commands);
2020-06-01 17:59:51 -07:00
if (node->node.command.points) free(node->node.command.points);
break;
default:
break;
}
free(node);
}
static Efl_VG *
_apply_gradient_property(Svg_Style_Gradient *g, Efl_VG *vg, Efl_VG *parent, Vg_File_Data *vg_data, int fill_opacity)
{
Efl_VG *grad_obj = NULL;
Efl_Gfx_Gradient_Stop *stops, *stop;
int stop_count = 0, i = 0;
Eina_List *l;
Eina_Matrix3 m; //for bbox translation
Eina_Rect r = EINA_RECT( 0, 0, 1, 1 );
Eina_Rect grad_geom = EINA_RECT(0, 0, 0, 0);
int radius;
//TODO: apply actual sizes (imporve bounds_get function?)...
//for example with figures and paths
if (!g->user_space)
efl_gfx_path_bounds_get(vg, &r);
else
{
r.w = vg_data->view_box.w;
r.h = vg_data->view_box.h;
}
if (g->type == SVG_LINEAR_GRADIENT)
{
grad_obj = efl_add(EFL_CANVAS_VG_GRADIENT_LINEAR_CLASS, parent);
if (g->use_percentage)
{
g->linear->x1 = g->linear->x1 * r.w + r.x;
g->linear->y1 = g->linear->y1 * r.h + r.y;
g->linear->x2 = g->linear->x2 * r.w + r.x;
g->linear->y2 = g->linear->y2 * r.h + r.y;
}
if (g->transform)
{
double cy = ((double) r.h) * 0.5 + r.y;
double cx = ((double) r.w) * 0.5 + r.x;
//Calc start point
eina_matrix3_identity(&m);
eina_matrix3_translate(&m, g->linear->x1 - cx, g->linear->y1 - cy);
eina_matrix3_multiply_copy(&m, g->transform , &m);
eina_matrix3_translate(&m, cx, cy);
eina_matrix3_values_get(&m, NULL, NULL, &g->linear->x1,
NULL, NULL, &g->linear->y1,
NULL, NULL, NULL);
//Calc end point
eina_matrix3_identity(&m);
eina_matrix3_translate(&m, g->linear->x2 - cx, g->linear->y2 - cy);
eina_matrix3_multiply_copy(&m, g->transform , &m);
eina_matrix3_translate(&m, cx, cy);
eina_matrix3_values_get(&m, NULL, NULL, &g->linear->x2,
NULL, NULL, &g->linear->y2,
NULL, NULL, NULL);
}
efl_gfx_gradient_linear_start_set(grad_obj, g->linear->x1, g->linear->y1);
efl_gfx_gradient_linear_end_set(grad_obj, g->linear->x2, g->linear->y2);
}
else if (g->type == SVG_RADIAL_GRADIENT)
{
radius = sqrt(pow(r.w, 2) + pow(r.h, 2)) / sqrt(2.0);
if (!g->user_space)
{
/**
* That is according to Units in here
*
* https://www.w3.org/TR/2015/WD-SVG2-20150915/coords.html
*/
int min = (r.h > r.w) ? r.w : r.h;
radius = sqrt(pow(min, 2) + pow(min, 2)) / sqrt(2.0);
}
if (g->use_percentage)
{
g->radial->cx = g->radial->cx * r.w + r.x;
g->radial->cy = g->radial->cy * r.h + r.y;
g->radial->r = g->radial->r * radius;
g->radial->fx = g->radial->fx * r.w + r.x;
g->radial->fy = g->radial->fy * r.h + r.y;
}
grad_obj = efl_add(EFL_CANVAS_VG_GRADIENT_RADIAL_CLASS, parent);
efl_gfx_gradient_radial_center_set(grad_obj, g->radial->cx, g->radial->cy);
efl_gfx_gradient_radial_radius_set(grad_obj, g->radial->r);
efl_gfx_gradient_radial_focal_set(grad_obj, g->radial->fx, g->radial->fy);
/* in case of objectBoundingBox it need proper scaling */
if (!g->user_space)
{
double scale_X = 1.0, scale_reversed_X = 1.0;
double scale_Y = 1.0, scale_reversed_Y = 1.0;
/* check the smallest size, find the scale value */
if (r.h > r.w)
{
scale_Y = ((double) r.w) / r.h;
scale_reversed_Y = ((double) r.h) / r.w;
}
else
{
scale_X = ((double) r.h) / r.w;
scale_reversed_X = ((double) r.w) / r.h;
}
efl_gfx_path_bounds_get(grad_obj, &grad_geom);
double cy = ((double) grad_geom.h) * 0.5 + grad_geom.y;
double cy_scaled = (((double) grad_geom.h) * 0.5) * scale_reversed_Y;
double cx = ((double) grad_geom.w) * 0.5 + grad_geom.x;
double cx_scaled = (((double) grad_geom.w) * 0.5) * scale_reversed_X;
/* matrix tranformation of gradient figure:
* 0. we remember size of gradient and it's center point
* 1. move all gradients to point {0;0}
* (so scale wont increase starting point)
* 2. scale properly only according to the bigger size of entity
* 3. move back so new center point would stay on position
* it had previously
*/
eina_matrix3_identity(&m);
eina_matrix3_translate(&m, grad_geom.x, grad_geom.y);
eina_matrix3_scale(&m, scale_X, scale_Y);
eina_matrix3_translate(&m, cx_scaled - cx, cy_scaled - cy);
efl_canvas_vg_node_transformation_set(grad_obj, &m);
}
}
else
{
// not a known gradient
return NULL;
}
// apply common prperty
efl_gfx_gradient_spread_set(grad_obj, g->spread);
// update the stops
stop_count = eina_list_count(g->stops);
if (stop_count)
{
double opacity;
double fopacity = ((double) fill_opacity) / 255; //fill opacity if any exists.
stops = calloc(stop_count, sizeof(Efl_Gfx_Gradient_Stop));
i = 0;
double prevOffset = 0;
EINA_LIST_FOREACH(g->stops, l, stop)
{
// Use premultiplied color
opacity = ((double) stop->a / 255) * fopacity;
stops[i].r = (stop->r * opacity);
stops[i].g = (stop->g * opacity);
stops[i].b = (stop->b * opacity);
stops[i].a = (stop->a * fopacity);
stops[i].offset = stop->offset;
//NOTE: check the offset corner cases - refer to: https://svgwg.org/svg2-draft/pservers.html#StopNotes
if (stop->offset < prevOffset)
{
stops[i].offset = prevOffset;
}
else if (stop->offset > 1)
{
stops[i].offset = 1;
}
prevOffset = stops[i].offset;
i++;
}
efl_gfx_gradient_stop_set(grad_obj, stops, stop_count);
free(stops);
}
return grad_obj;
}
// vg tree creation
static void
_apply_vg_property(Svg_Node *node, Efl_VG *vg, Efl_VG *parent, Vg_File_Data *vg_data)
{
Svg_Style_Property *style = node->style;
// update the vg name
if (node->id) efl_name_set(vg, node->id);
// apply the transformation
if (node->transform) efl_canvas_vg_node_transformation_set(vg, node->transform);
if (node->type != SVG_NODE_DOC && !node->display) efl_gfx_entity_visible_set(vg, EINA_FALSE);
evas_vg_load_svg: Support "display" attribute. Summary: If the display attribute is "none", VG object is not show. The default is "inline" which means visible and "none" means invisible. Depending on the type of node, additional functionality may be required. refer to https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/display Test Plan: [SVG] <svg viewBox="0 0 220 100" xmlns="http://www.w3.org/2000/svg"> <!-- Here the yellow rectangle is displayed --> <g display="none"> <rect x="0" y="0" width="100" height="100" fill="skyblue"></rect> </g> <rect x="20" y="20" width="60" height="60" fill="yellow"></rect> <!-- Here the yellow rectangle is not displayed --> <rect x="120" y="0" width="100" height="100" fill="skyblue"></rect> <rect x="140" y="20" width="60" height="60" fill="yellow" display="none"></rect> </svg> [C CODE] int main(int argc, char **argv) { setenv("ECTOR_BACKEND", "default", 1); elm_init(argc, argv); Evas_Object *win = elm_win_util_standard_add(NULL, "test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); elm_win_autodel_set(win, 1); Evas *evas = evas_object_evas_get(win); Evas_Object *vg = evas_object_vg_add(evas); evas_object_show(vg); Evas_Object *container = evas_vg_container_add(vg); evas_object_vg_root_node_set(vg, container); Evas_Object *svg = efl_add(EFL_CANVAS_VG_OBJECT_CLASS, container); efl_file_simple_load(svg, "./test.svg", NULL); efl_gfx_entity_size_set(svg, EINA_SIZE2D(600, 600)); efl_gfx_entity_visible_set(svg, EINA_TRUE); evas_object_size_hint_weight_set(svg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(svg, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(win, vg); evas_object_resize(win, WIDTH, HEIGHT); evas_object_show(win); elm_run(); elm_shutdown(); return 0; } Reviewers: Hermet, smohanty, kimcinoo Reviewed By: Hermet Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9640
2019-08-20 04:32:15 -07:00
if (node->type == SVG_NODE_DOC) return;
// if fill property is NULL then do nothing
if (style->fill.paint.none)
{
//do nothing
}
else if (style->fill.paint.gradient)
{
Efl_VG *gradient = _apply_gradient_property(style->fill.paint.gradient, vg, parent, vg_data, style->fill.opacity);
efl_canvas_vg_shape_fill_set(vg, gradient);
}
else if (style->fill.paint.cur_color)
{
// apply the current style color
float fa = ((float) style->fill.opacity / 255);
efl_gfx_color_set(vg, ((float) style->r) * fa, ((float) style->g) * fa, ((float) style->b) * fa,
style->fill.opacity);
}
else
{
// apply the fill color
float fa = ((float) style->fill.opacity / 255);
efl_gfx_color_set(vg, ((float) style->fill.paint.r) * fa, ((float) style->fill.paint.g) * fa,
((float) style->fill.paint.b) * fa, style->fill.opacity);
}
//apply node opacity
if (style->opacity < 255)
{
int r, g, b, a;
efl_gfx_color_get(vg, &r, &g, &b, &a);
float fa = ((float) style->opacity / 255);
efl_gfx_color_set(vg, ((float) r) * fa, ((float) g) * fa, ((float) b) * fa, ((float) a) * fa);
}
if (node->type == SVG_NODE_G || node->type == SVG_NODE_CLIP_PATH) return;
// apply the fill style property
efl_gfx_shape_fill_rule_set(vg, style->fill.fill_rule);
efl_gfx_shape_stroke_width_set(vg, style->stroke.width);
efl_gfx_shape_stroke_cap_set(vg, style->stroke.cap);
efl_gfx_shape_stroke_join_set(vg, style->stroke.join);
efl_gfx_shape_stroke_scale_set(vg, style->stroke.scale);
if (style->stroke.dash && style->stroke.dash_count > 0)
efl_gfx_shape_stroke_dash_set(vg, style->stroke.dash, style->stroke.dash_count);
// if stroke property is NULL then do nothing
if (style->stroke.paint.none)
{
//do nothing
}
else if (style->stroke.paint.gradient)
{
// if the fill has gradient then apply.
Efl_VG *gradient = _apply_gradient_property(style->stroke.paint.gradient, vg, parent, vg_data, 255);
efl_canvas_vg_shape_stroke_fill_set(vg, gradient);
}
else if (style->stroke.paint.url)
{
// apply the color pointed by url
// TODO
}
else if (style->stroke.paint.cur_color)
{
// apply the current style color
efl_gfx_shape_stroke_color_set(vg, style->r, style->g,
style->b, style->stroke.opacity);
}
else
{
// apply the stroke color
efl_gfx_shape_stroke_color_set(vg, style->stroke.paint.r, style->stroke.paint.g,
style->stroke.paint.b, style->stroke.opacity);
}
vg_common_svg: Apply node opacity to stroke color Summary: When an object to be converted to a stroke or path uses "opacity" attribute, opacity is also applied. Test Plan: [SVG] <?xml version="1.0" encoding="UTF-8"?> <svg width="40px" height="40px" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <!-- Generator: Sketch 52.6 (67491) - http://www.bohemiancoding.com/sketch --> <rect fill="#FF0000" opacity="0" x="0" y="0" width="40" height="40"></rect> <path d="M12,20 L25,8 L12,20 Z M12,20 L25,32 L12,20 Z" id="Combined-Shape" stroke="#FFFFFF" stroke-width="2" opacity="0.12" stroke-linecap="round" stroke-linejoin="round" fill-rule="nonzero"></path> </svg> [Code] int main(int argc, char **argv) { setenv("ECTOR_BACKEND", "default", 1); elm_init(argc, argv); Evas_Object *win = elm_win_util_standard_add(NULL, "test"); evas_object_smart_callback_add(win, "delete,request", win_del, 0); elm_win_autodel_set(win, 1); Evas *evas = evas_object_evas_get(win); Evas_Object *vg = evas_object_vg_add(evas); evas_object_show(vg); Evas_Object *container = evas_vg_container_add(vg); evas_object_vg_root_node_set(vg, container); Evas_Object *svg = efl_add(EFL_CANVAS_VG_OBJECT_CLASS, container); efl_file_simple_load(svg, "./i_arrow_l_disable.svg", NULL); efl_gfx_entity_size_set(svg, EINA_SIZE2D(600, 600)); efl_gfx_entity_visible_set(svg, EINA_TRUE); evas_object_size_hint_weight_set(svg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(svg, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(win, vg); evas_object_resize(win, 600, 600); evas_object_show(win); elm_run(); elm_shutdown(); return 0; } Reviewers: Hermet, smohanty, kimcinoo Reviewed By: Hermet Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9620
2019-08-19 03:46:01 -07:00
//apply node opacity to stroke color
if (style->opacity < 255)
{
int r, g, b, a;
efl_gfx_shape_stroke_color_get(vg, &r, &g, &b, &a);
float fa = ((float) style->opacity / 255);
efl_gfx_shape_stroke_color_set(vg, ((float) r) * fa, ((float) g) * fa, ((float) b) * fa, ((float) a) * fa);
}
}
static void
_add_polyline(Efl_VG *vg, double *array, int size, Eina_Bool polygon)
{
int i;
if (size < 2) return;
efl_gfx_path_append_move_to(vg, array[0], array[1]);
for (i = 2; i < size - 1; i += 2)
efl_gfx_path_append_line_to(vg, array[i], array[i+1]);
if (polygon)
efl_gfx_path_append_close(vg);
}
static Efl_VG *
_create_vg_container(Efl_VG *parent)
{
if (!parent)
return efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
else
return efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, parent);
}
static Efl_VG *
vg_common_create_vg_node_helper(Svg_Node *node, Efl_VG *parent, Vg_File_Data *vg_data)
{
Efl_VG *vg = NULL;
Svg_Node *child;
Eina_List *l;
// apply composite node
if (node->style->comp.node)
{
// composite ClipPath
if (node->style->comp.flags & SVG_COMPOSITE_FLAGS_CLIP_PATH)
{
Svg_Node *comp_node = node->style->comp.node;
Efl_VG *comp_parent = NULL ,*comp_vg_container = NULL;
//NOTE:: If node has a composition node, add a container to use VG_COMPOSITION_METHOD.
// The composition method is applied to the newly added container.
comp_parent = _create_vg_container(parent);
comp_vg_container = _create_vg_container(parent);
// apply the transformation
if (comp_node->transform) efl_canvas_vg_node_transformation_set(comp_vg_container, comp_node->transform);
EINA_LIST_FOREACH(comp_node->child, l, child)
{
Efl_VG *vg = vg_common_create_vg_node_helper(child, comp_vg_container, vg_data);
// clippath does not require color blending. That's why we keep 255 opacity.
efl_gfx_color_set(vg, 255, 255, 255, 255);
}
// Composition matte alpha
efl_canvas_vg_node_comp_method_set(comp_parent, comp_vg_container, EFL_GFX_VG_COMPOSITE_METHOD_MATTE_ALPHA);
parent = comp_parent; // replace parent
}
}
switch (node->type)
{
case SVG_NODE_DOC:
case SVG_NODE_G:
{
if (!parent)
vg = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
else
vg = efl_add(EFL_CANVAS_VG_CONTAINER_CLASS, parent);
_apply_vg_property(node, vg, parent, vg_data);
EINA_LIST_FOREACH(node->child, l, child)
vg_common_create_vg_node_helper(child, vg, vg_data);
return vg;
}
break;
case SVG_NODE_PATH:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
efl_gfx_path_append_svg_path(vg, node->node.path.path);
break;
case SVG_NODE_POLYGON:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
_add_polyline(vg, node->node.polygon.points, node->node.polygon.points_count, EINA_TRUE);
break;
case SVG_NODE_POLYLINE:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
_add_polyline(vg, node->node.polygon.points, node->node.polygon.points_count, EINA_FALSE);
break;
case SVG_NODE_ELLIPSE:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
efl_gfx_path_append_arc(vg, node->node.ellipse.cx - node->node.ellipse.rx,
node->node.ellipse.cy - node->node.ellipse.ry,
2*node->node.ellipse.rx, 2*node->node.ellipse.ry, 0, 360);
efl_gfx_path_append_close(vg);
break;
case SVG_NODE_CIRCLE:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
efl_gfx_path_append_circle(vg, node->node.circle.cx, node->node.circle.cy, node->node.circle.r);
break;
case SVG_NODE_RECT:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
efl_gfx_path_append_rect(vg, node->node.rect.x, node->node.rect.y, node->node.rect.w, node->node.rect.h,
node->node.rect.rx, node->node.rect.ry);
break;
case SVG_NODE_LINE:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
efl_gfx_path_append_move_to(vg, node->node.line.x1, node->node.line.y1);
efl_gfx_path_append_line_to(vg, node->node.line.x2, node->node.line.y2);
break;
case SVG_NODE_CUSTOME_COMMAND:
vg = efl_add(EFL_CANVAS_VG_SHAPE_CLASS, parent);
efl_gfx_path_set(vg, node->node.command.commands, node->node.command.points);
break;
default:
break;
}
if (vg)
_apply_vg_property(node, vg, parent, vg_data);
return vg;
}
Vg_File_Data *
vg_common_svg_create_vg_node(Svg_Node *node)
{
Vg_File_Data *vg_data;
if (!node || (node->type != SVG_NODE_DOC)) return NULL;
vg_data = calloc(1, sizeof(Vg_File_Data));
2019-02-17 22:07:01 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL(vg_data, NULL);
vg_data->view_box.x = node->node.doc.vx;
vg_data->view_box.y = node->node.doc.vy;
vg_data->view_box.w = node->node.doc.vw;
vg_data->view_box.h = node->node.doc.vh;
vg_data->preserve_aspect = node->node.doc.preserve_aspect;
vg_data->static_viewbox = EINA_TRUE;
vg_data->root = vg_common_create_vg_node_helper(node, NULL, vg_data);
return vg_data;
}
static Svg_Node *
_create_node(Svg_Node *parent, Svg_Node_Type type)
{
Svg_Node *node = calloc(1, sizeof(Svg_Node));
2019-02-17 22:07:01 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL(node, NULL);
// default fill property
node->style = calloc(1, sizeof(Svg_Style_Property));
2019-02-17 22:09:44 -08:00
if (!node->style)
{
free(node);
ERR("OOM: Failed calloc()");
return NULL;
2019-02-17 22:09:44 -08:00
}
// update the default value of stroke and fill
//https://www.w3.org/TR/SVGTiny12/painting.html#SpecifyingPaint
// default fill color is black
node->style->fill.paint.r = 0;
node->style->fill.paint.g = 0;
node->style->fill.paint.b = 0;
node->style->fill.paint.none = EINA_FALSE;
// default fill opacity is 1
node->style->fill.opacity = 255;
// default fill rule is nonzero
node->style->fill.fill_rule = EFL_GFX_FILL_RULE_WINDING;
// default stroke is none
node->style->stroke.paint.none = EINA_TRUE;
// default stroke opacity is 1
node->style->stroke.opacity = 255;
// default stroke width is 1
node->style->stroke.width = 1;
// default line cap is butt
node->style->stroke.cap = EFL_GFX_CAP_BUTT;
// default line join is miter
node->style->stroke.join = EFL_GFX_JOIN_MITER;
node->style->stroke.scale = 1.0;
node->style->opacity = 255;
node->parent = parent;
node->type = type;
node->child = NULL;
if (parent)
parent->child = eina_list_append(parent->child, node);
return node;
}
static Svg_Style_Gradient*
_create_gradient_node(Efl_VG *vg)
{
const Efl_Gfx_Gradient_Stop *stops = NULL;
Efl_Gfx_Gradient_Stop *new_stop;
unsigned int count = 0, i;
Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient));
2019-02-17 22:02:47 -08:00
EINA_SAFETY_ON_NULL_RETURN_VAL(grad, NULL);
grad->spread = efl_gfx_gradient_spread_get(vg);
efl_gfx_gradient_stop_get(vg, &stops, &count);
for (i = 0; i < count; i++)
{
new_stop = calloc(1, sizeof(Efl_Gfx_Gradient_Stop));
2019-02-17 22:17:41 -08:00
if (!new_stop) goto oom_error;
memcpy(new_stop, stops, sizeof(Efl_Gfx_Gradient_Stop));
grad->stops = eina_list_append(grad->stops, new_stop);
stops++;
}
if (efl_isa(vg, EFL_CANVAS_VG_GRADIENT_LINEAR_CLASS))
{
grad->type = SVG_LINEAR_GRADIENT;
grad->linear = calloc(1, sizeof(Svg_Linear_Gradient));
2019-02-17 22:17:41 -08:00
if (!grad->linear) goto oom_error;
efl_gfx_gradient_linear_start_get(vg, &grad->linear->x1, &grad->linear->y1);
efl_gfx_gradient_linear_end_get(vg, &grad->linear->x2, &grad->linear->y2);
}
else
{
grad->type = SVG_RADIAL_GRADIENT;
grad->radial = calloc(1, sizeof(Svg_Radial_Gradient));
2019-02-17 22:17:41 -08:00
if (!grad->radial) goto oom_error;
efl_gfx_gradient_radial_center_get(vg, &grad->radial->cx, &grad->radial->cy);
efl_gfx_gradient_radial_focal_get(vg, &grad->radial->fx, &grad->radial->fy);
grad->radial->r = efl_gfx_gradient_radial_radius_get(vg);
}
grad->use_percentage = EINA_FALSE;
return grad;
2019-02-17 22:17:41 -08:00
oom_error:
ERR("OOM: Failed calloc()");
return grad;
}
static void
_apply_svg_property(Svg_Node *node, Efl_VG *vg)
{
const Eina_Matrix3 *matrix;
const char *id;
Svg_Style_Property *style = node->style;
// transformation
if ((matrix = efl_canvas_vg_node_transformation_get(vg)))
{
node->transform = calloc(1, sizeof(Eina_Matrix3));
eina_matrix3_copy(node->transform, matrix);
}
if ((id = efl_name_get(vg)))
{
node->id = eina_stringshare_add(id);
}
node->display = efl_gfx_entity_visible_get(vg);
if (node->type == SVG_NODE_G) return;
// apply the fill style property
style->fill.fill_rule = efl_gfx_shape_fill_rule_get(vg);
style->fill.paint.none = EINA_FALSE;
if (efl_canvas_vg_shape_fill_get(vg))
{
// if the fill has gradient then apply.
style->fill.paint.gradient = _create_gradient_node(efl_canvas_vg_shape_fill_get(vg));
}
else
{
efl_gfx_color_get(vg, &style->fill.paint.r, &style->fill.paint.g,
&style->fill.paint.b, &style->fill.opacity);
}
// apply stroke style property
style->stroke.paint.none = EINA_FALSE;
if (efl_canvas_vg_shape_stroke_fill_get(vg))
{
// if the stroke has gradient then apply.
style->stroke.paint.gradient = _create_gradient_node(efl_canvas_vg_shape_stroke_fill_get(vg));
}
else
{
// apply the stroke color
efl_gfx_shape_stroke_color_get(vg, &style->stroke.paint.r, &style->stroke.paint.g,
&style->stroke.paint.b, &style->stroke.opacity);
}
style->stroke.width = efl_gfx_shape_stroke_width_get(vg);
style->stroke.cap = efl_gfx_shape_stroke_cap_get(vg);
style->stroke.join = efl_gfx_shape_stroke_join_get(vg);
style->stroke.scale = efl_gfx_shape_stroke_scale_get(vg);
}
static void
vg_common_create_svg_node_helper(Efl_VG *vg, Svg_Node *parent)
{
Eina_Iterator *it;
Efl_VG *child;
Svg_Node *svg_node;
const Efl_Gfx_Path_Command *commands;
unsigned int points_count, commands_count;
const double *points;
if (efl_isa(vg, EFL_CANVAS_VG_CONTAINER_CLASS))
{
svg_node = _create_node(parent, SVG_NODE_G);
_apply_svg_property(svg_node, vg);
// apply property
it = efl_canvas_vg_container_children_get(vg);
EINA_ITERATOR_FOREACH(it, child)
{
vg_common_create_svg_node_helper(child, svg_node);
}
}
else if (efl_isa(vg, EFL_CANVAS_VG_SHAPE_CLASS))
{
svg_node = _create_node(parent, SVG_NODE_CUSTOME_COMMAND);
efl_gfx_path_get(vg, &commands, &points);
efl_gfx_path_length_get(vg, &commands_count, &points_count);
svg_node->node.command.commands_count = commands_count;
svg_node->node.command.points_count = points_count;
svg_node->node.command.points = calloc(points_count, sizeof(double));
svg_node->node.command.commands = calloc(commands_count, sizeof(Efl_Gfx_Path_Command));
memcpy(svg_node->node.command.commands, commands, sizeof (Efl_Gfx_Path_Command) * commands_count);
memcpy(svg_node->node.command.points, points, sizeof (double) * points_count);
_apply_svg_property(svg_node, vg);
}
}
Svg_Node *
vg_common_svg_create_svg_node(Vg_File_Data *node)
{
Svg_Node *doc;
if (!node || !node->root) return NULL;
doc = _create_node(NULL, SVG_NODE_DOC);
doc->node.doc.vx = node->view_box.x;
doc->node.doc.vy = node->view_box.y;
doc->node.doc.vw = node->view_box.w;
doc->node.doc.vh = node->view_box.h;
doc->node.doc.preserve_aspect = node->preserve_aspect;
vg_common_create_svg_node_helper(node->root, doc);
return doc;
}