diff options
author | Vitalii Vorobiov <vi.vorobiov@samsung.com> | 2017-02-17 17:00:01 +0200 |
---|---|---|
committer | Jean-Philippe Andre <jp.andre@samsung.com> | 2017-11-07 11:54:09 +0900 |
commit | 405e56ac553db21f3e53d1702cc3db3863142811 (patch) | |
tree | c6ac76c18686aa95ce975234d8bb7946f4dc9e2a | |
parent | 6139aa78d5a48166a235087ecc49942b969b09af (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.c | 137 | ||||
-rw-r--r-- | src/static_libs/vg_common/vg_common.h | 19 |
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 | */ | ||
133 | static 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 | |||
129 | static inline int | 172 | static 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 | ||
1051 | static const struct { | 1094 | static 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 | ||
1110 | static const struct { | 1153 | static 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 | ||
1264 | static const struct { | 1307 | static 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 | ||
1330 | static const struct { | 1373 | static 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) | |||
1779 | static void | 1822 | static 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 | ||
1785 | static void | 1830 | static 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 | ||
1791 | static void | 1838 | static 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 | ||
1797 | static void | 1848 | static 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 | |||
1856 | static 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 | |||
1868 | static 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 | |||
1880 | static 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 | ||
1892 | static 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 | ||
1804 | typedef void (*Linear_Method)(Svg_Linear_Gradient *linear, const char *value); | 1904 | typedef void (*Linear_Method)(Svg_Linear_Gradient *linear, const char *value); |
1905 | typedef 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 | ||
1809 | static const struct { | 1910 | static 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 | */ | ||
1871 | static const struct { | 1988 | static 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 | */ | ||
179 | struct _Svg_Style_Gradient | 198 | struct _Svg_Style_Gradient |
180 | { | 199 | { |
181 | Svg_Gradient_Type type; | 200 | Svg_Gradient_Type type; |