Exemple #1
0
static fz_path *
svg_parse_polygon_imp(fz_context *ctx, svg_document *doc, fz_xml *node, int doclose)
{
	fz_path *path;

	const char *str = fz_xml_att(node, "points");
	float number;
	float args[2];
	int nargs;
	int isfirst;

	if (!str)
		return NULL;

	isfirst = 1;
	nargs = 0;

	path = fz_new_path(ctx);

	while (*str)
	{
		while (svg_is_whitespace_or_comma(*str))
			str ++;

		if (svg_is_digit(*str))
		{
			str = svg_lex_number(&number, str);
			args[nargs++] = number;
		}

		if (nargs == 2)
		{
			if (isfirst)
			{
				fz_moveto(ctx, path, args[0], args[1]);
				isfirst = 0;
			}
			else
			{
				fz_lineto(ctx, path, args[0], args[1]);
			}
			nargs = 0;
		}
	}

	return path;
}
Exemple #2
0
void
svg_parse_color(fz_context *ctx, svg_document *doc, const char *str, float *rgb)
{
	int i, l, m, r, cmp, n;

	rgb[0] = 0.0f;
	rgb[1] = 0.0f;
	rgb[2] = 0.0f;

	/* Crack hex-coded RGB */

	if (str[0] == '#')
	{
		str ++;

		n = strlen(str);
		if (n == 3 || (n > 3 && !ishex(str[3])))
		{
			rgb[0] = (unhex(str[0]) * 16 + unhex(str[0])) / 255.0f;
			rgb[1] = (unhex(str[1]) * 16 + unhex(str[1])) / 255.0f;
			rgb[2] = (unhex(str[2]) * 16 + unhex(str[2])) / 255.0f;
			return;
		}

		if (n >= 6)
		{
			rgb[0] = (unhex(str[0]) * 16 + unhex(str[1])) / 255.0f;
			rgb[1] = (unhex(str[2]) * 16 + unhex(str[3])) / 255.0f;
			rgb[2] = (unhex(str[4]) * 16 + unhex(str[5])) / 255.0f;
			return;
		}

		return;
	}

	/* rgb(X,Y,Z) -- whitespace allowed around numbers */

	else if (strstr(str, "rgb("))
	{
		int numberlen = 0;
		char numberbuf[50];

		str = str + 4;

		for (i = 0; i < 3; i++)
		{
			while (svg_is_whitespace_or_comma(*str))
				str ++;

			if (svg_is_digit(*str))
			{
				numberlen = 0;
				while (svg_is_digit(*str) && numberlen < sizeof(numberbuf) - 1)
					numberbuf[numberlen++] = *str++;
				numberbuf[numberlen] = 0;

				if (*str == '%')
				{
					str ++;
					rgb[i] = fz_atof(numberbuf) / 100.0f;
				}
				else
				{
					rgb[i] = fz_atof(numberbuf) / 255.0f;
				}
			}
		}

		return;
	}

	/* TODO: parse icc-profile(X,Y,Z,W) syntax */

	/* Search for a pre-defined color */

	else
	{
		char keyword[50], *p;
		fz_strlcpy(keyword, str, sizeof keyword);
		p = keyword;
		while (*p && *p >= 'a' && *p <= 'z')
			++p;
		*p = 0;

		l = 0;
		r = sizeof(svg_predefined_colors) / sizeof(svg_predefined_colors[0]);

		while (l <= r)
		{
			m = (l + r) / 2;
			cmp = strcmp(svg_predefined_colors[m].name, keyword);
			if (cmp > 0)
				r = m - 1;
			else if (cmp < 0)
				l = m + 1;
			else
			{
				rgb[0] = svg_predefined_colors[m].red / 255.0f;
				rgb[1] = svg_predefined_colors[m].green / 255.0f;
				rgb[2] = svg_predefined_colors[m].blue / 255.0f;
				return;
			}
		}
	}
}
Exemple #3
0
static fz_path *
svg_parse_path_data(fz_context *ctx, svg_document *doc, const char *str)
{
	fz_path *path = fz_new_path(ctx);

	fz_point p;
	float x1, y1, x2, y2;

	int cmd;
	float number;
	float args[6];
	int nargs;

	/* saved control point for smooth curves */
	int reset_smooth = 1;
	float smooth_x = 0.0;
	float smooth_y = 0.0;

	cmd = 0;
	nargs = 0;

	fz_try(ctx)
	{
		fz_moveto(ctx, path, 0.0, 0.0); /* for the case of opening 'm' */

		while (*str)
		{
			while (svg_is_whitespace_or_comma(*str))
				str ++;

			if (svg_is_digit(*str))
			{
				str = svg_lex_number(&number, str);
				if (nargs == 6)
					fz_throw(ctx, FZ_ERROR_GENERIC, "stack overflow in path data");
				args[nargs++] = number;
			}
			else if (svg_is_alpha(*str))
			{
				if (nargs != 0)
					fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in path data (wrong number of parameters to '%c')", cmd);
				cmd = *str++;
			}
			else if (*str == 0)
			{
				break;
			}
			else
			{
				fz_throw(ctx, FZ_ERROR_GENERIC, "syntax error in path data: '%c'", *str);
			}

			if (reset_smooth)
			{
				smooth_x = 0.0;
				smooth_y = 0.0;
			}

			reset_smooth = 1;

			switch (cmd)
			{
			case 'M':
				if (nargs == 2)
				{
					fz_moveto(ctx, path, args[0], args[1]);
					nargs = 0;
					cmd = 'L'; /* implicit lineto after */
				}
				break;

			case 'm':
				if (nargs == 2)
				{
					p = fz_currentpoint(ctx, path);
					fz_moveto(ctx, path, p.x + args[0], p.y + args[1]);
					nargs = 0;
					cmd = 'l'; /* implicit lineto after */
				}
				break;

			case 'Z':
			case 'z':
				if (nargs == 0)
				{
					fz_closepath(ctx, path);
				}
				break;

			case 'L':
				if (nargs == 2)
				{
					fz_lineto(ctx, path, args[0], args[1]);
					nargs = 0;
				}
				break;

			case 'l':
				if (nargs == 2)
				{
					p = fz_currentpoint(ctx, path);
					fz_lineto(ctx, path, p.x + args[0], p.y + args[1]);
					nargs = 0;
				}
				break;

			case 'H':
				if (nargs == 1)
				{
					p = fz_currentpoint(ctx, path);
					fz_lineto(ctx, path, args[0], p.y);
					nargs = 0;
				}
				break;

			case 'h':
				if (nargs == 1)
				{
					p = fz_currentpoint(ctx, path);
					fz_lineto(ctx, path, p.x + args[0], p.y);
					nargs = 0;
				}
				break;

			case 'V':
				if (nargs == 1)
				{
					p = fz_currentpoint(ctx, path);
					fz_lineto(ctx, path, p.x, args[0]);
					nargs = 0;
				}
				break;

			case 'v':
				if (nargs == 1)
				{
					p = fz_currentpoint(ctx, path);
					fz_lineto(ctx, path, p.x, p.y + args[0]);
					nargs = 0;
				}
				break;

			case 'C':
				reset_smooth = 0;
				if (nargs == 6)
				{
					fz_curveto(ctx, path, args[0], args[1], args[2], args[3], args[4], args[5]);
					smooth_x = args[4] - args[2];
					smooth_y = args[5] - args[3];
					nargs = 0;
				}
				break;

			case 'c':
				reset_smooth = 0;
				if (nargs == 6)
				{
					p = fz_currentpoint(ctx, path);
					fz_curveto(ctx, path,
						p.x + args[0], p.y + args[1],
						p.x + args[2], p.y + args[3],
						p.x + args[4], p.y + args[5]);
					smooth_x = args[4] - args[2];
					smooth_y = args[5] - args[3];
					nargs = 0;
				}
				break;

			case 'S':
				reset_smooth = 0;
				if (nargs == 4)
				{
					p = fz_currentpoint(ctx, path);
					fz_curveto(ctx, path,
							p.x + smooth_x, p.y + smooth_y,
							args[0], args[1],
							args[2], args[3]);
					smooth_x = args[2] - args[0];
					smooth_y = args[3] - args[1];
					nargs = 0;
				}
				break;

			case 's':
				reset_smooth = 0;
				if (nargs == 4)
				{
					p = fz_currentpoint(ctx, path);
					fz_curveto(ctx, path,
							p.x + smooth_x, p.y + smooth_y,
							p.x + args[0], p.y + args[1],
							p.x + args[2], p.y + args[3]);
					smooth_x = args[2] - args[0];
					smooth_y = args[3] - args[1];
					nargs = 0;
				}
				break;

			case 'Q':
				reset_smooth = 0;
				if (nargs == 4)
				{
					p = fz_currentpoint(ctx, path);
					x1 = args[0];
					y1 = args[1];
					x2 = args[2];
					y2 = args[3];
					fz_curveto(ctx, path,
							(p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3,
							(x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3,
							x2, y2);
					smooth_x = x2 - x1;
					smooth_y = y2 - y1;
					nargs = 0;
				}
				break;

			case 'q':
				reset_smooth = 0;
				if (nargs == 4)
				{
					p = fz_currentpoint(ctx, path);
					x1 = args[0] + p.x;
					y1 = args[1] + p.y;
					x2 = args[2] + p.x;
					y2 = args[3] + p.y;
					fz_curveto(ctx, path,
							(p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3,
							(x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3,
							x2, y2);
					smooth_x = x2 - x1;
					smooth_y = y2 - y1;
					nargs = 0;
				}
				break;

			case 'T':
				reset_smooth = 0;
				if (nargs == 4)
				{
					p = fz_currentpoint(ctx, path);
					x1 = p.x + smooth_x;
					y1 = p.y + smooth_y;
					x2 = args[0];
					y2 = args[1];
					fz_curveto(ctx, path,
							(p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3,
							(x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3,
							x2, y2);
					smooth_x = x2 - x1;
					smooth_y = y2 - y1;
					nargs = 0;
				}
				break;

			case 't':
				reset_smooth = 0;
				if (nargs == 4)
				{
					p = fz_currentpoint(ctx, path);
					x1 = p.x + smooth_x;
					y1 = p.y + smooth_y;
					x2 = args[0] + p.x;
					y2 = args[1] + p.y;
					fz_curveto(ctx, path,
							(p.x + 2 * x1) / 3, (p.y + 2 * y1) / 3,
							(x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3,
							x2, y2);
					smooth_x = x2 - x1;
					smooth_y = y2 - y1;
					nargs = 0;
				}
				break;

			case 0:
				if (nargs != 0)
					fz_throw(ctx, FZ_ERROR_GENERIC, "path data must begin with a command");
				break;

			default:
				fz_throw(ctx, FZ_ERROR_GENERIC, "unrecognized command in path data: '%c'", cmd);
			}
		}
	}
	fz_catch(ctx)
	{
		fz_drop_path(ctx, path);
		fz_rethrow(ctx);
	}

	return path;
}
Exemple #4
0
/* Coordinate transformations */
fz_matrix
svg_parse_transform(fz_context *ctx, svg_document *doc, const char *str, fz_matrix transform)
{
	char keyword[20];
	int keywordlen;
	float args[6];
	int nargs;

	nargs = 0;
	keywordlen = 0;

	while (*str)
	{
		while (svg_is_whitespace_or_comma(*str))
			str ++;
		if (*str == 0)
			break;

		/*
		 * Parse keyword and opening parenthesis.
		 */

		keywordlen = 0;
		while (svg_is_alpha(*str) && keywordlen < sizeof(keyword) - 1)
			keyword[keywordlen++] = *str++;
		keyword[keywordlen] = 0;

		if (keywordlen == 0)
			fz_throw(ctx, FZ_ERROR_SYNTAX, "expected keyword in transform attribute");

		while (svg_is_whitespace(*str))
			str ++;

		if (*str != '(')
			fz_throw(ctx, FZ_ERROR_SYNTAX, "expected opening parenthesis in transform attribute");
		str ++;

		/*
		 * Parse list of numbers until closing parenthesis
		 */

		nargs = 0;
		while (*str && *str != ')' && nargs < 6)
		{
			while (svg_is_whitespace_or_comma(*str))
				str ++;
			if (svg_is_digit(*str))
				str = svg_lex_number(&args[nargs++], str);
		}

		if (*str != ')')
			fz_throw(ctx, FZ_ERROR_SYNTAX, "expected closing parenthesis in transform attribute");
		str ++;

		/*
		 * Execute the transform.
		 */

		if (!strcmp(keyword, "matrix"))
		{
			fz_matrix m;

			if (nargs != 6)
				fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to matrix(): %d", nargs);

			m.a = args[0];
			m.b = args[1];
			m.c = args[2];
			m.d = args[3];
			m.e = args[4];
			m.f = args[5];

			transform = fz_concat(transform, m);
		}

		else if (!strcmp(keyword, "translate"))
		{
			if (nargs != 2)
				fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to translate(): %d", nargs);

			transform = fz_pre_translate(transform, args[0], args[1]);
		}

		else if (!strcmp(keyword, "scale"))
		{
			if (nargs == 1)
				transform = fz_pre_scale(transform, args[0], args[0]);
			else if (nargs == 2)
				transform = fz_pre_scale(transform, args[0], args[1]);
			else
				fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to scale(): %d", nargs);
		}

		else if (!strcmp(keyword, "rotate"))
		{
			if (nargs != 1)
				fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to rotate(): %d", nargs);
			transform = fz_pre_rotate(transform, args[0]);
		}

		else if (!strcmp(keyword, "skewX"))
		{
			fz_matrix m;

			if (nargs != 1)
				fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to skewX(): %d", nargs);

			m.a = 1;
			m.b = 0;
			m.c = tanf(args[0] * FZ_DEGREE);
			m.d = 1;
			m.e = 0;
			m.f = 0;

			transform = fz_concat(transform, m);
		}

		else if (!strcmp(keyword, "skewY"))
		{
			fz_matrix m;

			if (nargs != 1)
				fz_throw(ctx, FZ_ERROR_SYNTAX, "wrong number of arguments to skewY(): %d", nargs);

			m.a = 1;
			m.b = tanf(args[0] * FZ_DEGREE);
			m.c = 0;
			m.d = 1;
			m.e = 0;
			m.f = 0;

			transform = fz_concat(transform, m);
		}

		else
		{
			fz_throw(ctx, FZ_ERROR_SYNTAX, "unknown transform function: %s", keyword);
		}
	}

	return transform;
}