rsvg-paint-server.c 20.8 KB
Newer Older
1
/* vim: set sw=4: -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 3 4 5 6 7
/* 
   rsvg-paint-server.c: Implement the SVG paint server abstraction.
 
   Copyright (C) 2000 Eazel, Inc.
  
   This program is free software; you can redistribute it and/or
8
   modify it under the terms of the GNU Library General Public License as
9 10 11 12 13 14
   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
15
   Library General Public License for more details.
16
  
17
   You should have received a copy of the GNU Library General Public
18 19 20 21 22 23 24
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
  
   Author: Raph Levien <raph@artofcode.com>
*/

25
#include "config.h"
26
#include "rsvg-private.h"
27 28
#include "rsvg-defs.h"
#include "rsvg-paint-server.h"
29
#include "rsvg-styles.h"
30
#include "rsvg-image.h"
31

32
#include <glib/gmem.h>
Darin Adler's avatar
Darin Adler committed
33
#include <glib/gmessages.h>
34 35
#include <glib/gstrfuncs.h>
#include <string.h>
36 37
#include <math.h>

38 39 40 41 42
#include "rsvg-css.h"

static RsvgPaintServer *
rsvg_paint_server_solid (guint32 rgb)
{
43
	RsvgPaintServer *result = g_new (RsvgPaintServer, 1);
44
	
45 46 47 48 49
	result->refcnt = 1;
	result->type = RSVG_PAINT_SERVER_SOLID;
	result->core.colour = g_new(RsvgSolidColour, 1);
	result->core.colour->rgb = rgb;
	result->core.colour->currentcolour = FALSE;
50
	
51
	return result;
52 53 54 55 56
}

static RsvgPaintServer *
rsvg_paint_server_solid_current_colour ()
{
57
	RsvgPaintServer *result = g_new (RsvgPaintServer, 1);
58
	
59 60 61 62
	result->refcnt = 1;
	result->type = RSVG_PAINT_SERVER_SOLID;
	result->core.colour = g_new(RsvgSolidColour, 1);
	result->core.colour->currentcolour = TRUE;
63
	
64
	return result;
65 66 67 68 69
}

static RsvgPaintServer *
rsvg_paint_server_lin_grad (RsvgLinearGradient *gradient)
{
70
	RsvgPaintServer *result = g_new (RsvgPaintServer, 1);
71
	
72 73 74
	result->refcnt = 1;
	result->type = RSVG_PAINT_SERVER_LIN_GRAD;
	result->core.lingrad = gradient;
75
	
76
	return result;
77 78 79 80 81
}

static RsvgPaintServer *
rsvg_paint_server_rad_grad (RsvgRadialGradient *gradient)
{
82
	RsvgPaintServer *result = g_new (RsvgPaintServer, 1);
Caleb Michael Moore's avatar
Caleb Michael Moore committed
83
	
84 85 86
	result->refcnt = 1;
	result->type = RSVG_PAINT_SERVER_RAD_GRAD;
	result->core.radgrad = gradient;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
87
	
88
	return result;
89 90 91 92 93
}

static RsvgPaintServer *
rsvg_paint_server_pattern (RsvgPattern *pattern)
{
94
	RsvgPaintServer *result = g_new (RsvgPaintServer, 1);
95
	
96 97
	result->refcnt = 1;
	result->type = RSVG_PAINT_SERVER_PATTERN;
98
	rsvg_pattern_fix_fallback(pattern);
99
	result->core.pattern = pattern;
100
	
101
	return result;
102 103
}

104 105 106 107 108 109 110 111 112 113 114
/**
 * rsvg_paint_server_parse: Parse an SVG paint specification.
 * @defs: Defs for looking up gradients.
 * @str: The SVG paint specification string to parse.
 *
 * Parses the paint specification @str, creating a new paint server
 * object.
 *
 * Return value: The newly created paint server, or NULL on error.
 **/
RsvgPaintServer *
115
rsvg_paint_server_parse (gboolean * inherit, const RsvgDefs *defs, const char *str,
116
						 guint32 current_color)
