rsvg-structure.c 13.4 KB
Newer Older
1 2 3 4 5
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
   rsvg-structure.c: Rsvg's structual elements

   Copyright (C) 2000 Eazel, Inc.
Caleb Michael Moore's avatar
Caleb Michael Moore committed
6 7
   Copyright (C) 2002 - 2005 Dom Lachowicz <cinamod@hotmail.com>
   Copyright (C) 2003 - 2005 Caleb Moore <c.moore@student.unsw.edu.au>
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Authors: Raph Levien <raph@artofcode.com>, 
            Dom Lachowicz <cinamod@hotmail.com>, 
            Caleb Moore <c.moore@student.unsw.edu.au>
*/

#include "rsvg-structure.h"
#include "rsvg-image.h"
#include "rsvg-css.h"

33 34
#include <stdio.h>

35
void 
Caleb Michael Moore's avatar
Caleb Michael Moore committed
36
rsvg_node_draw (RsvgNode * self, RsvgDrawingCtx *ctx,
37 38
						 int dominate)
{
39 40
	RsvgState *state;

41
	state = self->state;
42 43 44 45

	if (0 /*!state->visible*/)
		return;

46 47 48
	self->draw(self, ctx, dominate);
}

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
/* generic function for drawing all of the children of a particular node */ 
void 
_rsvg_node_draw_children (RsvgNode * self, RsvgDrawingCtx *ctx, 
						  int dominate)
{
	guint i;
	if (dominate != -1)
		{
			rsvg_state_reinherit_top(ctx, self->state, dominate);
			
			rsvg_push_discrete_layer (ctx);	
		}
	for (i = 0; i < self->children->len; i++)
		{
			rsvg_state_push(ctx);
			rsvg_node_draw (g_ptr_array_index(self->children, i), 
									 ctx, 0);
			rsvg_state_pop(ctx);
		}			
	if (dominate != -1)
		rsvg_pop_discrete_layer (ctx);
}

/* generic function that doesn't draw anything at all */
73
static void 
74 75 76 77 78
_rsvg_node_draw_nothing (RsvgNode * self, RsvgDrawingCtx *ctx, 
						 int dominate)
{
}

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
static void
_rsvg_node_dont_set_atts (RsvgNode * node, RsvgHandle * ctx, RsvgPropertyBag * atts)
{
}

void
_rsvg_node_init(RsvgNode *self)
{
	self->children = g_ptr_array_new();
	self->state = g_new(RsvgState, 1);
	rsvg_state_init(self->state);
	self->type = RSVG_NODE_PATH;
	self->free = _rsvg_node_free;
	self->draw = _rsvg_node_draw_nothing;
	self->set_atts = _rsvg_node_dont_set_atts;
}

