1 /* svg_gradient.c: Data structures for SVG gradients
2
3 Copyright � 2002 USC/Information Sciences Institute
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19
20 Author: Steven Kramer
21 */
22
23 #include "svgint.h"
24
25 #include <string.h>
26
27 svg_status_t
_svg_gradient_init(svg_gradient_t * gradient)28 _svg_gradient_init (svg_gradient_t *gradient)
29 {
30 int i;
31 svg_transform_t transform;
32
33 _svg_gradient_set_type (gradient, SVG_GRADIENT_LINEAR);
34
35 gradient->units = SVG_GRADIENT_UNITS_BBOX;
36 gradient->spread = SVG_GRADIENT_SPREAD_PAD;
37
38 _svg_transform_init (&transform);
39 for (i = 0; i < 6 ; i++) {
40 gradient->transform [i] = transform.m[i/2][i%2];
41 }
42
43 gradient->stops = NULL;
44 gradient->num_stops = 0;
45 gradient->stops_size = 0;
46
47 return SVG_STATUS_SUCCESS;
48 }
49
50 svg_status_t
_svg_gradient_init_copy(svg_gradient_t * gradient,svg_gradient_t * other)51 _svg_gradient_init_copy (svg_gradient_t *gradient,
52 svg_gradient_t *other)
53 {
54 *gradient = *other;
55
56 gradient->stops = malloc (gradient->stops_size * sizeof (svg_gradient_stop_t));
57 if (gradient->stops == NULL)
58 return SVG_STATUS_NO_MEMORY;
59 memcpy (gradient->stops, other->stops, gradient->num_stops * sizeof (svg_gradient_stop_t));
60
61 return SVG_STATUS_SUCCESS;
62 }
63
64 svg_status_t
_svg_gradient_deinit(svg_gradient_t * gradient)65 _svg_gradient_deinit (svg_gradient_t *gradient)
66 {
67 if (gradient->stops) {
68 free (gradient->stops);
69 gradient->stops = NULL;
70 }
71 gradient->stops_size = 0;
72 gradient->num_stops = 0;
73
74 return SVG_STATUS_SUCCESS;
75 }
76
77 svg_status_t
_svg_gradient_set_type(svg_gradient_t * gradient,svg_gradient_type_t type)78 _svg_gradient_set_type (svg_gradient_t *gradient,
79 svg_gradient_type_t type)
80 {
81 gradient->type = type;
82
83 /* XXX: Should check what these defaults should really be. */
84
85 if (gradient->type == SVG_GRADIENT_LINEAR) {
86 _svg_length_init_unit (&gradient->u.linear.x1, 0, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_HORIZONTAL);
87 _svg_length_init_unit (&gradient->u.linear.y1, 0, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_VERTICAL);
88 _svg_length_init_unit (&gradient->u.linear.x2, 100, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_HORIZONTAL);
89 _svg_length_init_unit (&gradient->u.linear.y2, 0, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_VERTICAL);
90 } else {
91 _svg_length_init_unit (&gradient->u.radial.cx, 50, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_HORIZONTAL);
92 _svg_length_init_unit (&gradient->u.radial.cy, 50, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_VERTICAL);
93 _svg_length_init_unit (&gradient->u.radial.fx, 50, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_HORIZONTAL);
94 _svg_length_init_unit (&gradient->u.radial.fy, 50, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_VERTICAL);
95 _svg_length_init_unit (&gradient->u.radial.r, 50, SVG_LENGTH_UNIT_PCT, SVG_LENGTH_ORIENTATION_HORIZONTAL);
96 }
97
98 return SVG_STATUS_SUCCESS;
99 }
100
101 svg_status_t
_svg_gradient_add_stop(svg_gradient_t * gradient,double offset,svg_color_t * color,double opacity)102 _svg_gradient_add_stop (svg_gradient_t *gradient,
103 double offset,
104 svg_color_t *color,
105 double opacity)
106 {
107 svg_gradient_stop_t *new_stops, *stop;
108
109 if (gradient->num_stops >= gradient->stops_size) {
110 int old_size = gradient->stops_size;
111 if (gradient->stops_size)
112 gradient->stops_size *= 2;
113 else
114 gradient->stops_size = 2; /* Any useful gradient has at least 2 */
115 new_stops = realloc (gradient->stops,
116 gradient->stops_size * sizeof (svg_gradient_stop_t));
117 if (new_stops == NULL) {
118 gradient->stops_size = old_size;
119 return SVG_STATUS_NO_MEMORY;
120 }
121 gradient->stops = new_stops;
122 }
123
124 stop = &gradient->stops[gradient->num_stops++];
125 stop->offset = offset;
126 stop->color = *color;
127 stop->opacity = opacity;
128
129 return SVG_STATUS_SUCCESS;
130 }
131
132 svg_status_t
_svg_gradient_apply_attributes(svg_gradient_t * gradient,svg_t * svg,const char ** attributes)133 _svg_gradient_apply_attributes (svg_gradient_t *gradient,
134 svg_t *svg,
135 const char **attributes)
136 {
137 svgint_status_t status;
138 const char *href;
139 int i;
140 svg_transform_t transform;
141 const char *str;
142 svg_gradient_t* prototype = 0;
143
144 /* SPK: still an incomplete set of attributes */
145 _svg_attribute_get_string (attributes, "xlink:href", &href, 0);
146 if (href) {
147 svg_element_t *ref = NULL;
148 _svg_fetch_element_by_id (svg, href + 1, &ref);
149
150 if (ref && ref->type == SVG_ELEMENT_TYPE_GRADIENT) {
151 svg_gradient_t save_gradient = *gradient;
152
153 prototype = &ref->e.gradient;
154 _svg_gradient_init_copy (gradient, prototype);
155
156 if (gradient->type != save_gradient.type) {
157 gradient->type = save_gradient.type;
158 gradient->u = save_gradient.u;
159 }
160 }
161 }
162
163 status = _svg_attribute_get_string (attributes, "gradientUnits", &str, "objectBoundingBox");
164 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype) {
165 gradient->units = prototype->units;
166 } else {
167 if (strcmp (str, "userSpaceOnUse") == 0)
168 gradient->units = SVG_GRADIENT_UNITS_USER;
169 else if (strcmp (str, "objectBoundingBox") == 0)
170 gradient->units = SVG_GRADIENT_UNITS_BBOX;
171 else
172 return SVG_STATUS_INVALID_VALUE;
173 }
174
175 status = _svg_attribute_get_string (attributes, "gradientTransform", &str, 0);
176 if (str) {
177 _svg_transform_init (&transform);
178 _svg_transform_parse_str (&transform, str);
179 for (i = 0 ; i < 6 ; i++) {
180 gradient->transform [i] = transform.m[i/2][i%2];
181 }
182 } else if (prototype) {
183 for (i = 0 ; i < 6 ; ++i)
184 gradient->transform[i] = prototype->transform[i];
185 }
186
187 status = _svg_attribute_get_string (attributes, "spreadMethod",
188 &str, "pad");
189 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype) {
190 gradient->spread = prototype->spread;
191 } else {
192 if (strcmp (str, "pad") == 0)
193 gradient->spread = SVG_GRADIENT_SPREAD_PAD;
194 else if (strcmp (str, "reflect") == 0)
195 gradient->spread = SVG_GRADIENT_SPREAD_REFLECT;
196 else if (strcmp (str, "repeat") == 0)
197 gradient->spread = SVG_GRADIENT_SPREAD_REPEAT;
198 else
199 return SVG_STATUS_INVALID_VALUE;
200 }
201
202 if (prototype && prototype->type != gradient->type)
203 prototype = NULL;
204
205 if (gradient->type == SVG_GRADIENT_LINEAR) {
206 status = _svg_attribute_get_length (attributes, "x1", &gradient->u.linear.x1, "0%");
207 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype)
208 gradient->u.linear.x1 = prototype->u.linear.x1;
209 status = _svg_attribute_get_length (attributes, "y1", &gradient->u.linear.y1, "0%");
210 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype)
211 gradient->u.linear.y1 = prototype->u.linear.y1;
212 status = _svg_attribute_get_length (attributes, "x2", &gradient->u.linear.x2, "100%");
213 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype)
214 gradient->u.linear.x2 = prototype->u.linear.x2;
215 status = _svg_attribute_get_length (attributes, "y2", &gradient->u.linear.y2, "0%");
216 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype)
217 gradient->u.linear.y2 = prototype->u.linear.y2;
218 } else {
219 status = _svg_attribute_get_length (attributes, "cx", &gradient->u.radial.cx, "50%");
220 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype)
221 gradient->u.radial.cx = prototype->u.radial.cx;
222 status = _svg_attribute_get_length (attributes, "cy", &gradient->u.radial.cy, "50%");
223 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype)
224 gradient->u.radial.cy = prototype->u.radial.cy;
225 status = _svg_attribute_get_length (attributes, "r", &gradient->u.radial.r, "50%");
226 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND && prototype)
227 gradient->u.radial.r = prototype->u.radial.r;
228
229 /* fx and fy default to cx and cy */
230 status = _svg_attribute_get_length (attributes, "fx", &gradient->u.radial.fx, "50%");
231 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND)
232 gradient->u.radial.fx = gradient->u.radial.cx;
233
234 status = _svg_attribute_get_length (attributes, "fy", &gradient->u.radial.fy, "50%");
235 if (status == SVGINT_STATUS_ATTRIBUTE_NOT_FOUND)
236 gradient->u.radial.fy = gradient->u.radial.cy;
237 }
238
239 return SVG_STATUS_SUCCESS;
240 }
241