117
{
118
	guint32 rgb;
119 120
	if (inherit != NULL)
		*inherit = 1;
121 122
	if (!strcmp (str, "none"))
		return NULL;
123

124 125 126 127 128
	if (!strncmp (str, "url(", 4))
		{
			const char *p = str + 4;
			int ix;
			char *name;
129
			RsvgNode *val;
130 131 132 133 134 135 136 137 138 139 140 141 142
			
			while (g_ascii_isspace (*p)) p++;
			for (ix = 0; p[ix]; ix++)
				if (p[ix] == ')') break;
			if (p[ix] != ')')
				return NULL;
			name = g_strndup (p, ix);
			val = rsvg_defs_lookup (defs, name);
			g_free (name);
			if (val == NULL)
				return NULL;
			switch (val->type)
				{
143
				case RSVG_NODE_LINGRAD:
144
					return rsvg_paint_server_lin_grad ((RsvgLinearGradient *)val);
145
				case RSVG_NODE_RADGRAD:
146
					return rsvg_paint_server_rad_grad ((RsvgRadialGradient *)val);
147
				case RSVG_NODE_PATTERN:
148
					return rsvg_paint_server_pattern ((RsvgPattern *)val);
149 150 151 152
				default:
					return NULL;
				}
		}
153
	else if (!strcmp (str, "inherit"))
154
		{
155 156
			if (inherit != NULL)
				*inherit = 0;
Caleb Michael Moore's avatar
Caleb Michael Moore committed
157
			return rsvg_paint_server_solid (0);
158 159 160 161
		}
	else if (!strcmp (str, "currentColor"))
		{	
			RsvgPaintServer * ps;			
Caleb Michael Moore's avatar
Caleb Michael Moore committed
162
			ps = rsvg_paint_server_solid_current_colour ();
163
			return ps;
164 165
		}
	else
166
		{
Caleb Michael Moore's avatar
Caleb Michael Moore committed
167
			rgb = rsvg_css_parse_color (str, inherit);
168 169
			return rsvg_paint_server_solid (rgb);
		}
170 171 172 173 174 175 176 177 178
}

/**
 * rsvg_paint_server_ref: Reference a paint server object.
 * @ps: The paint server object to reference.
 **/
void
rsvg_paint_server_ref (RsvgPaintServer *ps)
{
179 180 181
	if (ps == NULL)
		return;
	ps->refcnt++;
182 183 184 185 186 187 188 189 190
}

/**
 * rsvg_paint_server_unref: Unreference a paint server object.
 * @ps: The paint server object to unreference.
 **/
void
rsvg_paint_server_unref (RsvgPaintServer *ps)
{
191 192 193
	if (ps == NULL)
		return;
	if (--ps->refcnt == 0)
194 195 196 197 198
		{
			if (ps->type == RSVG_PAINT_SERVER_SOLID)
				g_free(ps->core.colour);
			g_free (ps);
		}
199
}
200

201
static void
202 203
rsvg_stop_set_atts (RsvgNode *self, RsvgHandle *ctx,
					RsvgPropertyBag *atts)
204 205
{
	double offset = 0;
206
	gboolean is_current_color = FALSE;
207
	const char *value;
208 209 210 211
	RsvgGradientStop * stop;

	stop = (RsvgGradientStop *)self;

212 213 214 215 216
	if (rsvg_property_bag_size (atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "offset")))
				{
					/* either a number [0,1] or a percentage */
217
					offset = rsvg_css_parse_normalized_length (value, rsvg_dpi_percentage (ctx), 1., 0.);
218 219 220 221 222
					
					if (offset < 0.)
						offset = 0.;
					else if (offset > 1.)
						offset = 1.;
223
					stop->offset = offset;
224 225
				}
			if ((value = rsvg_property_bag_lookup (atts, "style")))
226
				rsvg_parse_style (ctx, self->state, value);
227 228 229
			
			if ((value = rsvg_property_bag_lookup (atts, "stop-color")))
				if (!strcmp(value, "currentColor"))
230 231 232
					is_current_color = TRUE;

			rsvg_parse_style_pairs (ctx, self->state, atts);
233
		}
234 235 236 237 238 239 240
	self->parent = ctx->currentnode;
	RsvgState state;
	rsvg_state_init(&state);
	rsvg_state_reconstruct(&state, self);
	if (is_current_color)
		state.stop_color = state.current_color;
	stop->rgba = (state.stop_color << 8) | state.stop_opacity;
