1 /* svg_group.c: Data structures for SVG group elements
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: Carl Worth <cworth@isi.edu>
21 */
22
23 #include "svgint.h"
24
25 static svg_status_t
26 _svg_group_grow_element_by (svg_group_t *group, int additional);
27
28 svg_status_t
_svg_group_init(svg_group_t * group)29 _svg_group_init (svg_group_t *group)
30 {
31 group->element = NULL;
32 group->num_elements = 0;
33 group->element_size = 0;
34
35 _svg_length_init_unit (&group->width, 0, SVG_LENGTH_UNIT_PX, SVG_LENGTH_ORIENTATION_HORIZONTAL);
36 _svg_length_init_unit (&group->height, 0, SVG_LENGTH_UNIT_PX, SVG_LENGTH_ORIENTATION_VERTICAL);
37 group->view_box.aspect_ratio = SVG_PRESERVE_ASPECT_RATIO_UNKNOWN;
38 group->view_box.meet_or_slice = SVG_MEET_OR_SLICE_UNKNOWN;
39
40 _svg_length_init_unit (&group->x, 0, SVG_LENGTH_UNIT_PX, SVG_LENGTH_ORIENTATION_HORIZONTAL);
41 _svg_length_init_unit (&group->y, 0, SVG_LENGTH_UNIT_PX, SVG_LENGTH_ORIENTATION_VERTICAL);
42
43 return SVG_STATUS_SUCCESS;
44 }
45
46 svg_status_t
_svg_group_init_copy(svg_group_t * group,svg_group_t * other)47 _svg_group_init_copy (svg_group_t *group,
48 svg_group_t *other)
49 {
50 svg_status_t status;
51 svg_element_t *clone;
52 int i;
53 group->element = NULL;
54 group->num_elements = 0;
55 group->element_size = 0;
56
57 /* clone children */
58 for (i=0; i < other->num_elements; i++) {
59 status = _svg_element_clone (&clone, other->element[i]);
60 if (status)
61 return status;
62 status = _svg_group_add_element (group, clone);
63 if (status)
64 return status;
65 }
66
67 group->width = other->width;
68 group->height = other->height;
69
70 group->view_box = other->view_box;
71
72 group->x = other->x;
73 group->y = other->y;
74
75 return SVG_STATUS_SUCCESS;
76 }
77
78 svg_status_t
_svg_group_deinit(svg_group_t * group)79 _svg_group_deinit (svg_group_t *group)
80 {
81 int i;
82
83 for (i = 0; i < group->num_elements; i++)
84 _svg_element_destroy (group->element[i]);
85
86 free (group->element);
87 group->element = NULL;
88 group->num_elements = 0;
89 group->element_size = 0;
90
91 return SVG_STATUS_SUCCESS;
92 }
93
94 svg_status_t
_svg_group_add_element(svg_group_t * group,svg_element_t * element)95 _svg_group_add_element (svg_group_t *group, svg_element_t *element)
96 {
97 svg_status_t status;
98
99 if (group->num_elements >= group->element_size) {
100 int additional = group->element_size ? group->element_size : 4;
101 status = _svg_group_grow_element_by(group, additional);
102 if (status)
103 return status;
104 }
105
106 group->element[group->num_elements] = element;
107 group->num_elements++;
108
109 return SVG_STATUS_SUCCESS;
110 }
111
112 svg_status_t
_svg_group_render(svg_group_t * group,svg_render_engine_t * engine,void * closure)113 _svg_group_render (svg_group_t *group,
114 svg_render_engine_t *engine,
115 void *closure)
116 {
117 int i;
118 svg_status_t status, return_status = SVG_STATUS_SUCCESS;
119
120 /* XXX: Perhaps this isn't the cleanest way to do this. It would
121 be cleaner to just immediately abort on an error I think. In
122 order to do that, we'd need to fix the parser so that it
123 doesn't include images with null data in the tree for
124 example. */
125 for (i=0; i < group->num_elements; i++) {
126 status = svg_element_render (group->element[i],
127 engine, closure);
128 if (status && !return_status)
129 return_status = status;
130 }
131
132 return return_status;
133 }
134
135 svg_status_t
_svg_symbol_render(svg_element_t * group,svg_render_engine_t * engine,void * closure)136 _svg_symbol_render (svg_element_t *group,
137 svg_render_engine_t *engine,
138 void *closure)
139 {
140 /* Never render a symbol directly. Only way to show a symbol is through <use>. */
141 return SVG_STATUS_SUCCESS;
142 }
143
144 /* Apply attributes unique to `svg' elements */
145 svg_status_t
_svg_group_apply_svg_attributes(svg_group_t * group,const char ** attributes)146 _svg_group_apply_svg_attributes (svg_group_t *group,
147 const char **attributes)
148 {
149 const char *view_box_str, *aspect_ratio_str;
150 svgint_status_t status;
151
152 _svg_attribute_get_length (attributes, "width", &group->width, "100%");
153 _svg_attribute_get_length (attributes, "height", &group->height, "100%");
154
155 /* XXX: What else? */
156 _svg_attribute_get_length (attributes, "x", &group->x, "0");
157 _svg_attribute_get_length (attributes, "y", &group->y, "0");
158
159 _svg_attribute_get_string (attributes, "viewBox", &view_box_str, NULL);
160
161 if (view_box_str)
162 {
163 status = _svg_element_parse_view_box (view_box_str,
164 &group->view_box.box.x,
165 &group->view_box.box.y,
166 &group->view_box.box.width,
167 &group->view_box.box.height);
168
169 group->view_box.aspect_ratio = SVG_PRESERVE_ASPECT_RATIO_NONE;
170 _svg_attribute_get_string (attributes, "preserveAspectRatio", &aspect_ratio_str, NULL);
171 if (aspect_ratio_str)
172 status = _svg_element_parse_aspect_ratio (aspect_ratio_str, &group->view_box);
173 }
174
175 return SVG_STATUS_SUCCESS;
176 }
177
178 /* Apply attributes common to `svg' and `g' elements */
179 svg_status_t
_svg_group_apply_group_attributes(svg_group_t * group,const char ** attributes)180 _svg_group_apply_group_attributes (svg_group_t *group,
181 const char **attributes)
182 {
183 /* XXX: NYI */
184
185 return SVG_STATUS_SUCCESS;
186 }
187
188 svg_status_t
_svg_group_apply_use_attributes(svg_element_t * group,const char ** attributes)189 _svg_group_apply_use_attributes (svg_element_t *group,
190 const char **attributes)
191 {
192 const char *href;
193 svg_element_t *ref;
194 svg_element_t *clone;
195 svgint_status_t status;
196
197 _svg_attribute_get_string (attributes, "xlink:href", &href, "");
198 _svg_fetch_element_by_id (group->doc, href + 1, &ref);
199 if (!ref) {
200 /* XXX: Should we report an error here? */
201 return SVG_STATUS_SUCCESS;
202 }
203
204 /*printf ("_svg_group_apply_use_attributes : %s\n", href + 1);
205 printf ("_svg_group_apply_use_attributes : %d\n", ref); */
206
207 _svg_attribute_get_length (attributes, "width", &group->e.group.width, "100%");
208 _svg_attribute_get_length (attributes, "height", &group->e.group.height, "100%");
209
210 /* TODO : remove cloned tree (requires ref counting?). */
211 status = _svg_element_clone (&clone, ref);
212 if (status)
213 return status;
214 if (clone)
215 {
216 if (clone->type == SVG_ELEMENT_TYPE_SYMBOL)
217 {
218 clone->e.group.width = group->e.group.width;
219 clone->e.group.height = group->e.group.height;
220 }
221 /* perform extra view_box transform for symbol */
222 if (clone->type == SVG_ELEMENT_TYPE_SYMBOL &&
223 clone->e.group.view_box.aspect_ratio != SVG_PRESERVE_ASPECT_RATIO_UNKNOWN)
224 {
225 /*status = _svg_transform_apply_viewbox (&clone->transform, &clone->e.group.view_box,
226 clone->e.group.width, clone->e.group.height);*/
227
228 clone->type = SVG_ELEMENT_TYPE_GROUP;
229 }
230 _svg_group_add_element (&group->e.group, clone);
231 }
232
233 _svg_attribute_get_length (attributes, "x", &group->e.group.x, "0");
234 _svg_attribute_get_length (attributes, "y", &group->e.group.y, "0");
235
236 /* _svg_transform_add_translate (&group->transform, _x, _y); */
237
238 return SVG_STATUS_SUCCESS;
239 }
240
241 static svg_status_t
_svg_group_grow_element_by(svg_group_t * group,int additional)242 _svg_group_grow_element_by (svg_group_t *group, int additional)
243 {
244 svg_element_t **new_element;
245 int old_size = group->element_size;
246 int new_size = group->num_elements + additional;
247
248 if (new_size <= group->element_size) {
249 return SVG_STATUS_SUCCESS;
250 }
251
252 group->element_size = new_size;
253 new_element = realloc (group->element,
254 group->element_size * sizeof(svg_element_t *));
255
256 if (new_element == NULL) {
257 group->element_size = old_size;
258 return SVG_STATUS_NO_MEMORY;
259 }
260
261 group->element = new_element;
262
263 return SVG_STATUS_SUCCESS;
264 }
265
266 svg_status_t
_svg_group_get_size(svg_group_t * group,svg_length_t * width,svg_length_t * height)267 _svg_group_get_size (svg_group_t *group, svg_length_t *width, svg_length_t *height)
268 {
269 *width = group->width;
270 *height = group->height;
271
272 return SVG_STATUS_SUCCESS;
273 }
274