96
void 
97
_rsvg_node_free (RsvgNode *self)
98
{
99
	if (self->state != NULL)
100 101 102 103
		{
			rsvg_state_finalize (self->state);
			g_free(self->state);
		}
104 105
	if (self->children != NULL)
		g_ptr_array_free(self->children, TRUE);
106 107 108
	g_free (self);
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
109 110
static void
rsvg_node_group_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts)
111 112 113 114 115 116 117 118
{
	const char * klazz = NULL, * id = NULL, *value;

	if (rsvg_property_bag_size (atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "class")))
				klazz = value;
			if ((value = rsvg_property_bag_lookup (atts, "id")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
119 120 121 122
				{
					id = value;
					rsvg_defs_register_name (ctx->defs, value, self);
				}
123

Caleb Michael Moore's avatar
Caleb Michael Moore committed
124
			rsvg_parse_style_attrs (ctx, self->state, "g", klazz, id, atts);
125 126 127
		}	
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
128 129
RsvgNode *
rsvg_new_group (void)
130
{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
131 132
	RsvgNodeGroup *group;
	group = g_new (RsvgNodeGroup, 1);
133
	_rsvg_node_init(&group->super);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
134
	group->super.type = RSVG_NODE_PATH;
135
	group->super.draw = _rsvg_node_draw_children;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
136
	group->super.set_atts = rsvg_node_group_set_atts;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
137
	return &group->super;
138 139
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
140 141 142
void
rsvg_pop_def_group (RsvgHandle *ctx)
{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
143 144
	if (ctx->currentnode != NULL)
		ctx->currentnode = ctx->currentnode->parent;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
145 146 147 148 149
}

void 
rsvg_node_group_pack (RsvgNode *self, RsvgNode *child)
{
150
	g_ptr_array_add(self->children, child);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
151 152 153
	child->parent = self;
}

154
static void 
Caleb Michael Moore's avatar
Caleb Michael Moore committed
155
rsvg_node_use_draw (RsvgNode * self, RsvgDrawingCtx *ctx, 
156 157
							  int dominate)
{
158 159
	RsvgNodeUse *use = (RsvgNodeUse*)self;
	RsvgNode * child;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
160 161
	RsvgState * state;
	double affine[6];
162

163
	rsvg_state_reinherit_top(ctx,  self->state, dominate);
164

Caleb Michael Moore's avatar
Caleb Michael Moore committed
165 166 167
	rsvg_push_discrete_layer (ctx);


Caleb Michael Moore's avatar
Caleb Michael Moore committed
168
	child = use->link;
169

170 171 172
	/* If it can find nothing to draw... draw nothing */
	if (!use->link)
		return;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
173
	state = rsvg_state_current(ctx);	
Caleb Michael Moore's avatar
Caleb Michael Moore committed
174
	if (child->type != RSVG_NODE_SYMBOL)
Caleb Michael Moore's avatar
Caleb Michael Moore committed
175 176 177 178 179 180 181 182
		{
			_rsvg_affine_translate(affine, use->x, use->y);
			_rsvg_affine_multiply(state->affine, affine, state->affine);

			rsvg_state_push(ctx);	
			rsvg_node_draw (child, ctx, 1);
			rsvg_state_pop(ctx);
		}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
183
	else
Caleb Michael Moore's avatar
Caleb Michael Moore committed
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
		{
			RsvgNodeSymbol *symbol = 
				(RsvgNodeSymbol*)child;
			double x, y, width, height;
			x = use->x;
			y = use->y;
			width = use->w;
			height = use->h;
			
			if (symbol->has_vbox){
				rsvg_preserve_aspect_ratio
					(symbol->preserve_aspect_ratio, 
					 symbol->width, symbol->height, 
					 &width, &height, &x, &y);

				_rsvg_affine_translate(affine, x, y);
				_rsvg_affine_multiply(state->affine, affine, state->affine);
				_rsvg_affine_scale(affine, width / symbol->width,
								   height / symbol->height);
				_rsvg_affine_multiply(state->affine, affine, state->affine);
				_rsvg_affine_translate(affine, -symbol->x, 
									   -symbol->y);
				_rsvg_affine_multiply(state->affine, affine, state->affine);

Caleb Michael Moore's avatar
Caleb Michael Moore committed
208 209 210 211
				if (!state->overflow || 
					(!state->has_overflow && child->state->overflow))
					rsvg_add_clipping_rect (ctx, symbol->x, symbol->y,
											symbol->width, symbol->height);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
212 213 214 215
			} else {
				_rsvg_affine_translate(affine, use->x, use->y);
				_rsvg_affine_multiply(state->affine, affine, state->affine);
			}
216

Caleb Michael Moore's avatar
Caleb Michael Moore committed
217 218 219
			rsvg_state_push(ctx);
			_rsvg_node_draw_children(child, ctx, 1);
			rsvg_state_pop(ctx);
220

Caleb Michael Moore's avatar
Caleb Michael Moore committed
221 222
		}
	rsvg_pop_discrete_layer (ctx);
223 224 225
}	

static void 
Caleb Michael Moore's avatar
Caleb Michael Moore committed
226
rsvg_node_use_free (RsvgNode *self)
227
{
228 229 230
	RsvgNodeUse *z = (RsvgNodeUse *)self;
	rsvg_state_finalize (z->super.state);
	g_free (z->super.state);
231 232 233 234
	g_free (z);
}

static void
Caleb Michael Moore's avatar
Caleb Michael Moore committed
235
rsvg_node_svg_draw (RsvgNode * self, RsvgDrawingCtx *ctx, 
236 237
							 int dominate)
{
238
	RsvgNodeSvg * sself;
239
	RsvgState *state;
240
	gdouble affine[6];
241
	guint i;
242
	sself = (RsvgNodeSvg *)self;
243

244
	rsvg_state_reinherit_top(ctx, self->state, dominate);
245

246
	rsvg_push_discrete_layer (ctx);
247

Caleb Michael Moore's avatar
Caleb Michael Moore committed
248 249 250
	state = rsvg_state_current (ctx);

	if (!state->overflow && self->parent)
251 252 253
		{
			rsvg_add_clipping_rect(ctx, sself->x, sself->y, sself->w, sself->h);
		}
254 255

	if (sself->has_vbox && sself->hasw && sself->hash)
256
		{
257 258 259 260 261
			double x = sself->x, y = sself->y, w = sself->w, h = sself->h;
			rsvg_preserve_aspect_ratio(sself->preserve_aspect_ratio,
									   sself->vbw, sself->vbh, 
									   &w, &h, &x, &y);
			affine[0] = w / sself->vbw;
262 263
			affine[1] = 0;
			affine[2] = 0;
264 265 266
			affine[3] = h / sself->vbh;
			affine[4] = x - sself->vbx * w / sself->vbw;
			affine[5] = y - sself->vby * h / sself->vbh;
267 268 269 270 271 272 273 274 275 276 277 278 279 280
			_rsvg_affine_multiply(state->affine, affine, 
								  state->affine);
		}
	else
		{
			affine[0] = 1;
			affine[1] = 0;
			affine[2] = 0;
			affine[3] = 1;
			affine[4] = sself->x;
			affine[5] = sself->y;
			_rsvg_affine_multiply(state->affine, affine, 
								  state->affine);
		}
281

282
	for (i = 0; i < self->children->len; i++)
283 284 285
		{
			rsvg_state_push(ctx);

286
			rsvg_node_draw (g_ptr_array_index(self->children, i), 
287 288 289 290 291 292 293 294
									 ctx, 0);
	
			rsvg_state_pop(ctx);
		}			

	rsvg_pop_discrete_layer (ctx);
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
295 296
static void
rsvg_node_svg_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts)
297 298
{
	const char * id, *value;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
299
	RsvgNodeSvg * svg = (RsvgNodeSvg *)self;
Dom Lachowicz's avatar
Dom Lachowicz committed
300 301

	id = NULL;
302 303 304 305 306

	if (rsvg_property_bag_size (atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "viewBox")))
				{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
307 308 309 310 311 312 313 314 315 316
					svg->has_vbox = rsvg_css_parse_vbox (value, 
														 &svg->vbx, 
														 &svg->vby,
														 &svg->vbw, 
														 &svg->vbh);
					if (svg->has_vbox)
						{
							ctx->width = svg->vbw;
							ctx->height = svg->vbh;
						}
317
				}
318 319
			if ((value = rsvg_property_bag_lookup (atts, "preserveAspectRatio")))
				svg->preserve_aspect_ratio = rsvg_css_parse_aspect_ratio (value);			
320
			if ((value = rsvg_property_bag_lookup (atts, "width")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
321 322
				{
					svg->w = rsvg_css_parse_normalized_length (value, ctx->dpi_x, ctx->width, 1);
323
					svg->hasw = (svg->w > 0);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
324 325 326
					if (!svg->has_vbox)
						ctx->width = svg->w; 
				}
327
			if ((value = rsvg_property_bag_lookup (atts, "height")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
328 329
				{
					svg->h = rsvg_css_parse_normalized_length (value, ctx->dpi_y, ctx->height, 1);
330
					svg->hash = (svg->h > 0);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
331 332 333
					if (!svg->has_vbox)
						ctx->height = svg->h;
				}
334
			if ((value = rsvg_property_bag_lookup (atts, "x")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
335
				svg->x = rsvg_css_parse_normalized_length (value, ctx->dpi_x, ctx->width, 1);
336
			if ((value = rsvg_property_bag_lookup (atts, "y")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
337
				svg->y = rsvg_css_parse_normalized_length (value, ctx->dpi_y, ctx->height, 1);
338
			if ((value = rsvg_property_bag_lookup (atts, "id")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
339 340 341 342
				{
					id = value;
					rsvg_defs_register_name (ctx->defs, value, &svg->super);
				}
343
		}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
344
}
345

Caleb Michael Moore's avatar
Caleb Michael Moore committed
346 347 348 349
RsvgNode *
rsvg_new_svg (void)
{
	RsvgNodeSvg * svg;
350
	svg = g_new (RsvgNodeSvg, 1);
351
	_rsvg_node_init(&svg->super);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
352
	svg->has_vbox = FALSE;
353
	svg->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
354
	svg->x = 0; svg->y = 0; svg->w = -1; svg->h = -1;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
355
	svg->hasw = svg->hash = FALSE;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
356 357 358 359 360
	svg->vbx = 0; svg->vby = 0; svg->vbw = 0; svg->vbh = 0;
	svg->super.type = RSVG_NODE_PATH;
	svg->super.draw = rsvg_node_svg_draw;
	svg->super.set_atts = rsvg_node_svg_set_atts;
	return &svg->super;
361 362
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
363 364
static void 
rsvg_node_use_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts)
365
{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
366 367 368
	const char *value = NULL, *klazz = NULL, *id = NULL;
	double font_size;	
	RsvgNodeUse * use;
369

370 371
	font_size = rsvg_state_current_font_size(ctx);

Caleb Michael Moore's avatar
Caleb Michael Moore committed
372
	use = (RsvgNodeUse *)self;
373 374 375
	if (rsvg_property_bag_size(atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "x")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
376
				use->x = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->width, font_size);
377
			if ((value = rsvg_property_bag_lookup (atts, "y")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
378
				use->y = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size);
379
			if ((value = rsvg_property_bag_lookup (atts, "width")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
380
				use->w = rsvg_css_parse_normalized_length (value, ctx->dpi_x, (gdouble)ctx->height, font_size);
381
			if ((value = rsvg_property_bag_lookup (atts, "height")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
382
				use->h = rsvg_css_parse_normalized_length (value, ctx->dpi_y, (gdouble)ctx->height, font_size);
383 384 385
			if ((value = rsvg_property_bag_lookup (atts, "class")))
				klazz = value;
			if ((value = rsvg_property_bag_lookup (atts, "id")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
386 387 388 389
				{
					id = value;
					rsvg_defs_register_name (ctx->defs, value, &use->super);
				}
390
			if ((value = rsvg_property_bag_lookup (atts, "xlink:href")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
391 392
				rsvg_defs_add_resolver (ctx->defs, &use->link, value);
			rsvg_parse_style_attrs (ctx, self->state, "use", klazz, id, atts);
393
		}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
394 395
	
}
396

Caleb Michael Moore's avatar
Caleb Michael Moore committed
397 398 399
RsvgNode *
rsvg_new_use ()
{
400 401
	RsvgNodeUse * use;
	use = g_new (RsvgNodeUse, 1);
402
	_rsvg_node_init(&use->super);
403
	use->super.type = RSVG_NODE_PATH;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
404 405
	use->super.free = rsvg_node_use_free;
	use->super.draw = rsvg_node_use_draw;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
406 407 408 409 410
	use->super.set_atts = rsvg_node_use_set_atts;
	use->x = 0;
	use->y = 0;
	use->w = 0;
	use->h = 0;
411
	use->link = NULL;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
412
	return (RsvgNode *)use;
413 414
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
415 416
static void 
rsvg_node_symbol_set_atts(RsvgNode *self, RsvgHandle *ctx, RsvgPropertyBag *atts)
417
{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
418
	RsvgNodeSymbol *symbol = (RsvgNodeSymbol *)self;
419

420
	const char * klazz = NULL, *value, *id = NULL;
421 422 423 424 425 426

	if (rsvg_property_bag_size(atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "class")))
				klazz = value;
			if ((value = rsvg_property_bag_lookup (atts, "id")))
427 428 429 430
				{
					id = value;
					rsvg_defs_register_name (ctx->defs, value, &symbol->super);
				}
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
			if ((value = rsvg_property_bag_lookup (atts, "viewBox")))
				{
					symbol->has_vbox = rsvg_css_parse_vbox (value, 
															&symbol->x, 
															&symbol->y,
															&symbol->width, 
															&symbol->height);
					if (symbol->has_vbox)
						{
							ctx->width = symbol->width;
							ctx->height = symbol->height;
						}
				}
			if ((value = rsvg_property_bag_lookup (atts, "preserveAspectRatio")))
				symbol->preserve_aspect_ratio = rsvg_css_parse_aspect_ratio (value);			
		}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
448 449
	rsvg_parse_style_attrs (ctx, self->state, "symbol", klazz, id, atts);
}
450 451


Caleb Michael Moore's avatar
Caleb Michael Moore committed
452 453
RsvgNode *
rsvg_new_symbol(void)
454
{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
455 456
	RsvgNodeSymbol * symbol;
	symbol = g_new (RsvgNodeSymbol, 1);
457
	_rsvg_node_init(&symbol->super);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
458 459 460
	symbol->has_vbox = 0;
	symbol->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
	symbol->super.type = RSVG_NODE_SYMBOL;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
461
	symbol->super.draw = _rsvg_node_draw_nothing;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
462 463 464
	symbol->super.set_atts = rsvg_node_symbol_set_atts;
	return &symbol->super;
}
465

Caleb Michael Moore's avatar
Caleb Michael Moore committed
466 467 468 469 470
RsvgNode *
rsvg_new_defs ()
{
	RsvgNodeGroup *group;
	group = g_new (RsvgNodeGroup, 1);
471
	_rsvg_node_init(&group->super);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
472
	group->super.type = RSVG_NODE_PATH;
473
	group->super.draw = _rsvg_node_draw_nothing;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
474 475
	group->super.set_atts = rsvg_node_group_set_atts;
	return &group->super;
476
}
Dom Lachowicz's avatar
Dom Lachowicz committed
477 478

static void 
Caleb Michael Moore's avatar
Caleb Michael Moore committed
479
_rsvg_node_switch_draw (RsvgNode * self, RsvgDrawingCtx *ctx, 
Dom Lachowicz's avatar
Dom Lachowicz committed
480 481 482 483
								 int dominate)
{
	guint i;

484
	rsvg_state_reinherit_top(ctx, self->state, dominate);
Dom Lachowicz's avatar
Dom Lachowicz committed
485 486 487

	rsvg_push_discrete_layer (ctx);	

488
	for (i = 0; i < self->children->len; i++)
Dom Lachowicz's avatar
Dom Lachowicz committed
489
		{
490
			RsvgNode * drawable = g_ptr_array_index(self->children, i);
Dom Lachowicz's avatar
Dom Lachowicz committed
491

492
			if (drawable->state->cond_true) {
Dom Lachowicz's avatar
Dom Lachowicz committed
493
				rsvg_state_push(ctx);
494
				rsvg_node_draw (g_ptr_array_index(self->children, i), 
Dom Lachowicz's avatar
Dom Lachowicz committed
495 496 497 498 499 500 501 502 503 504
										 ctx, 0);
				rsvg_state_pop(ctx);

				break; /* only render the 1st one */
			}
		}			

	rsvg_pop_discrete_layer (ctx);
}

Caleb Michael Moore's avatar
Caleb Michael Moore committed
505 506
RsvgNode *
rsvg_new_switch (void)
Dom Lachowicz's avatar
Dom Lachowicz committed
507
{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
508 509
	RsvgNodeGroup *group;
	group = g_new (RsvgNodeGroup, 1);
510
	_rsvg_node_init(&group->super);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
511 512 513 514
	group->super.type = RSVG_NODE_PATH;
	group->super.draw = _rsvg_node_switch_draw;
	group->super.set_atts = rsvg_node_group_set_atts;
	return &group->super;
Dom Lachowicz's avatar
Dom Lachowicz committed
515
}