241 242 243
	rsvg_state_finalize(&state);
}

244 245
RsvgNode *
rsvg_new_stop (void)
246
{
247
	RsvgGradientStop * stop = g_new(RsvgGradientStop, 1);
248
	_rsvg_node_init(&stop->super);
249 250 251
	stop->super.set_atts = rsvg_stop_set_atts;
	stop->offset = 0;
	stop->rgba = 0;
252
	stop->super.type = RSVG_NODE_STOP;
253
	return &stop->super;
254 255 256
}

static void
257
rsvg_linear_gradient_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts)
258
{
259 260 261
	RsvgLinearGradient *grad = (RsvgLinearGradient *)self;
	const char *value;
	double font_size = rsvg_state_current_font_size(ctx);
262 263 264 265
		
	if (rsvg_property_bag_size (atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "id")))
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
				rsvg_defs_register_name (ctx->defs, value, self);
			if ((value = rsvg_property_bag_lookup (atts, "x1"))){
				grad->x1 = rsvg_css_parse_normalized_length (value, ctx->dpi_x, 1, font_size);
				grad->hasx1 = TRUE;
			}				
			if ((value = rsvg_property_bag_lookup (atts, "y1"))){
				grad->y1 = rsvg_css_parse_normalized_length (value, ctx->dpi_y, 1, font_size);
				grad->hasy1 = TRUE;
			}				
			if ((value = rsvg_property_bag_lookup (atts, "x2"))){
				grad->x2 = rsvg_css_parse_normalized_length (value, ctx->dpi_x, 1, font_size);
				grad->hasx2 = TRUE;
			}	
			if ((value = rsvg_property_bag_lookup (atts, "y2"))){
				grad->y2 = rsvg_css_parse_normalized_length (value, ctx->dpi_y, 1, font_size);
				grad->hasy2 = TRUE;
			}	
		if ((value = rsvg_property_bag_lookup (atts, "spreadMethod")))
284 285
				{
					if (!strcmp (value, "pad")) {
286
						grad->spread = RSVG_GRADIENT_PAD;
287 288
					}
					else if (!strcmp (value, "reflect")) {
289
						grad->spread = RSVG_GRADIENT_REFLECT;
290 291
					}
					else if (!strcmp (value, "repeat")) {
292
						grad->spread = RSVG_GRADIENT_REPEAT;
293
					}
294
					grad->hasspread = TRUE;
295 296
				}
			if ((value = rsvg_property_bag_lookup (atts, "xlink:href")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
297
				rsvg_defs_add_resolver (ctx->defs, &grad->fallback, value);
298 299 300 301
			if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))){
				rsvg_parse_transform (grad->affine, value);
				grad->hastransform = TRUE;
			}
302
			if ((value = rsvg_property_bag_lookup (atts, "color")))
303
				grad->current_color = rsvg_css_parse_color (value, 0);
304 305
			if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
				if (!strcmp (value, "userSpaceOnUse"))
306
					grad->obj_bbox = FALSE;
307
				else if (!strcmp (value, "objectBoundingBox"))
308 309
					grad->obj_bbox = TRUE;
				grad->hasbbox = TRUE;
310
			}
311 312
			rsvg_parse_style_attrs (ctx, self->state, "linearGradient", 
									NULL, NULL, atts);
313 314 315
		}
}

316 317 318

RsvgNode *
rsvg_new_linear_gradient (void)
319
{
320 321
	RsvgLinearGradient *grad = NULL;
	grad = g_new (RsvgLinearGradient, 1);
322
	_rsvg_node_init(&grad->super);
323 324 325 326 327 328 329 330 331 332 333 334 335
	grad->super.type = RSVG_NODE_LINGRAD;
	_rsvg_affine_identity(grad->affine);
	grad->has_current_color = FALSE;
	grad->x1 = 0;
	grad->y1 = 0;
	grad->x2 = 1.0;
	grad->y2 = 0;
	grad->fallback = NULL;
	grad->obj_bbox = TRUE;
	grad->spread = RSVG_GRADIENT_PAD;
	grad->super.set_atts = rsvg_linear_gradient_set_atts;
	grad->hasx1 = grad->hasy1 = grad->hasx2 = grad->hasy2 = grad->hasbbox = grad->hasspread = grad->hastransform = FALSE;
	return &grad->super;
336 337
}

