summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitalii Vorobiov <vi.vorobiov@samsung.com>2017-02-17 17:00:01 +0200
committerJean-Philippe Andre <jp.andre@samsung.com>2017-11-07 11:54:09 +0900
commit405e56ac553db21f3e53d1702cc3db3863142811 (patch)
treec6ac76c18686aa95ce975234d8bb7946f4dc9e2a
parent6139aa78d5a48166a235087ecc49942b969b09af (diff)
svg_parse: parse linear gradient variables accroding to gradientUnits
There are difficult cases according to https://www.w3.org/TR/2000/CR-SVG-20000802/pservers.html
-rw-r--r--src/modules/evas/vg_loaders/svg/evas_vg_load_svg.c137
-rw-r--r--src/static_libs/vg_common/vg_common.h19
2 files changed, 146 insertions, 10 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 636b27fcb9..ff1b2d8e2d 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
@@ -42,6 +42,7 @@ typedef struct {
42 int x, y, width, height; 42 int x, y, width, height;
43 } global; 43 } global;
44 struct { 44 struct {
45 Eina_Bool x1_percent, x2_percent, y1_percent, y2_percent;
45 Eina_Bool fx_parsed; 46 Eina_Bool fx_parsed;
46 Eina_Bool fy_parsed; 47 Eina_Bool fy_parsed;
47 } gradient; 48 } gradient;
@@ -126,6 +127,48 @@ _to_double(const char *str, SVG_Parser_Length_Type type)
126 return parsed_value; 127 return parsed_value;
127} 128}
128 129
130/**
131 * Turn gradient variables into percentages
132 */
133static inline double
134_gradient_to_double(const char *str, SVG_Parser_Length_Type type)
135{
136 char *end = NULL;
137
138 double parsed_value = strtod(str, &end);
139 double max = 1;
140
141 /* unique case, if that is percentage, just return it */
142 if (strstr(str, "%"))
143 {
144 parsed_value = parsed_value / 100.0;
145 return parsed_value;
146 }
147
148 if (type == SVG_PARSER_LENGTH_VERTICAL)
149 max = svg_parse.global.height;
150 else if (type == SVG_PARSER_LENGTH_HORIZONTAL)
151 max = svg_parse.global.width;
152 //TODO: what about radial?
153
154 if (strstr(str, "cm"))
155 parsed_value = parsed_value * 35.43307;
156 else if (strstr(str, "mm"))
157 parsed_value = parsed_value * 3.543307;
158 else if (strstr(str, "pt"))
159 parsed_value = parsed_value * 1.25;
160 else if (strstr(str, "pc"))
161 parsed_value = parsed_value * 15;
162 else if (strstr(str, "in"))
163 parsed_value = parsed_value * 90;
164 //TODO: implement 'em', 'ex' attributes
165
166 /* Transform into global percentage */
167 parsed_value = parsed_value / max;
168
169 return parsed_value;
170}
171
129static inline int 172static inline int
130_to_offset(const char *str) 173_to_offset(const char *str)
131{ 174{
@@ -1046,7 +1089,7 @@ _create_path_node(Svg_Node *parent, const char *buf, unsigned buflen)
1046} 1089}
1047 1090
1048#define CIRCLE_DEF(Name, Field, Type) \ 1091#define CIRCLE_DEF(Name, Field, Type) \
1049 { #Name, sizeof (#Name), offsetof(Svg_Circle_Node, Field)} 1092 { #Name, Type, sizeof (#Name), offsetof(Svg_Circle_Node, Field)}
1050 1093
1051static const struct { 1094static const struct {
1052 const char *tag; 1095 const char *tag;
@@ -1105,7 +1148,7 @@ _create_circle_node(Svg_Node *parent, const char *buf, unsigned buflen)
1105} 1148}
1106 1149
1107#define ELLIPSE_DEF(Name, Field, Type) \ 1150#define ELLIPSE_DEF(Name, Field, Type) \
1108 { #Name, Type, sizeof (#Name), offsetof(Svg_Ellipse_Node, Field)} 1151 { #Name, Type, sizeof (#Name) + sizeof (Type), offsetof(Svg_Ellipse_Node, Field)}
1109 1152
1110static const struct { 1153static const struct {
1111 const char *tag; 1154 const char *tag;
@@ -1259,7 +1302,7 @@ _create_polyline_node(Svg_Node *parent, const char *buf, unsigned buflen)
1259} 1302}
1260 1303
1261#define RECT_DEF(Name, Field, Type) \ 1304#define RECT_DEF(Name, Field, Type) \
1262 { #Name, Type, sizeof (#Name), offsetof(Svg_Rect_Node, Field)} 1305 { #Name, Type, sizeof (#Name) + sizeof(Type), offsetof(Svg_Rect_Node, Field)}
1263 1306
1264static const struct { 1307static const struct {
1265 const char *tag; 1308 const char *tag;
@@ -1325,7 +1368,7 @@ _create_rect_node(Svg_Node *parent, const char *buf, unsigned buflen)
1325} 1368}
1326 1369
1327#define LINE_DEF(Name, Field, Type) \ 1370#define LINE_DEF(Name, Field, Type) \
1328 { #Name, Type, sizeof (#Name), offsetof(Svg_Line_Node, Field)} 1371 { #Name, Type, sizeof (#Name) + sizeof (Type), offsetof(Svg_Line_Node, Field)}
1329 1372
1330static const struct { 1373static const struct {
1331 const char *tag; 1374 const char *tag;
@@ -1779,37 +1822,96 @@ _attr_parse_stops(void *data, const char *key, const char *value)
1779static void 1822static void
1780_handle_linear_x1_attr(Svg_Linear_Gradient* linear, const char *value) 1823_handle_linear_x1_attr(Svg_Linear_Gradient* linear, const char *value)
1781{ 1824{
1782 linear->x1 = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL); 1825 linear->x1 = _gradient_to_double(value, SVG_PARSER_LENGTH_HORIZONTAL);
1826 if (strstr(value, "%"))
1827 svg_parse.gradient.x1_percent = EINA_TRUE;
1783} 1828}
1784 1829
1785static void 1830static void
1786_handle_linear_y1_attr(Svg_Linear_Gradient* linear, const char *value) 1831_handle_linear_y1_attr(Svg_Linear_Gradient* linear, const char *value)
1787{ 1832{
1788 linear->y1 = _to_double(value, SVG_PARSER_LENGTH_VERTICAL); 1833 linear->y1 = _gradient_to_double(value, SVG_PARSER_LENGTH_VERTICAL);
1834 if (strstr(value, "%"))
1835 svg_parse.gradient.y1_percent = EINA_TRUE;
1789} 1836}
1790 1837
1791static void 1838static void
1792_handle_linear_x2_attr(Svg_Linear_Gradient* linear, const char *value) 1839_handle_linear_x2_attr(Svg_Linear_Gradient* linear, const char *value)
1793{ 1840{
1794 linear->x2 = _to_double(value, SVG_PARSER_LENGTH_HORIZONTAL); 1841 linear->x2 = _gradient_to_double(value, SVG_PARSER_LENGTH_HORIZONTAL);
1842 /* checking if there are no percentage because x2 have default value
1843 * already set in percentages (100%) */
1844 if (!strstr(value, "%"))
1845 svg_parse.gradient.x2_percent = EINA_FALSE;
1795} 1846}
1796 1847
1797static void 1848static void
1798_handle_linear_y2_attr(Svg_Linear_Gradient* linear, const char *value) 1849_handle_linear_y2_attr(Svg_Linear_Gradient* linear, const char *value)
1799{ 1850{
1800 linear->y2 = _to_double(value, SVG_PARSER_LENGTH_VERTICAL); 1851 linear->y2 = _gradient_to_double(value, SVG_PARSER_LENGTH_VERTICAL);
1852 if (strstr(value, "%"))
1853 svg_parse.gradient.y2_percent = EINA_TRUE;
1854}
1855
1856static void
1857_recalc_linear_x1_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space)
1858{
1859 if (!svg_parse.gradient.x1_percent && !user_space)
1860 {
1861 /* Since previous percentage is not required (it was already percent)
1862 * so oops and make it all back */
1863 linear->x1 = linear->x1 * svg_parse.global.width;
1864 }
1865 svg_parse.gradient.x1_percent = EINA_FALSE;
1866}
1867
1868static void
1869_recalc_linear_y1_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space)
1870{
1871 if (!svg_parse.gradient.y1_percent && !user_space)
1872 {
1873 /* Since previous percentage is not required (it was already percent)
1874 * so oops and make it all back */
1875 linear->y1 = linear->y1 * svg_parse.global.height;
1876 }
1877 svg_parse.gradient.y1_percent = EINA_FALSE;
1878}
1879
1880static void
1881_recalc_linear_x2_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space)
1882{
1883 if (!svg_parse.gradient.x2_percent && !user_space)
1884 {
1885 /* Since previous percentage is not required (it was already percent)
1886 * so oops and make it all back */
1887 linear->x2 = linear->x2 * svg_parse.global.width;
1888 }
1889 svg_parse.gradient.x2_percent = EINA_FALSE;
1801} 1890}
1802 1891
1892static void
1893_recalc_linear_y2_attr(Svg_Linear_Gradient* linear, Eina_Bool user_space)
1894{
1895 if (!svg_parse.gradient.y2_percent && !user_space)
1896 {
1897 /* Since previous percentage is not required (it was already percent)
1898 * so oops and make it all back */
1899 linear->y2 = linear->y2 * svg_parse.global.height;
1900 }
1901 svg_parse.gradient.y2_percent = EINA_FALSE;
1902}
1803 1903
1804typedef void (*Linear_Method)(Svg_Linear_Gradient *linear, const char *value); 1904typedef void (*Linear_Method)(Svg_Linear_Gradient *linear, const char *value);
1905typedef void (*Linear_Method_Recalc)(Svg_Linear_Gradient *linear, Eina_Bool user_space);
1805 1906
1806#define LINEAR_DEF(Name) \ 1907#define LINEAR_DEF(Name) \
1807 { #Name, sizeof (#Name), _handle_linear_##Name##_attr} 1908 { #Name, sizeof (#Name), _handle_linear_##Name##_attr, _recalc_linear_##Name##_attr}
1808 1909
1809static const struct { 1910static const struct {
1810 const char *tag; 1911 const char *tag;
1811 int sz; 1912 int sz;
1812 Linear_Method tag_handler;; 1913 Linear_Method tag_handler;;
1914 Linear_Method_Recalc tag_recalc;;
1813} linear_tags[] = { 1915} linear_tags[] = {
1814 LINEAR_DEF(x1), 1916 LINEAR_DEF(x1),
1815 LINEAR_DEF(y1), 1917 LINEAR_DEF(y1),
@@ -1856,18 +1958,33 @@ static Svg_Style_Gradient *
1856_create_linearGradient(const char *buf, unsigned buflen) 1958_create_linearGradient(const char *buf, unsigned buflen)
1857{ 1959{
1858 Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient)); 1960 Svg_Style_Gradient *grad = calloc(1, sizeof(Svg_Style_Gradient));
1961 unsigned int i;
1859 1962
1860 grad->type = SVG_LINEAR_GRADIENT; 1963 grad->type = SVG_LINEAR_GRADIENT;
1861 grad->linear = calloc(1, sizeof(Svg_Linear_Gradient)); 1964 grad->linear = calloc(1, sizeof(Svg_Linear_Gradient));
1965 /**
1966 * Default value of x2 is 100%
1967 */
1968 grad->linear->x2 = 1;
1969 svg_parse.gradient.x2_percent = EINA_TRUE;
1862 eina_simple_xml_attributes_parse(buf, buflen, 1970 eina_simple_xml_attributes_parse(buf, buflen,
1863 _attr_parse_linear_gradient_node, grad); 1971 _attr_parse_linear_gradient_node, grad);
1864 return grad;
1865 1972
1973 for (i = 0; i < sizeof (linear_tags) / sizeof(linear_tags[0]); i++)
1974 linear_tags[i].tag_recalc(grad->linear, grad->user_space);
1975
1976 return grad;
1866} 1977}
1867 1978
1868#define GRADIENT_DEF(Name) \ 1979#define GRADIENT_DEF(Name) \
1869 { #Name, sizeof (#Name), _create_##Name } 1980 { #Name, sizeof (#Name), _create_##Name }
1870 1981
1982/**
1983 * For all Gradients lengths would be calculated into percentages related to
1984 * canvas width and height.
1985 *
1986 * if user then recalculate actual pixels into percentages
1987 */
1871static const struct { 1988static const struct {
1872 const char *tag; 1989 const char *tag;
1873 int sz; 1990 int sz;
diff --git a/src/static_libs/vg_common/vg_common.h b/src/static_libs/vg_common/vg_common.h
index 65c70a89a9..174cb2003e 100644
--- a/src/static_libs/vg_common/vg_common.h
+++ b/src/static_libs/vg_common/vg_common.h
@@ -176,6 +176,25 @@ struct _Svg_Radial_Gradient
176 double r; 176 double r;
177}; 177};
178 178
179/**
180 * IMPORTANT!
181 * Talking about parsing gradient variables
182 *
183 * All variables (like x1,x2,y1,y2,fx,fy,rx,ry,r, etc) would be percentages
184 * and then all recalculations would be done after that if userSpaceOnUse
185 * is set or not (recalculation depends on that).
186 *
187 * If gradientUnits="userSpaceOnUse" (grad->user_space is set to true)
188 * > Gradient variables (x1,x2,r,fx etc) contains percentages of entire cavas
189 * > size.
190 *
191 * If gradientUnits="objectBoundingBox" (grad->user_space is set to false)
192 * > Gradient variables (x1,x2,r,fx etc) contain percentages of 'whatever'
193 * > figure.
194 *
195 * So later on, while using gradient, please be careful and
196 * check user_space to use and transform sizes correctly.
197 */
179struct _Svg_Style_Gradient 198struct _Svg_Style_Gradient
180{ 199{
181 Svg_Gradient_Type type; 200 Svg_Gradient_Type type;