Exemplo n.º 1
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;
}
Exemplo n.º 2
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;
}