338 339
static void
rsvg_radial_gradient_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts)
340
{
341 342 343
	RsvgRadialGradient *grad = (RsvgRadialGradient *) self;
	const char *value;
	double font_size = rsvg_state_current_font_size(ctx);
344 345 346 347
	
	if (rsvg_property_bag_size (atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "id")))
348 349 350 351
				rsvg_defs_register_name (ctx->defs, value, self);
			if ((value = rsvg_property_bag_lookup (atts, "cx"))){
				grad->cx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, 1, font_size);	
				grad->hascx = TRUE;
352 353
				if (!grad->hasfx)
					grad->fx = grad->cx;
354
			}
355 356 357
			if ((value = rsvg_property_bag_lookup (atts, "cy"))){
				grad->cy = rsvg_css_parse_normalized_length (value, ctx->dpi_y, 1, font_size);	
				grad->hascy = TRUE;
358 359
				if (!grad->hasfy)
					grad->fy = grad->cy;
360
			}
361 362 363
			if ((value = rsvg_property_bag_lookup (atts, "r"))){
				grad->r = rsvg_css_parse_normalized_length (value, rsvg_dpi_percentage (ctx), 1, font_size);	
				grad->hasr = TRUE;
364
			}
365 366 367
			if ((value = rsvg_property_bag_lookup (atts, "fx"))){
				grad->fx = rsvg_css_parse_normalized_length (value, ctx->dpi_x, 1, font_size);	
				grad->hasfx = TRUE;
368
			}
369 370 371
			if ((value = rsvg_property_bag_lookup (atts, "fy"))){
				grad->fy = rsvg_css_parse_normalized_length (value, ctx->dpi_y, 1, font_size);
				grad->hasfy = TRUE;
372 373
			}
			if ((value = rsvg_property_bag_lookup (atts, "xlink:href")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
374
				rsvg_defs_add_resolver (ctx->defs, &grad->fallback, value);	
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
			if ((value = rsvg_property_bag_lookup (atts, "gradientTransform"))){
				rsvg_parse_transform (grad->affine, value);
				grad->hastransform = TRUE;
			}
			if ((value = rsvg_property_bag_lookup (atts, "color"))){
				grad->current_color = rsvg_css_parse_color (value, 0);
			}
			if ((value = rsvg_property_bag_lookup (atts, "spreadMethod"))){
				if (!strcmp (value, "pad"))
					grad->spread = RSVG_GRADIENT_PAD;
				else if (!strcmp (value, "reflect"))
					grad->spread = RSVG_GRADIENT_REFLECT;
				else if (!strcmp (value, "repeat"))
					grad->spread = RSVG_GRADIENT_REPEAT;
				grad->hasspread = TRUE;
390 391 392
			}
			if ((value = rsvg_property_bag_lookup (atts, "gradientUnits"))) {
				if (!strcmp (value, "userSpaceOnUse"))
393
					grad->obj_bbox = FALSE;
394
				else if (!strcmp (value, "objectBoundingBox"))
395 396
					grad->obj_bbox = TRUE;
				grad->hasbbox = TRUE;
397
			}
398 399
			rsvg_parse_style_attrs (ctx, self->state, "radialGradient", 
									NULL, NULL, atts);
400 401 402
		}
}

403 404
RsvgNode *
rsvg_new_radial_gradient (void)
405
{
406 407

	RsvgRadialGradient * grad = g_new (RsvgRadialGradient, 1);
408
	_rsvg_node_init(&grad->super);
409 410 411 412 413 414 415 416 417 418 419 420 421 422
	grad->super.type = RSVG_NODE_RADGRAD;
	_rsvg_affine_identity(grad->affine);
	grad->has_current_color = FALSE;
	grad->obj_bbox = TRUE;
	grad->spread = RSVG_GRADIENT_PAD;
	grad->fallback = NULL;
	grad->cx = 0.5;
	grad->cy = 0.5;
	grad->r = 0.5;
	grad->fx = 0.5;
	grad->fy = 0.5;
	grad->super.set_atts = rsvg_radial_gradient_set_atts;
	grad->hascx = grad->hascy = grad->hasfx = grad->hasfy = grad->hasr = grad->hasbbox = grad->hasspread = grad->hastransform = FALSE;
	return &grad->super;
423 424
}

