summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitalii Vorobiov <vi.vorobiov@samsung.com>2017-02-17 13:00:54 +0200
committerJean-Philippe Andre <jp.andre@samsung.com>2017-11-07 11:54:09 +0900
commit6139aa78d5a48166a235087ecc49942b969b09af (patch)
treeb8bb1ce527029084d57ffa3f718dabb46b171326
parent1354c1c8ab53ab10e4da195aa1ac157c65ba6bf8 (diff)
svg_parse: implement <length> parse
Accodring to https://www.w3.org/TR/SVG/types.html#Length length ::= number ("em" | "ex" | "px" | "in" | "cm" | "mm" | "pt" | "pc" | "%") This is still work in progress since some of lengths should be treated differently, for example gradient lengths
-rw-r--r--src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c180
1 files changed, 112 insertions, 68 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 531cb05b9c..636b27fcb9 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
@@ -28,11 +28,23 @@ struct _Evas_SVG_Loader
28 Eina_Bool result:1; 28 Eina_Bool result:1;
29}; 29};
30 30
31/* length type to recalculate %, pt, pc, mm, cm etc*/
32typedef enum {
33 SVG_PARSER_LENGTH_VERTICAL,
34 SVG_PARSER_LENGTH_HORIZONTAL,
35 /* in case of, for example, radius of radial gradient */
36 SVG_PARSER_LENGTH_OTHER
37} SVG_Parser_Length_Type;
38
31/* Global struct for working global cases during the parse */ 39/* Global struct for working global cases during the parse */
32typedef struct { 40typedef struct {
33 struct { 41 struct {
34 int x, y, width, height; 42 int x, y, width, height;
35 } global; 43 } global;
44 struct {
45 Eina_Bool fx_parsed;
46 Eina_Bool fy_parsed;
47 } gradient;
36} Evas_SVG_Parsing; 48} Evas_SVG_Parsing;
37static Evas_SVG_Parsing svg_parse; 49static Evas_SVG_Parsing svg_parse;
38 50
@@ -73,10 +85,58 @@ _parse_number(const char **content, double *number)
73 return EINA_TRUE; 85 return EINA_TRUE;
74} 86}
75 87
88/**
89 * According to https://www.w3.org/TR/SVG/coords.html#Units
90 *
91 * TODO
92 * Since this documentation is not obvious, more clean recalculation with dpi
93 * is required, but for now default w3 constants would be used
94 */
76static inline double 95static inline double
77_to_double(const char *str) 96_to_double(const char *str, SVG_Parser_Length_Type type)
97{
98 double parsed_value = strtod(str, NULL);
99
100 if (strstr(str, "cm"))
101 parsed_value = parsed_value * 35.43307;
102 else if (strstr(str, "mm"))
103 parsed_value = parsed_value * 3.543307;
104 else if (strstr(str, "pt"))
105 parsed_value = parsed_value * 1.25;
106 else if (strstr(str, "pc"))
107 parsed_value = parsed_value * 15;
108 else if (strstr(str, "in"))
109 parsed_value = parsed_value * 90;
110 else if (strstr(str, "%"))
111 {
112 if (type == SVG_PARSER_LENGTH_VERTICAL)
113 parsed_value = (parsed_value / 100.0) * svg_parse.global.height;
114 else if (type == SVG_PARSER_LENGTH_HORIZONTAL)
115 parsed_value = (parsed_value / 100.0) * svg_parse.global.width;
116 else // if other then it's radius
117 {
118 double max = svg_parse.global.width;
119 if (max < svg_parse.global.height) max = svg_parse.global.height;
120 parsed_value = (parsed_value / 100.0) * max;
121 }
122 }
123
124 //TODO: implement 'em', 'ex' attributes
125
126 return parsed_value;
127}
128
129static inline int
130_to_offset(const char *str)
78{ 131{
79 return strtod(str, NULL); 132 char *end = NULL;
133
134 double parsed_value = strtod(str, &end);
135
136 if (strstr(str, "%"))
137 parsed_value = parsed_value / 100.0;
138
139 return parsed_value;
80} 140}
81 141
82static inline int 142static inline int
@@ -752,7 +812,7 @@ static void
752_handle_stroke_width_attr(Svg_Node* node, const char *value) 812_handle_stroke_width_attr(Svg_Node* node, const char *value)
753{ 813{
754 node->style->stroke.flags |= SVG_STROKE_FLAGS_WIDTH; 814 node->style->stroke.flags |= SVG_STROKE_FLAGS_WIDTH;
755 node->style->stroke.width = _to_double(value); 815 node->style->stroke.width = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL);
756} 816}
757 817
758static void 818static void
@@ -985,17 +1045,18 @@ _create_path_node(Svg_Node *parent, const char *buf, unsigned buflen)
985 return node; 1045 return node;
986} 1046}
987 1047
988#define CIRCLE_DEF(Name, Field) \ 1048#define CIRCLE_DEF(Name, Field, Type) \
989 { #Name, sizeof (#Name), offsetof(Svg_Circle_Node, Field)} 1049 { #Name, sizeof (#Name), offsetof(Svg_Circle_Node, Field)}
990 1050
991static const struct { 1051static const struct {
992 const char *tag; 1052 const char *tag;
1053 SVG_Parser_Length_Type type;
993 int sz; 1054 int sz;
994 size_t offset; 1055 size_t offset;
995} circle_tags[] = { 1056} circle_tags[] = {
996 CIRCLE_DEF(cx, cx), 1057 CIRCLE_DEF(cx, cx, SVG_PARSER_LENGTH_HORIZONTAL),
997 CIRCLE_DEF(cy, cy), 1058 CIRCLE_DEF(cy, cy, SVG_PARSER_LENGTH_VERTICAL),
998 CIRCLE_DEF(r, r) 1059 CIRCLE_DEF(r, r, SVG_PARSER_LENGTH_OTHER)
999}; 1060};
1000 1061
1001/* parse the attributes for a circle element. 1062/* parse the attributes for a circle element.
@@ -1014,7 +1075,7 @@ _attr_parse_circle_node(void *data, const char *key, const char *value)
1014 for (i = 0; i < sizeof (circle_tags) / sizeof(circle_tags[0]); i++) 1075 for (i = 0; i < sizeof (circle_tags) / sizeof(circle_tags[0]); i++)
1015 if (circle_tags[i].sz - 1 == sz && !strncmp(circle_tags[i].tag, key, sz)) 1076 if (circle_tags[i].sz - 1 == sz && !strncmp(circle_tags[i].tag, key, sz))
1016 { 1077 {
1017 *((double*) (array + circle_tags[i].offset)) = _to_double(value); 1078 *((double*) (array + circle_tags[i].offset)) = _to_double(value, circle_tags[i].type);
1018 return EINA_TRUE; 1079 return EINA_TRUE;
1019 } 1080 }
1020 1081
@@ -1043,18 +1104,19 @@ _create_circle_node(Svg_Node *parent, const char *buf, unsigned buflen)
1043 return node; 1104 return node;
1044} 1105}
1045 1106
1046#define ELLIPSE_DEF(Name, Field) \ 1107#define ELLIPSE_DEF(Name, Field, Type) \
1047 { #Name, sizeof (#Name), offsetof(Svg_Ellipse_Node, Field)} 1108 { #Name, Type, sizeof (#Name), offsetof(Svg_Ellipse_Node, Field)}
1048 1109
1049static const struct { 1110static const struct {
1050 const char *tag; 1111 const char *tag;
1112 SVG_Parser_Length_Type type;
1051 int sz; 1113 int sz;
1052 size_t offset; 1114 size_t offset;
1053} ellipse_tags[] = { 1115} ellipse_tags[] = {
1054 ELLIPSE_DEF(cx,cx), 1116 ELLIPSE_DEF(cx,cx, SVG_PARSER_LENGTH_HORIZONTAL),
1055 ELLIPSE_DEF(cy,cy), 1117 ELLIPSE_DEF(cy,cy, SVG_PARSER_LENGTH_VERTICAL),
1056 ELLIPSE_DEF(rx,rx), 1118 ELLIPSE_DEF(rx,rx, SVG_PARSER_LENGTH_HORIZONTAL),
1057 ELLIPSE_DEF(ry,ry) 1119 ELLIPSE_DEF(ry,ry, SVG_PARSER_LENGTH_VERTICAL)
1058}; 1120};
1059 1121
1060/* parse the attributes for an ellipse element. 1122/* parse the attributes for an ellipse element.
@@ -1073,7 +1135,7 @@ _attr_parse_ellipse_node(void *data, const char *key, const char *value)
1073 for (i = 0; i < sizeof (ellipse_tags) / sizeof(ellipse_tags[0]); i++) 1135 for (i = 0; i < sizeof (ellipse_tags) / sizeof(ellipse_tags[0]); i++)
1074 if (ellipse_tags[i].sz - 1 == sz && !strncmp(ellipse_tags[i].tag, key, sz)) 1136 if (ellipse_tags[i].sz - 1 == sz && !strncmp(ellipse_tags[i].tag, key, sz))
1075 { 1137 {
1076 *((double*) (array + ellipse_tags[i].offset)) = _to_double(value); 1138 *((double*) (array + ellipse_tags[i].offset)) = _to_double(value, ellipse_tags[i].type);
1077 return EINA_TRUE; 1139 return EINA_TRUE;
1078 } 1140 }
1079 1141
@@ -1196,20 +1258,21 @@ _create_polyline_node(Svg_Node *parent, const char *buf, unsigned buflen)
1196 return node; 1258 return node;
1197} 1259}
1198 1260
1199#define RECT_DEF(Name, Field) \ 1261#define RECT_DEF(Name, Field, Type) \
1200 { #Name, sizeof (#Name), offsetof(Svg_Rect_Node, Field)} 1262 { #Name, Type, sizeof (#Name), offsetof(Svg_Rect_Node, Field)}
1201 1263
1202static const struct { 1264static const struct {
1203 const char *tag; 1265 const char *tag;
1266 SVG_Parser_Length_Type type;
1204 int sz; 1267 int sz;
1205 size_t offset; 1268 size_t offset;
1206} rect_tags[] = { 1269} rect_tags[] = {
1207 RECT_DEF(x,x), 1270 RECT_DEF(x,x, SVG_PARSER_LENGTH_HORIZONTAL),
1208 RECT_DEF(y, y), 1271 RECT_DEF(y, y, SVG_PARSER_LENGTH_VERTICAL),
1209 RECT_DEF(width, w), 1272 RECT_DEF(width, w, SVG_PARSER_LENGTH_HORIZONTAL),
1210 RECT_DEF(height, h), 1273 RECT_DEF(height, h, SVG_PARSER_LENGTH_VERTICAL),
1211 RECT_DEF(rx, rx), 1274 RECT_DEF(rx, rx, SVG_PARSER_LENGTH_HORIZONTAL),
1212 RECT_DEF(ry, ry) 1275 RECT_DEF(ry, ry, SVG_PARSER_LENGTH_VERTICAL)
1213}; 1276};
1214 1277
1215/* parse the attributes for a rect element. 1278/* parse the attributes for a rect element.
@@ -1228,7 +1291,7 @@ _attr_parse_rect_node(void *data, const char *key, const char *value)
1228 for (i = 0; i < sizeof (rect_tags) / sizeof(rect_tags[0]); i++) 1291 for (i = 0; i < sizeof (rect_tags) / sizeof(rect_tags[0]); i++)
1229 if (rect_tags[i].sz - 1 == sz && !strncmp(rect_tags[i].tag, key, sz)) 1292 if (rect_tags[i].sz - 1 == sz && !strncmp(rect_tags[i].tag, key, sz))
1230 { 1293 {
1231 *((double*) (array + rect_tags[i].offset)) = _to_double(value); 1294 *((double*) (array + rect_tags[i].offset)) = _to_double(value, rect_tags[i].type);
1232 return EINA_TRUE; 1295 return EINA_TRUE;
1233 } 1296 }
1234 1297
@@ -1261,18 +1324,19 @@ _create_rect_node(Svg_Node *parent, const char *buf, unsigned buflen)
1261 return node; 1324 return node;
1262} 1325}
1263 1326
1264#define LINE_DEF(Name, Field) \ 1327#define LINE_DEF(Name, Field, Type) \
1265 { #Name, sizeof (#Name), offsetof(Svg_Line_Node, Field)} 1328 { #Name, Type, sizeof (#Name), offsetof(Svg_Line_Node, Field)}
1266 1329
1267static const struct { 1330static const struct {
1268 const char *tag; 1331 const char *tag;
1332 SVG_Parser_Length_Type type;
1269 int sz; 1333 int sz;
1270 size_t offset; 1334 size_t offset;
1271} line_tags[] = { 1335} line_tags[] = {
1272 LINE_DEF(x1, x1), 1336 LINE_DEF(x1, x1, SVG_PARSER_LENGTH_HORIZONTAL),
1273 LINE_DEF(y1, y1), 1337 LINE_DEF(y1, y1, SVG_PARSER_LENGTH_VERTICAL),
1274 LINE_DEF(x2, x2), 1338 LINE_DEF(x2, x2, SVG_PARSER_LENGTH_HORIZONTAL),
1275 LINE_DEF(y2, y2) 1339 LINE_DEF(y2, y2, SVG_PARSER_LENGTH_VERTICAL)
1276}; 1340};
1277 1341
1278/* parse the attributes for a rect element. 1342/* parse the attributes for a rect element.
@@ -1291,7 +1355,7 @@ _attr_parse_line_node(void *data, const char *key, const char *value)
1291 for (i = 0; i < sizeof (line_tags) / sizeof(line_tags[0]); i++) 1355 for (i = 0; i < sizeof (line_tags) / sizeof(line_tags[0]); i++)
1292 if (line_tags[i].sz - 1 == sz && !strncmp(line_tags[i].tag, key, sz)) 1356 if (line_tags[i].sz - 1 == sz && !strncmp(line_tags[i].tag, key, sz))
1293 { 1357 {
1294 *((double*) (array + line_tags[i].offset)) = _to_double(value); 1358 *((double*) (array + line_tags[i].offset)) = _to_double(value, line_tags[i].type);
1295 return EINA_TRUE; 1359 return EINA_TRUE;
1296 } 1360 }
1297 1361
@@ -1518,6 +1582,7 @@ _create_use_node(Svg_Node *parent, const char *buf, unsigned buflen)
1518#define TAG_DEF(Name) \ 1582#define TAG_DEF(Name) \
1519 { #Name, sizeof (#Name), _create_##Name##_node } 1583 { #Name, sizeof (#Name), _create_##Name##_node }
1520 1584
1585//TODO: implement 'text' primitive
1521static const struct { 1586static const struct {
1522 const char *tag; 1587 const char *tag;
1523 int sz; 1588 int sz;
@@ -1579,58 +1644,40 @@ _parse_spread_value(const char *value)
1579 return spread; 1644 return spread;
1580} 1645}
1581 1646
1582
1583/**
1584 * Comment SVG_GRADIENT_FX_FY_PARSED
1585 *
1586 * if "fx" and "fy" is not specified then they are fx==cx and fy==cx
1587 * but we should also be careful when during the parsing it would be
1588 * something like <radialGradient fx="0" cx="100" cy="100">
1589 * so then fx is 0, but fy is 100
1590 *
1591 * So we need to check if focal was parsed, if not then set up same as center
1592 * point.
1593 *
1594 * It is required to set those public variables back to zero when parsing new
1595 * gradient.
1596 */
1597static Eina_Bool fx_parsed;
1598static Eina_Bool fy_parsed;
1599
1600static void 1647static void
1601_handle_radial_cx_attr(Svg_Radial_Gradient* radial, const char *value) 1648_handle_radial_cx_attr(Svg_Radial_Gradient* radial, const char *value)
1602{ 1649{
1603 radial->cx = _to_double(value); 1650 radial->cx = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL);
1604 if (!fx_parsed) 1651 if (!svg_parse.gradient.fx_parsed)
1605 radial->fx = radial->cx; 1652 radial->fx = radial->cx;
1606} 1653}
1607 1654
1608static void 1655static void
1609_handle_radial_cy_attr(Svg_Radial_Gradient* radial, const char *value) 1656_handle_radial_cy_attr(Svg_Radial_Gradient* radial, const char *value)
1610{ 1657{
1611 radial->cy = _to_double(value); 1658 radial->cy = _to_double(value, SVG_PARSER_LENGTH_VERTICAL);
1612 if (!fy_parsed) 1659 if (!svg_parse.gradient.fy_parsed)
1613 radial->fy = radial->cy; 1660 radial->fy = radial->cy;
1614} 1661}
1615 1662
1616static void 1663static void
1617_handle_radial_fx_attr(Svg_Radial_Gradient* radial, const char *value) 1664_handle_radial_fx_attr(Svg_Radial_Gradient* radial, const char *value)
1618{ 1665{
1619 radial->fx = _to_double(value); 1666 radial->fx = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL);
1620 fx_parsed = EINA_TRUE; 1667 svg_parse.gradient.fx_parsed = EINA_TRUE;
1621} 1668}
1622 1669
1623static void 1670static void
1624_handle_radial_fy_attr(Svg_Radial_Gradient* radial, const char *value) 1671_handle_radial_fy_attr(Svg_Radial_Gradient* radial, const char *value)
1625{ 1672{
1626 radial->fy = _to_double(value); 1673 radial->fy = _to_double(value, SVG_PARSER_LENGTH_VERTICAL);
1627 fy_parsed = EINA_TRUE; 1674 svg_parse.gradient.fy_parsed = EINA_TRUE;
1628} 1675}
1629 1676
1630static void 1677static void
1631_handle_radial_r_attr(Svg_Radial_Gradient* radial, const char *value) 1678_handle_radial_r_attr(Svg_Radial_Gradient* radial, const char *value)
1632{ 1679{
1633 radial->r = _to_double(value); 1680 radial->r = _to_double(value, SVG_PARSER_LENGTH_OTHER);
1634} 1681}
1635 1682
1636 1683
@@ -1694,11 +1741,8 @@ _create_radialGradient(const char *buf, unsigned buflen)
1694 grad->type = SVG_RADIAL_GRADIENT; 1741 grad->type = SVG_RADIAL_GRADIENT;
1695 grad->radial = calloc(1, sizeof(Svg_Radial_Gradient)); 1742 grad->radial = calloc(1, sizeof(Svg_Radial_Gradient));
1696 1743
1697 /** 1744 svg_parse.gradient.fx_parsed = EINA_FALSE;
1698 * Please see SVG_GRADIENT_FX_FY_PARSED comment for more info 1745 svg_parse.gradient.fy_parsed = EINA_FALSE;
1699 */
1700 fx_parsed = EINA_FALSE;
1701 fy_parsed = EINA_FALSE;
1702 eina_simple_xml_attributes_parse(buf, buflen, 1746 eina_simple_xml_attributes_parse(buf, buflen,
1703 _attr_parse_radial_gradient_node, grad); 1747 _attr_parse_radial_gradient_node, grad);
1704 1748
@@ -1713,7 +1757,7 @@ _attr_parse_stops(void *data, const char *key, const char *value)
1713 1757
1714 if (!strcmp(key, "offset")) 1758 if (!strcmp(key, "offset"))
1715 { 1759 {
1716 stop->offset = _to_double(value); 1760 stop->offset = _to_offset(value);
1717 } 1761 }
1718 else if (!strcmp(key, "stop-opacity")) 1762 else if (!strcmp(key, "stop-opacity"))
1719 { 1763 {
@@ -1735,25 +1779,25 @@ _attr_parse_stops(void *data, const char *key, const char *value)
1735static void 1779static void
1736_handle_linear_x1_attr(Svg_Linear_Gradient* linear, const char *value) 1780_handle_linear_x1_attr(Svg_Linear_Gradient* linear, const char *value)
1737{ 1781{
1738 linear->x1 = _to_double(value); 1782 linear->x1 = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL);
1739} 1783}
1740 1784
1741static void 1785static void
1742_handle_linear_y1_attr(Svg_Linear_Gradient* linear, const char *value) 1786_handle_linear_y1_attr(Svg_Linear_Gradient* linear, const char *value)
1743{ 1787{
1744 linear->y1 = _to_double(value); 1788 linear->y1 = _to_double(value, SVG_PARSER_LENGTH_VERTICAL);
1745} 1789}
1746 1790
1747static void 1791static void
1748_handle_linear_x2_attr(Svg_Linear_Gradient* linear, const char *value) 1792_handle_linear_x2_attr(Svg_Linear_Gradient* linear, const char *value)
1749{ 1793{
1750 linear->x2 = _to_double(value); 1794 linear->x2 = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL);
1751} 1795}
1752 1796
1753static void 1797static void
1754_handle_linear_y2_attr(Svg_Linear_Gradient* linear, const char *value) 1798_handle_linear_y2_attr(Svg_Linear_Gradient* linear, const char *value)
1755{ 1799{
1756 linear->y2 = _to_double(value); 1800 linear->y2 = _to_double(value, SVG_PARSER_LENGTH_VERTICAL);
1757} 1801}
1758 1802
1759 1803