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