425 426
static void
rsvg_pattern_set_atts (RsvgNode * self, RsvgHandle *ctx, RsvgPropertyBag *atts)
427
{
428 429 430
	RsvgPattern *pattern = (RsvgPattern *)self;
	const char  *value;
	double font_size = rsvg_state_current_font_size(ctx);
431 432 433 434

	if (rsvg_property_bag_size (atts))
		{
			if ((value = rsvg_property_bag_lookup (atts, "id")))
435 436 437 438 439 440 441 442 443 444 445 446
				rsvg_defs_register_name (ctx->defs, value, self);
			if ((value = rsvg_property_bag_lookup (atts, "viewBox"))){
				pattern->vbox = rsvg_css_parse_vbox (value, 
													 &pattern->vbx, 
													 &pattern->vby,
													 &pattern->vbw, 
													 &pattern->vbh);
				pattern->hasvbox = TRUE;
			}
			if ((value = rsvg_property_bag_lookup (atts, "x"))){
				pattern->x = rsvg_css_parse_normalized_length (value, ctx->dpi_x, 1, font_size);
				pattern->hasx = TRUE;
447
			}
448 449 450
			if ((value = rsvg_property_bag_lookup (atts, "y"))){
				pattern->y = rsvg_css_parse_normalized_length (value, ctx->dpi_y, 1, font_size);
				pattern->hasy = TRUE;			
451
			}
452 453 454
			if ((value = rsvg_property_bag_lookup (atts, "width"))){
				pattern->width = rsvg_css_parse_normalized_length (value, ctx->dpi_x, 1, font_size);
				pattern->haswidth = TRUE;
455
			}
456 457 458
			if ((value = rsvg_property_bag_lookup (atts, "height"))){
				pattern->height = rsvg_css_parse_normalized_length (value, ctx->dpi_y, 1, font_size);
				pattern->hasheight = TRUE;
459 460
			}
			if ((value = rsvg_property_bag_lookup (atts, "xlink:href")))
Caleb Michael Moore's avatar
Caleb Michael Moore committed
461
				rsvg_defs_add_resolver (ctx->defs, (RsvgNode **)&pattern->fallback, value);
462 463 464 465
			if ((value = rsvg_property_bag_lookup (atts, "patternTransform"))){
				rsvg_parse_transform (pattern->affine, value);
				pattern->hastransform = TRUE;
			}
466 467
			if ((value = rsvg_property_bag_lookup (atts, "patternUnits"))) {
				if (!strcmp (value, "userSpaceOnUse"))
468
					pattern->obj_bbox = FALSE;
469
				else if (!strcmp (value, "objectBoundingBox"))
470 471
					pattern->obj_bbox = TRUE;
				pattern->hasbbox = TRUE;
472 473 474
			}
			if ((value = rsvg_property_bag_lookup (atts, "patternContentUnits"))) {
				if (!strcmp (value, "userSpaceOnUse"))
475
					pattern->obj_cbbox = FALSE;
476
				else if (!strcmp (value, "objectBoundingBox"))
477 478 479 480 481 482
					pattern->obj_cbbox = TRUE;	
				pattern->hascbox = TRUE;
			}
			if ((value = rsvg_property_bag_lookup (atts, "preserveAspectRatio"))){
				pattern->preserve_aspect_ratio = rsvg_css_parse_aspect_ratio (value);
				pattern->hasaspect = TRUE;
483
			}
484 485
		}
}
486 487


488 489 490 491
RsvgNode *
rsvg_new_pattern (void)
{
	RsvgPattern *pattern = g_new (RsvgPattern, 1);
492
	_rsvg_node_init(&pattern->super);
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
	pattern->obj_bbox = TRUE;
	pattern->obj_cbbox = FALSE;
	pattern->x = 0;
	pattern->y = 0;
	pattern->width = 0;
	pattern->height = 0;
	pattern->vbx = 0;
	pattern->vby = 0;
	pattern->vbw = 1;
	pattern->vbh = 1;
	pattern->fallback = NULL;
	pattern->preserve_aspect_ratio = RSVG_ASPECT_RATIO_XMID_YMID;
	pattern->vbox = FALSE;
	_rsvg_affine_identity(pattern->affine);
	pattern->super.set_atts = rsvg_pattern_set_atts;
	pattern->super.type = RSVG_NODE_PATTERN;
	pattern->hasx = pattern->hasy = pattern->haswidth = pattern->hasheight = pattern->hasvbox = pattern->hasbbox = pattern->hascbox = pattern->hasaspect = pattern->hastransform = pattern->hasaspect = FALSE; 
	return &pattern->super;
}
512

Caleb Michael Moore's avatar
Caleb Michael Moore committed
513 514 515 516 517 518 519 520 521 522 523
static int hasstop(GPtrArray *lookin)
{
	unsigned int i;
	for (i = 0; i < lookin->len; i++)
		{
			if (((RsvgNode *)g_ptr_array_index(lookin, i))->type == RSVG_NODE_STOP)
				return 1;
		}
	return 0;
}

524 525 526 527 528 529 530
void
rsvg_linear_gradient_fix_fallback(RsvgLinearGradient * grad)
{
	RsvgNode * ufallback;
	int i;
	ufallback = grad->fallback;
	while (ufallback != NULL)
531
		{
532 533 534 535 536
			if (ufallback->type == RSVG_NODE_LINGRAD){
				RsvgLinearGradient * fallback = (RsvgLinearGradient *)ufallback;
				if (!grad->hasx1 && fallback->hasx1){
					grad->hasx1 = TRUE;
					grad->x1 = fallback->x1;
537
				}
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
				if (!grad->hasy1 && fallback->hasy1){
					grad->hasy1 = TRUE;
					grad->y1 = fallback->y1;
				}
				if (!grad->hasx2 && fallback->hasx2){
					grad->hasx2 = TRUE;
					grad->x2 = fallback->x2;
				}
				if (!grad->hasy2 && fallback->hasy2){
					grad->hasy2 = TRUE;
					grad->y2 = fallback->y2;
				}
				if (!grad->hastransform && fallback->hastransform){
					grad->hastransform = TRUE;
					for (i = 0; i < 6; i++)
						grad->affine[i] = fallback->affine[i];
				}
				if (!grad->hasspread && fallback->hasspread){
					grad->hasspread = TRUE;
557
					grad->spread = fallback->spread;
558 559 560 561 562
				}
				if (!grad->hasbbox && fallback->hasbbox){
					grad->hasbbox = TRUE;
					grad->obj_bbox = fallback->obj_bbox;
				}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
563
				if (!hasstop(grad->super.children) && hasstop(fallback->super.children)){
564 565 566 567 568 569 570 571 572 573 574 575 576
					grad->super.children = fallback->super.children;
				}
				ufallback = fallback->fallback; 
			}
			else if (ufallback->type == RSVG_NODE_RADGRAD){
				RsvgRadialGradient * fallback = (RsvgRadialGradient *)ufallback;
				if (!grad->hastransform && fallback->hastransform){
					grad->hastransform = TRUE;
					for (i = 0; i < 6; i++)
						grad->affine[i] = fallback->affine[i];
				}
				if (!grad->hasspread && fallback->hasspread){
					grad->hasspread = TRUE;
577
					grad->spread = fallback->spread;
578 579 580 581 582
				}
				if (!grad->hasbbox && fallback->hasbbox){
					grad->hasbbox = TRUE;
					grad->obj_bbox = fallback->obj_bbox;
				}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
583
				if (!hasstop(grad->super.children) && hasstop(fallback->super.children)){
584 585 586 587
					grad->super.children = fallback->super.children;
				}
				ufallback = fallback->fallback; 
			}
588
		}
589 590 591 592 593 594 595 596 597
}

void
rsvg_radial_gradient_fix_fallback(RsvgRadialGradient * grad)
{
	RsvgNode * ufallback;
	int i;
	ufallback = grad->fallback;
	while (ufallback != NULL)
598
		{
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
			if (ufallback->type == RSVG_NODE_RADGRAD){
				RsvgRadialGradient * fallback = (RsvgRadialGradient *)ufallback;
				if (!grad->hascx && fallback->hascx){
					grad->hascx = TRUE;
					grad->cx = fallback->cx;
				}
				if (!grad->hascy && fallback->hascy){
					grad->hascy = TRUE;
					grad->cy = fallback->cy;
				}
				if (!grad->hasfx && fallback->hasfx){
					grad->hasfx = TRUE;
					grad->fx = fallback->fx;
				}
				if (!grad->hasfy && fallback->hasfy){
					grad->hasfy = TRUE;
					grad->fy = fallback->fy;
				}
				if (!grad->hasr && fallback->hasr){
					grad->hasr = TRUE;
					grad->r = fallback->r;
				}
				if (!grad->hastransform && fallback->hastransform){
					grad->hastransform = TRUE;
					for (i = 0; i < 6; i++)
						grad->affine[i] = fallback->affine[i];
				}
				if (!grad->hasspread && fallback->hasspread){
					grad->hasspread = TRUE;
628
					grad->spread = fallback->spread;
629 630 631 632 633
				}
				if (!grad->hasbbox && fallback->hasbbox){
					grad->hasbbox = TRUE;
					grad->obj_bbox = fallback->obj_bbox;
				}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
634
				if (!hasstop(grad->super.children) && hasstop(fallback->super.children)){
635 636 637 638 639 640 641 642 643 644 645 646 647
					grad->super.children = fallback->super.children;
				}
				ufallback = fallback->fallback; 
			}
			else if (ufallback->type == RSVG_NODE_LINGRAD){
				RsvgLinearGradient * fallback = (RsvgLinearGradient *)ufallback;
				if (!grad->hastransform && fallback->hastransform){
					grad->hastransform = TRUE;
					for (i = 0; i < 6; i++)
						grad->affine[i] = fallback->affine[i];
				}
				if (!grad->hasspread && fallback->hasspread){
					grad->hasspread = TRUE;
648
					grad->spread = fallback->spread;
649 650 651 652 653
				}
				if (!grad->hasbbox && fallback->hasbbox){
					grad->hasbbox = TRUE;
					grad->obj_bbox = fallback->obj_bbox;
				}
Caleb Michael Moore's avatar
Caleb Michael Moore committed
654
				if (!hasstop(grad->super.children) && hasstop(fallback->super.children)){
655 656 657 658
					grad->super.children = fallback->super.children;
				}
				ufallback = fallback->fallback; 
			}
659 660 661
		}
}

662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685

void
rsvg_pattern_fix_fallback(RsvgPattern * pattern)
{
	RsvgPattern * fallback;
	int i;
	for (fallback = pattern->fallback; fallback != NULL; fallback = fallback->fallback)
		{
			if (!pattern->hasx && fallback->hasx){
				pattern->hasx = TRUE;
				pattern->x = fallback->x;
			}
			if (!pattern->hasy && fallback->hasy){
				pattern->hasy = TRUE;
				pattern->y = fallback->y;
			}
			if (!pattern->haswidth && fallback->haswidth){
				pattern->haswidth = TRUE;
				pattern->width = fallback->width;
			}
			if (!pattern->hasheight && fallback->hasheight){
				pattern->hasheight = TRUE;
				pattern->height = fallback->height;
			}
686 687 688 689 690
			if (!pattern->hastransform && fallback->hastransform){
					pattern->hastransform = TRUE;
					for (i = 0; i < 6; i++)
						pattern->affine[i] = fallback->affine[i];
				}
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715
			if (!pattern->hasvbox && fallback->hasvbox){
				pattern->hasvbox = TRUE;
				pattern->vbx = fallback->vbx;
				pattern->vby = fallback->vby;
				pattern->vbw = fallback->vbw;
				pattern->vbh = fallback->vbh;
				pattern->vbox = fallback->vbox;
			}
			if (!pattern->hasaspect && fallback->hasaspect){
				pattern->hasaspect = TRUE;
				pattern->preserve_aspect_ratio = fallback->preserve_aspect_ratio;
			}
			if (!pattern->hasbbox && fallback->hasbbox){
				pattern->hasbbox = TRUE;
				pattern->obj_bbox = fallback->obj_bbox;
			}
			if (!pattern->hascbox && fallback->hascbox){
				pattern->hascbox = TRUE;
				pattern->obj_cbbox = fallback->obj_cbbox;
			}
			if (!pattern->super.children->len && fallback->super.children->len){
				pattern->super.children = fallback->super.children;
			}
		}
}