1/*
2 * Copyright 2006, Haiku Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Marc Flerackers (mflerackers@androme.be)
7 */
8
9
10#include "SVGViewView.h"
11
12
13named_color colors[] = {
14	{ "aliceblue",			{ 240, 248, 255, 255 } },
15	{ "antiquewhite",		{ 250, 235, 215, 255 } },
16	{ "aqua",				{ 0,   255, 255, 255 } },
17	{ "aquamarine",			{ 127, 255, 212, 255 } },
18	{ "azure",				{ 240, 255, 255, 255 } },
19	{ "beige",				{ 245, 245, 220, 255 } },
20	{ "bisque",				{ 255, 228, 196, 255 } },
21	{ "black",				{ 0,   0,   0,   255 } },
22	{ "blanchedalmond",		{ 255, 235, 205, 255 } },
23	{ "blue",				{ 0,   0,   255, 255 } },
24	{ "blueviolet",			{ 138, 43,  226, 255 } },
25	{ "brown",				{ 165, 42,  42,  255 } },
26	{ "burlywood",			{ 222, 184, 135, 255 } },
27	{ "cadetblue",			{ 95,  158, 160, 255 } },
28	{ "chartreuse",			{ 127, 255, 0,   255 } },
29	{ "chocolate",			{ 210, 105, 30,  255 } },
30	{ "coral",				{ 255, 127, 80,  255 } },
31	{ "cornflowerblue",		{ 100, 149, 237, 255 } },
32	{ "cornsilk",			{ 255, 248, 220, 255 } },
33	{ "crimson",			{ 220, 20,  60,  255 } },
34	{ "cyan",				{ 0,   255, 255, 255 } },
35	{ "darkblue",			{ 0,   0,   139, 255 } },
36	{ "darkcyan",			{ 0,   139, 139, 255 } },
37	{ "darkgoldenrod",		{ 184, 134, 11,  255 } },
38	{ "darkgray",			{ 169, 169, 169, 255 } },
39	{ "darkgreen",			{ 0,   100, 0,   255 } },
40	{ "darkgrey",			{ 169, 169, 169, 255 } },
41	{ "darkkhaki",			{ 189, 183, 107, 255 } },
42	{ "darkmagenta",		{ 139, 0,   139, 255 } },
43	{ "darkolivegreen",		{ 85,  107, 47,  255 } },
44	{ "darkorange",			{ 255, 140, 0,   255 } },
45	{ "darkorchid",			{ 153, 50,  204, 255 } },
46	{ "darkred",			{ 139, 0,   0,   255 } },
47	{ "darksalmon",			{ 233, 150, 122, 255 } },
48	{ "darkseagreen",		{ 143, 188, 143, 255 } },
49	{ "darkslateblue",		{ 72,  61,  139, 255 } },
50	{ "darkslategray",		{ 47,  79,  79,  255 } },
51	{ "darkslategrey",		{ 47,  79,  79,  255 } },
52	{ "darkturquoise",		{ 0,   206, 209, 255 } },
53	{ "darkviolet",			{ 148, 0,   211, 255 } },
54	{ "deeppink",			{ 255, 20,  147, 255 } },
55	{ "deepskyblue",		{ 0,   191, 255, 255 } },
56	{ "dimgray",			{ 105, 105, 105, 255 } },
57	{ "dimgrey",			{ 105, 105, 105, 255 } },
58	{ "dodgerblue",			{ 30,  144, 255, 255 } },
59	{ "firebrick",			{ 178, 34,  34,  255 } },
60	{ "floralwhite",		{ 255, 250, 240, 255 } },
61	{ "forestgreen",		{ 34,  139, 34,  255 } },
62	{ "fuchsia",			{ 255, 0,   255, 255 } },
63	{ "gainsboro",			{ 220, 220, 220, 255 } },
64	{ "ghostwhite",			{ 248, 248, 255, 255 } },
65	{ "gold",				{ 255, 215, 0,   255 } },
66	{ "goldenrod",			{ 218, 165, 32,  255 } },
67	{ "gray",				{ 128, 128, 128, 255 } },
68	{ "grey",				{ 128, 128, 128, 255 } },
69	{ "green",				{ 0,   128, 0,   255 } },
70	{ "greenyellow",		{ 173, 255, 47,  255 } },
71	{ "honeydew",			{ 240, 255, 240, 255 } },
72	{ "hotpink",			{ 255, 105, 180, 255 } },
73	{ "indianred",			{ 205, 92,  92,  255 } },
74	{ "indigo",				{ 75,  0,   130, 255 } },
75	{ "ivory",				{ 255, 255, 240, 255 } },
76	{ "khaki",				{ 240, 230, 140, 255 } },
77	{ "lavender",			{ 230, 230, 250, 255 } },
78	{ "lavenderblush",		{ 255, 240, 245, 255 } },
79	{ "lawngreen",			{ 124, 252, 0,   255 } },
80	{ "lemonchiffon",		{ 255, 250, 205, 255 } },
81	{ "lightblue",			{ 173, 216, 230, 255 } },
82	{ "lightcoral",			{ 240, 128, 128, 255 } },
83	{ "lightcyan",			{ 224, 255, 255, 255 } },
84	{ "lightgoldenrodyellow",{ 250, 250, 210, 255 } },
85	{ "lightgray",			{ 211, 211, 211, 255 } },
86	{ "lightgreen",			{ 144, 238, 144, 255 } },
87	{ "lightgrey",			{ 211, 211, 211, 255 } },
88	{ "lightpink",			{ 255, 182, 193, 255 } },
89	{ "lightsalmon",		{ 255, 160, 122, 255 } },
90	{ "lightseagreen",		{ 32, 178, 170, 255 } },
91	{ "lightskyblue",		{ 135, 206, 250, 255 } },
92	{ "lightslategray",		{ 119, 136, 153, 255 } },
93	{ "lightslategrey",		{ 119, 136, 153, 255 } },
94	{ "lightsteelblue",		{ 176, 196, 222, 255 } },
95	{ "lightyellow",		{ 255, 255, 224, 255 } },
96	{ "lime",				{ 0,   255, 0,   255 } },
97	{ "limegreen",			{ 50,  205, 50,  255 } },
98	{ "linen",				{ 250, 240, 230, 255 } },
99	{ "magenta",			{ 255, 0,   255, 255 } },
100	{ "maroon",				{ 128, 0,   0,   255 } },
101	{ "mediumaquamarine",	{ 102, 205, 170, 255 } },
102	{ "mediumblue",			{ 0,   0,   205, 255 } },
103	{ "mediumorchid",		{ 186, 85,  211, 255 } },
104	{ "mediumpurple",		{ 147, 112, 219, 255 } },
105	{ "mediumseagreen",		{ 60,  179, 113, 255 } },
106	{ "mediumslateblue",	{ 123, 104, 238, 255 } },
107	{ "mediumspringgreen",	{ 0,   250, 154, 255 } },
108	{ "mediumturquoise",	{ 72,  209, 204, 255 } },
109	{ "mediumvioletred",	{ 199, 21,  133, 255 } },
110	{ "midnightblue",		{ 25,  25,  112, 255 } },
111	{ "mintcream",			{ 245, 255, 250, 255 } },
112	{ "mistyrose",			{ 255, 228, 225, 255 } },
113	{ "moccasin",			{ 255, 228, 181, 255 } },
114	{ "navajowhite",		{ 255, 222, 173, 255 } },
115	{ "navy",				{ 0,   0,   128, 255 } },
116	{ "oldlace",			{ 253, 245, 230, 255 } },
117	{ "olive",				{ 128, 128, 0,   255 } },
118	{ "olivedrab",			{ 107, 142, 35,  255 } },
119	{ "orange",				{ 255, 165, 0,   255 } },
120	{ "orangered",			{ 255, 69,  0,   255 } },
121	{ "orchid",				{ 218, 112, 214, 255 } },
122	{ "palegoldenrod",		{ 238, 232, 170, 255 } },
123	{ "palegreen",			{ 152, 251, 152, 255 } },
124	{ "paleturquoise",		{ 175, 238, 238, 255 } },
125	{ "palevioletred",		{ 219, 112, 147, 255 } },
126	{ "papayawhip",			{ 255, 239, 213, 255 } },
127	{ "peachpuff",			{ 255, 218, 185, 255 } },
128	{ "peru",				{ 205, 133, 63,  255 } },
129	{ "pink",				{ 255, 192, 203, 255 } },
130	{ "plum",				{ 221, 160, 221, 255 } },
131	{ "powderblue",			{ 176, 224, 230, 255 } },
132	{ "purple",				{ 128, 0,   128, 255 } },
133	{ "red",				{ 255, 0,   0,   255 } },
134	{ "rosybrown",			{ 188, 143, 143, 255 } },
135	{ "royalblue",			{ 65,  105, 225, 255 } },
136	{ "saddlebrown",		{ 139, 69,  19,  255 } },
137	{ "salmon",				{ 250, 128, 114, 255 } },
138	{ "sandybrown",			{ 244, 164, 96,  255 } },
139	{ "seagreen",			{ 46,  139, 87,  255 } },
140	{ "seashell",			{ 255, 245, 238, 255 } },
141	{ "sienna",				{ 160, 82,  45,  255 } },
142	{ "silver",				{ 192, 192, 192, 255 } },
143	{ "skyblue",			{ 135, 206, 235, 255 } },
144	{ "slateblue",			{ 106, 90,  205, 255 } },
145	{ "slategray",			{ 112, 128, 144, 255 } },
146	{ "slategrey",			{ 112, 128, 144, 255 } },
147	{ "snow",				{ 255, 250, 250, 255 } },
148	{ "springgreen",		{ 0,   255, 127, 255 } },
149	{ "steelblue",			{ 70,  130, 180, 255 } },
150	{ "tan",				{ 210, 180, 140, 255 } },
151	{ "teal",				{ 0,   128, 128, 255 } },
152	{ "thistle",			{ 216, 191, 216, 255 } },
153	{ "tomato",				{ 255, 99,  71,  255 } },
154	{ "turquoise",			{ 64,  224, 208, 255 } },
155	{ "violet",				{ 238, 130, 238, 255 } },
156	{ "wheat",				{ 245, 222, 179, 255 } },
157	{ "white",				{ 255, 255, 255, 255 } },
158	{ "whitesmoke",			{ 245, 245, 245, 255 } },
159	{ "yellow",				{ 255, 255, 0,   255 } },
160	{ "yellowgreen",		{ 154, 205, 50,  255 } },
161	{ NULL		,			{ 0,   0,	  0, 255 } },
162};
163
164// Globals ---------------------------------------------------------------------
165
166// Svg2PictureView class -------------------------------------------------------
167Svg2PictureView::Svg2PictureView(BRect frame, const char *filename)
168    :   BView(frame, "", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
169	fFileName(filename),
170	fPicture(NULL)
171{
172	fPicture = new BPicture();
173}
174
175
176Svg2PictureView::~Svg2PictureView()
177{
178	delete fPicture;
179}
180
181
182void
183Svg2PictureView::AttachedToWindow()
184{
185	BeginPicture(fPicture);
186
187	bool done = false;
188	FILE *file = fopen(fFileName.String(), "rb");
189
190	if (file) {
191		XML_Parser parser = XML_ParserCreate("UTF-8");
192		XML_SetUserData(parser, this);
193		XML_SetElementHandler(parser, (XML_StartElementHandler)_StartElement, (XML_EndElementHandler)_EndElement);
194		XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)_CharacterDataHandler);
195
196		while (!done) {
197			char buf[256];
198			size_t len = fread(buf, 1, sizeof(buf), file);
199			done = len < sizeof(buf);
200            		if (!XML_Parse(parser, buf, len, done))
201                		break;
202        	}
203
204        	XML_ParserFree(parser);
205        	fclose(file);
206	}
207	fPicture = EndPicture();
208}
209
210
211void
212Svg2PictureView::Draw(BRect updateRect)
213{
214	if (fPicture)
215		DrawPicture(fPicture);
216}
217
218
219//------------------------------------------------------------------------------
220bool Svg2PictureView::HasAttribute(const XML_Char **attributes, const char *name) {
221    while (*attributes && strcasecmp(*attributes, name) != 0)
222        attributes += 2;
223
224    return (*attributes);
225}
226//------------------------------------------------------------------------------
227float Svg2PictureView::GetFloatAttribute(const XML_Char **attributes, const char *name) {
228    while (*attributes && strcasecmp(*attributes, name) != 0)
229        attributes += 2;
230
231	if (*attributes)
232		return atof(*(attributes + 1));
233	else
234		return 0;
235}
236//------------------------------------------------------------------------------
237const char *Svg2PictureView::GetStringAttribute(const XML_Char **attributes, const char *name) {
238    while (*attributes && strcasecmp(*attributes, name) != 0)
239        attributes += 2;
240
241	if (*attributes)
242		return *(attributes + 1);
243	else
244		return NULL;
245}
246//------------------------------------------------------------------------------
247rgb_color Svg2PictureView::GetColorAttribute(const XML_Char **attributes, const char *name, uint8 alpha) {
248    const char *attr = GetStringAttribute(attributes, name);
249
250	if (!attr)
251		return colors[0].color;
252
253	int32 red, green, blue;
254
255	if (attr[0] == '#') {
256		if (strlen(attr) == 4) {
257			sscanf(attr, "#%1X%1X%1X", &red, &green, &blue);
258			red = (red << 4) + red;
259			green = (green << 4) + green;
260			blue = (blue << 4) + blue;
261		}
262		else
263			sscanf(attr, "#%2X%2X%2X", &red, &green, &blue);
264
265		rgb_color color;
266
267		color.red = red;
268		color.green = green;
269		color.blue = blue;
270		color.alpha = alpha;
271
272		return color;
273	}
274
275	if (sscanf(attr, "rgb(%d, %d, %d)", &red, &green, &blue) == 3) {
276		rgb_color color;
277
278		color.red = red;
279		color.green = green;
280		color.blue = blue;
281		color.alpha = alpha;
282
283		return color;
284	}
285
286	float redf, greenf, bluef;
287
288	if (sscanf(attr, "rgb(%f%%, %f%%, %f%%)", &redf, &greenf, &bluef) == 3) {
289		rgb_color color;
290
291		color.red = (int32)(redf * 2.55f);
292		color.green = (int32)(greenf * 2.55f);
293		color.blue = (int32)(bluef * 2.55f);
294		color.alpha = alpha;
295
296		return color;
297	}
298
299	if (strcasecmp(attr, "url")) {
300		const char *grad = strchr(attr, '#');
301
302		if (grad) {
303			for (int32 i = 0; i < fGradients.CountItems(); i++) {
304				named_color *item = (named_color*)fGradients.ItemAt(i);
305
306				if (strstr(grad, item->name)) {
307					rgb_color color = item->color;
308					color.alpha = alpha;
309					return color;
310				}
311			}
312		}
313	}
314
315	for (int32 i = 0; colors[i].name != NULL; i++)
316		if (strcasecmp(colors[i].name, attr) == 0) {
317			rgb_color color = colors[i].color;
318			color.alpha = alpha;
319			return color;
320		}
321
322	rgb_color color = colors[0].color;
323	color.alpha = alpha;
324	return color;
325}
326//------------------------------------------------------------------------------
327void Svg2PictureView::GetPolygonAttribute(const XML_Char **attributes, const char *name, BShape &shape) {
328	const char *attr = NULL;
329
330	while (*attributes && strcasecmp(*attributes, name) != 0)
331        attributes += 2;
332
333    if (*attributes)
334		attr = *(attributes + 1);
335
336	if (!attr)
337		return;
338
339	char *ptr = const_cast<char*>(attr);
340	BPoint point;
341	bool first = true;
342
343	while (*ptr) {
344		// Skip white space and ','
345		while (*ptr && (*ptr == ' ') || (*ptr == ','))
346			ptr++;
347
348		sscanf(ptr, "%f", &point.x);
349
350		// Skip x
351		while (*ptr && *ptr != ',')
352			ptr++;
353		if (!*ptr || !*(ptr + 1))
354			break;
355		ptr++;
356
357		sscanf(ptr, "%f", &point.y);
358
359		if (first)
360		{
361			shape.MoveTo(point);
362			first = false;
363		}
364		else
365			shape.LineTo(point);
366
367		// Skip y
368		while (*ptr && (*ptr != ' ') && (*ptr != ','))
369			ptr++;
370	}
371}
372//------------------------------------------------------------------------------
373void Svg2PictureView::GetMatrixAttribute(const XML_Char **attributes, const char *name, BMatrix *matrix) {
374	const char *attr = NULL;
375
376	while (*attributes && strcasecmp(*attributes, name) != 0)
377        attributes += 2;
378
379    if (*attributes)
380		attr = *(attributes + 1);
381
382	if (!attr)
383		return;
384
385	char *ptr = (char*)attr;
386
387	while (*ptr) {
388		while (*ptr == ' ')
389			ptr++;
390
391		char *transform_name = ptr;
392
393		while (*ptr != '(')
394			ptr++;
395
396		if (strncmp(transform_name, "translate", 9) == 0) {
397			float x, y;
398
399			if (sscanf(ptr, "(%f %f)", &x, &y) != 2)
400				sscanf(ptr, "(%f,%f)", &x, &y);
401
402			matrix->Translate(x, y);
403		}
404		else if (strncmp(transform_name, "rotate", 6) == 0) {
405			float angle;
406
407			sscanf(ptr, "(%f)", &angle);
408
409			matrix->Rotate(angle);
410		}
411		else if (strncmp(transform_name, "scale", 5) == 0) {
412			float sx, sy;
413
414			if (sscanf(ptr, "(%f,%f)", &sx, &sy) == 2)
415				matrix->Scale(sx, sy);
416			else
417			{
418				sscanf(ptr, "(%f)", &sx);
419				matrix->Scale(sx, sx);
420			}
421		}
422		else if (strncmp(transform_name, "skewX", 5) == 0) {
423			float angle;
424
425			sscanf(ptr, "(%f)", &angle);
426
427			matrix->SkewX(angle);
428		}
429		else if (strncmp(transform_name, "skewY", 5) == 0) {
430			float angle;
431
432			sscanf(ptr, "(%f)", &angle);
433
434			matrix->SkewY(angle);
435		}
436
437		while (*ptr != ')')
438			ptr++;
439
440		ptr++;
441	}
442}
443//------------------------------------------------------------------------------
444double CalcVectorAngle(double ux, double uy, double vx, double vy) {
445	double ta = atan2(uy, ux);
446	double tb = atan2(vy, vx);
447
448	if (tb >= ta)
449		return tb - ta;
450
451	return 6.28318530718 - (ta - tb);
452}
453//------------------------------------------------------------------------------
454char *SkipFloat(char *string) {
455	if (*string == '-')
456		string++;
457
458	int32 len = strspn(string, "1234567890.");
459
460	return string + len;
461}
462//------------------------------------------------------------------------------
463char *FindFloat(char *string) {
464	return strpbrk(string, "1234567890-.");
465}
466//------------------------------------------------------------------------------
467float GetFloat(char **string) {
468	*string = FindFloat(*string);
469	float f = atof(*string);
470	*string = SkipFloat(*string);
471	return f;
472}
473//------------------------------------------------------------------------------
474void Svg2PictureView::GetShapeAttribute(const XML_Char **attributes, const char *name, BShape &shape) {
475	const char *attr = GetStringAttribute(attributes, name);
476
477	if (!attr)
478		return;
479
480	char *ptr = const_cast<char*>(attr);
481	float x, y, x1, y1, x2, y2, rx, ry, angle;
482	bool largeArcFlag, sweepFlag;
483	char command, prevCommand = 0;
484	BPoint prevCtlPt;
485	BPoint pos, startPos;
486	bool canMove = true;
487
488	while (*ptr) {
489		ptr = strpbrk(ptr, "ZzMmLlCcQqAaHhVvSsTt");
490
491		if (ptr == NULL)
492			break;
493
494		command = *ptr;
495
496		switch (command) {
497			case 'Z':
498			case 'z':
499			{
500				pos.Set(startPos.x, startPos.y);
501				canMove = true;
502				shape.Close();
503				ptr++;
504				break;
505			}
506			case 'M':
507			{
508				x = GetFloat(&ptr);
509				y = GetFloat(&ptr);
510
511				pos.Set(x, y);
512				if (canMove)
513					startPos = pos;
514				shape.MoveTo(pos);
515				break;
516			}
517			case 'm':
518			{
519				x = GetFloat(&ptr);
520				y = GetFloat(&ptr);
521
522				pos.x += x;
523				pos.y += y;
524				if (canMove)
525					startPos = pos;
526				shape.MoveTo(pos);
527				break;
528			}
529			case 'L':
530			{
531				x = GetFloat(&ptr);
532				y = GetFloat(&ptr);
533
534				pos.Set(x, y);
535				canMove = false;
536				shape.LineTo(pos);
537				break;
538			}
539			case 'l':
540			{
541				x = GetFloat(&ptr);
542				y = GetFloat(&ptr);
543
544				pos.x += x;
545				pos.y += y;
546				canMove = false;
547				shape.LineTo(pos);
548				break;
549			}
550			case 'C':
551			case 'c':
552			{
553				if (command == 'C') {
554					x1 = GetFloat(&ptr);
555					y1 = GetFloat(&ptr);
556					x2 = GetFloat(&ptr);
557					y2 = GetFloat(&ptr);
558					x = GetFloat(&ptr);
559					y = GetFloat(&ptr);
560				}
561				else {
562					x1 = GetFloat(&ptr);
563					y1 = GetFloat(&ptr);
564					x2 = GetFloat(&ptr);
565					y2 = GetFloat(&ptr);
566					x = GetFloat(&ptr);
567					y = GetFloat(&ptr);
568
569					x1 += pos.x;
570					y1 += pos.y;
571					x2 += pos.x;
572					y2 += pos.y;
573					x += pos.x;
574					y += pos.y;
575				}
576
577				BPoint controlPoints[3];
578
579				controlPoints[0].Set(x1, y1);
580				controlPoints[1].Set(x2, y2);
581				controlPoints[2].Set(x, y);
582
583				pos.Set(x, y);
584				prevCtlPt = controlPoints[1];
585				canMove = false;
586				shape.BezierTo(controlPoints);
587				break;
588			}
589			case 'Q':
590			case 'q':
591			{
592				if (command == 'Q') {
593				    x1 = GetFloat(&ptr);
594					y1 = GetFloat(&ptr);
595					x = GetFloat(&ptr);
596					y = GetFloat(&ptr);
597				}
598				else {
599					x1 = GetFloat(&ptr);
600					y1 = GetFloat(&ptr);
601					x = GetFloat(&ptr);
602					y = GetFloat(&ptr);
603
604					x1 += pos.x;
605					y1 += pos.y;
606					x += pos.x;
607					y += pos.y;
608				}
609
610				BPoint controlPoints[3];
611
612				controlPoints[0].Set(pos.x + 2.0f / 3.0f * (x1 - pos.x),
613					pos.y + 2.0f / 3.0f * (y1 - pos.y));
614				controlPoints[1].Set(x1 + 1.0f / 3.0f * (x - x1),
615					y1  + 1.0f / 3.0f * (y - y1));
616				controlPoints[2].Set(x, y);
617
618				pos.Set(x, y);
619				prevCtlPt.Set(x1, y1);
620				canMove = false;
621				shape.BezierTo(controlPoints);
622				break;
623			}
624			case 'A':
625			case 'a':
626			{
627				x1 = pos.x;
628				y1 = pos.y;
629
630				if (command == 'A') {
631				    rx = GetFloat(&ptr);
632					ry = GetFloat(&ptr);
633					angle = GetFloat(&ptr);
634					largeArcFlag = GetFloat(&ptr);
635					sweepFlag = GetFloat(&ptr);
636					x = GetFloat(&ptr);
637					y = GetFloat(&ptr);
638
639					x2 = x;
640					y2 = y;
641				}
642				else {
643					rx = GetFloat(&ptr);
644					ry = GetFloat(&ptr);
645					angle = GetFloat(&ptr);
646					largeArcFlag = GetFloat(&ptr);
647					sweepFlag = GetFloat(&ptr);
648					x = GetFloat(&ptr);
649					y = GetFloat(&ptr);
650
651					x2 = x + pos.x;
652					y2 = y + pos.y;
653				}
654
655				const double pi = 3.14159265359;
656				const double radPerDeg = pi / 180.0;
657
658				if (x1 == x2 && y1 == y2)
659					break;
660
661				if (rx == 0.0f || ry == 0.0f) {
662					shape.LineTo(BPoint((float)x2, (float)y2));
663					break;
664				}
665
666				if (rx < 0.0)
667					rx = -rx;
668
669				if (ry < 0.0)
670					ry = -ry;
671
672				double sinPhi = sin(angle * radPerDeg);
673				double cosPhi = cos(angle * radPerDeg);
674
675				double x1dash =  cosPhi * (x1 - x2) / 2.0 +
676					sinPhi * (y1 - y2) / 2.0;
677				double y1dash = -sinPhi * (x1 - x2) / 2.0 +
678					cosPhi * (y1 - y2) / 2.0;
679
680				double root, numerator = rx * rx * ry * ry - rx * rx * y1dash * y1dash -
681					ry * ry * x1dash * x1dash;
682
683				if (numerator < 0.0) {
684					double s = (float)sqrt(1.0 - numerator / (rx * rx * ry * ry));
685
686					rx *= s;
687					ry *= s;
688					root = 0.0;
689				}
690				else {
691					root = (largeArcFlag == sweepFlag ? -1.0 : 1.0) *
692						sqrt(numerator /
693						(rx * rx * y1dash * y1dash + ry * ry * x1dash * x1dash));
694				}
695
696				double cxdash = root * rx * y1dash / ry, cydash = -root * ry * x1dash / rx;
697
698				double cx = cosPhi * cxdash - sinPhi * cydash + (x1 + x2) / 2.0;
699				double cy = sinPhi * cxdash + cosPhi * cydash + (y1 + y2) / 2.0;
700
701				double theta1 = CalcVectorAngle(1.0, 0.0, (x1dash - cxdash) / rx,
702					(y1dash - cydash) / ry ),
703					dtheta = CalcVectorAngle((x1dash - cxdash) / rx,
704						(y1dash - cydash) / ry, (-x1dash - cxdash) / rx,
705						(-y1dash - cydash) / ry);
706
707				if (!sweepFlag && dtheta > 0)
708					dtheta -= 2.0 * pi;
709				else if (sweepFlag && dtheta < 0)
710					dtheta += 2.0 * pi;
711
712				int segments = (int)ceil (fabs(dtheta / (pi / 2.0)));
713				double delta = dtheta / segments;
714				double t = 8.0/3.0 * sin(delta / 4.0) * sin( delta / 4.0) /
715					sin(delta / 2.0);
716
717				BPoint controlPoints[3];
718
719				for (int n = 0; n < segments; ++n) {
720					double cosTheta1 = cos(theta1);
721					double sinTheta1 = sin(theta1);
722					double theta2 = theta1 + delta;
723					double cosTheta2 = cos(theta2);
724					double sinTheta2 = sin(theta2);
725
726					double xe = cosPhi * rx * cosTheta2 - sinPhi * ry * sinTheta2 + cx;
727					double ye = sinPhi * rx * cosTheta2 + cosPhi * ry * sinTheta2 + cy;
728
729					double dx1 = t * (-cosPhi * rx * sinTheta1 - sinPhi * ry * cosTheta1);
730					double dy1 = t * (-sinPhi * rx * sinTheta1 + cosPhi * ry * cosTheta1);
731
732					double dxe = t * (cosPhi * rx * sinTheta2 + sinPhi * ry * cosTheta2);
733					double dye = t * (sinPhi * rx * sinTheta2 - cosPhi * ry * cosTheta2);
734
735					controlPoints[0].Set((float)(x1 + dx1), (float)(y1 + dy1));
736					controlPoints[1].Set((float)(xe + dxe), (float)(ye + dye));
737					controlPoints[2].Set((float)xe, (float)ye );
738
739					shape.BezierTo(controlPoints);
740
741					theta1 = theta2;
742					x1 = (float)xe;
743					y1 = (float)ye;
744				}
745
746				pos.Set(x2, y2);
747				break;
748			}
749			case 'H':
750			{
751				x = GetFloat(&ptr);
752
753				pos.x = x;
754				canMove = false;
755				shape.LineTo(pos);
756				break;
757			}
758			case 'h':
759			{
760				x = GetFloat(&ptr);
761
762				pos.x += x;
763				canMove = false;
764				shape.LineTo(pos);
765				break;
766			}
767			case 'V':
768			{
769				y = GetFloat(&ptr);
770
771				pos.y = y;
772				canMove = false;
773				shape.LineTo(pos);
774				break;
775			}
776			case 'v':
777			{
778				y = GetFloat(&ptr);
779
780				pos.y += y;
781				canMove = false;
782				shape.LineTo(pos);
783				break;
784			}
785			case 'S':
786			case 's':
787			{
788				if (command == 'S') {
789					x2 = GetFloat(&ptr);
790					y2 = GetFloat(&ptr);
791					x = GetFloat(&ptr);
792					y = GetFloat(&ptr);
793				}
794				else {
795					x2 = GetFloat(&ptr);
796					y2 = GetFloat(&ptr);
797					x = GetFloat(&ptr);
798					y = GetFloat(&ptr);
799
800					x2 += pos.x;
801					y2 += pos.y;
802					x += pos.x;
803					y += pos.y;
804				}
805
806				if (prevCommand == 'C' || prevCommand == 'c' ||
807					prevCommand == 'S' || prevCommand == 's') {
808					x1 = prevCtlPt.x  + 2 * (pos.x - prevCtlPt.x);
809					y1 = prevCtlPt.y  + 2 * (pos.y - prevCtlPt.y);
810				}
811				else {
812					x1 = pos.x;
813					y1 = pos.y;
814				}
815
816				BPoint controlPoints[3];
817
818				controlPoints[0].Set(x1, y1);
819				controlPoints[1].Set(x2, y2);
820				controlPoints[2].Set(x, y);
821
822				pos.Set(x, y);
823				prevCtlPt.Set(x2, y2);
824				canMove = false;
825				shape.BezierTo(controlPoints);
826				break;
827			}
828			case 'T':
829			case 't':
830			{
831				if (command == 'T') {
832					x = GetFloat(&ptr);
833					y = GetFloat(&ptr);
834				}
835				else {
836					x = GetFloat(&ptr);
837					y = GetFloat(&ptr);
838
839					x += pos.x;
840					y += pos.y;
841				}
842
843				if (prevCommand == 'Q' || prevCommand == 'q' ||
844					prevCommand == 'T' || prevCommand == 't') {
845					x1 = prevCtlPt.x  + 2 * (pos.x - prevCtlPt.x);
846					y1 = prevCtlPt.y  + 2 * (pos.y - prevCtlPt.y);
847				}
848				else {
849					x1 = pos.x;
850					y1 = pos.y;
851				}
852
853				BPoint controlPoints[3];
854
855				controlPoints[0].Set(pos.x + 2.0f / 3.0f * (x1 - pos.x),
856					pos.y + 2.0f / 3.0f * (y1 - pos.y));
857				controlPoints[1].Set(x1 + 1.0f / 3.0f * (x - x1),
858					y1  + 1.0f / 3.0f * (y - y1));
859				controlPoints[2].Set(x, y);
860
861				pos.Set(x, y);
862				prevCtlPt.Set(x1, y1);
863				canMove = false;
864				shape.BezierTo(controlPoints);
865				break;
866			}
867		}
868
869		prevCommand = command;
870	}
871}
872//------------------------------------------------------------------------------
873void Svg2PictureView::CheckAttributes(const XML_Char **attributes) {
874	uint8 alpha = fState.fStrokeColor.alpha;
875
876	if (HasAttribute(attributes, "opacity")) {
877	    float opacity = GetFloatAttribute(attributes, "opacity");
878		fState.fStrokeColor.alpha = (uint8)(opacity * alpha);
879		fState.fFlags |= STROKE_FLAG;
880		fState.fFillColor.alpha = (uint8)(opacity * alpha);
881		fState.fFlags |= FILL_FLAG;
882	}
883
884	if (HasAttribute(attributes, "color")) {
885        fState.fCurrentColor = GetColorAttribute(attributes, "color", fState.fCurrentColor.alpha);
886	}
887
888	if (HasAttribute(attributes, "stroke")) {
889	    const char *stroke = GetStringAttribute(attributes, "stroke");
890		if (strcasecmp(stroke, "none") == 0)
891			fState.fStroke = false;
892        else if (strcasecmp(stroke, "currentColor") == 0) {
893            fState.fStrokeColor = fState.fCurrentColor;
894			fState.fStroke = true;
895        }
896		else {
897			fState.fStrokeColor = GetColorAttribute(attributes, "stroke", fState.fFillColor.alpha);
898			fState.fStroke = true;
899			SetHighColor(fState.fStrokeColor);
900		}
901		fState.fFlags |= STROKE_FLAG;
902	}
903
904	if (HasAttribute(attributes, "stroke-opacity")) {
905		fState.fStrokeColor.alpha = (uint8)(GetFloatAttribute(attributes, "stroke-opacity") * alpha);
906		fState.fFlags |= STROKE_FLAG;
907	}
908
909	if (HasAttribute(attributes, "fill")) {
910	    const char *fill = GetStringAttribute(attributes, "fill");
911		if (strcasecmp(fill, "none") == 0)
912			fState.fFill = false;
913		else if (strcasecmp(fill, "currentColor") == 0) {
914		    fState.fFillColor = fState.fCurrentColor;
915			fState.fFill = true;
916		}
917		else {
918			fState.fFillColor = GetColorAttribute(attributes, "fill", fState.fFillColor.alpha);
919			fState.fFill = true;
920		}
921		fState.fFlags |= FILL_FLAG;
922	}
923
924	if (HasAttribute(attributes, "fill-opacity")) {
925		fState.fFillColor.alpha = (uint8)(GetFloatAttribute(attributes, "fill-opacity") * alpha);
926		fState.fFlags |= FILL_FLAG;
927	}
928
929	if (HasAttribute(attributes, "stroke-width")) {
930		fState.fStrokeWidth = GetFloatAttribute(attributes, "stroke-width");
931		SetPenSize(fState.fStrokeWidth);
932		fState.fFlags |= STROKE_WIDTH_FLAG;
933	}
934
935	if (HasAttribute(attributes, "stroke-linecap")) {
936	    const char *stroke_linecap = GetStringAttribute(attributes, "stroke-linecap");
937
938		if (strcasecmp(stroke_linecap, "but") == 0)
939			fState.fLineCap = B_BUTT_CAP;
940		else if (strcasecmp(stroke_linecap, "round") == 0)
941			fState.fLineCap = B_ROUND_CAP;
942		else if (strcasecmp(stroke_linecap, "square") == 0)
943			fState.fLineCap = B_SQUARE_CAP;
944
945		SetLineMode(fState.fLineCap, LineJoinMode(), LineMiterLimit());
946		fState.fFlags |= LINE_MODE_FLAG;
947	}
948
949	if (HasAttribute(attributes, "stroke-linejoin")) {
950	    const char *stroke_linejoin = GetStringAttribute(attributes, "stroke-linejoin");
951
952		if (strcasecmp(stroke_linejoin, "miter") == 0)
953			fState.fLineJoin = B_MITER_JOIN;
954		else if (strcasecmp(stroke_linejoin, "round") == 0)
955			fState.fLineJoin = B_ROUND_JOIN;
956		else if (strcasecmp(stroke_linejoin, "bevel") == 0)
957			fState.fLineJoin = B_BEVEL_JOIN;
958
959		SetLineMode(LineCapMode(), fState.fLineJoin, LineMiterLimit());
960		fState.fFlags |= LINE_MODE_FLAG;
961	}
962
963	if (HasAttribute(attributes, "stroke-miterlimit")) {
964		fState.fLineMiterLimit = GetFloatAttribute(attributes, "stroke-miterlimit");
965		SetLineMode(LineCapMode(), LineJoinMode(), fState.fLineMiterLimit);
966		fState.fFlags |= LINE_MODE_FLAG;
967	}
968
969	if (HasAttribute(attributes, "font-size")) {
970		fState.fFontSize = GetFloatAttribute(attributes, "font-size");
971		SetFontSize(fState.fFontSize);
972		fState.fFlags |= FONT_SIZE_FLAG;
973	}
974
975	if (HasAttribute(attributes, "transform")) {
976		BMatrix matrix;
977		GetMatrixAttribute(attributes, "transform", &matrix);
978		fState.fMatrix *= matrix;
979		fState.fFlags |= MATRIX_FLAG;
980	}
981}
982//------------------------------------------------------------------------------
983void Svg2PictureView::StartElement(const XML_Char *name, const XML_Char **attributes) {
984    Push();
985    CheckAttributes(attributes);
986
987    if (strcasecmp(name, "circle") == 0) {
988        BPoint c(GetFloatAttribute(attributes, "cx"), GetFloatAttribute(attributes, "cy"));
989        float r = GetFloatAttribute(attributes, "r");
990
991        if (fState.fFill) {
992            SetHighColor(fState.fFillColor);
993            FillEllipse(c, r, r);
994            SetHighColor(fState.fStrokeColor);
995        }
996        if (fState.fStroke)
997            StrokeEllipse(c, r, r);
998    }
999    else if (strcasecmp(name, "ellipse") == 0) {
1000        BPoint c(GetFloatAttribute(attributes, "cx"), GetFloatAttribute(attributes, "cy"));
1001        float rx = GetFloatAttribute(attributes, "rx");
1002        float ry = GetFloatAttribute(attributes, "ry");
1003
1004        if (fState.fFill) {
1005            SetHighColor(fState.fFillColor);
1006            FillEllipse(c, rx, ry);
1007            SetHighColor(fState.fStrokeColor);
1008        }
1009        if (fState.fStroke)
1010            StrokeEllipse(c, rx, ry);
1011    }
1012    else if (strcasecmp(name, "image") == 0) {
1013        BPoint topLeft(GetFloatAttribute(attributes, "x"), GetFloatAttribute(attributes, "y"));
1014        BPoint bottomRight(topLeft.x + GetFloatAttribute(attributes, "width"),
1015            topLeft.y + GetFloatAttribute(attributes, "height"));
1016
1017        fState.fMatrix.Transform(&topLeft);
1018        fState.fMatrix.Transform(&bottomRight);
1019
1020        const char *href = GetStringAttribute(attributes, "xlink:href");
1021
1022        if (href) {
1023            BBitmap *bitmap = BTranslationUtils::GetBitmap(href);
1024
1025            if (bitmap) {
1026                DrawBitmap(bitmap, BRect(topLeft, bottomRight));
1027                delete bitmap;
1028            }
1029        }
1030    }
1031    else if (strcasecmp(name, "line") == 0){
1032        BPoint from(GetFloatAttribute(attributes, "x1"), GetFloatAttribute(attributes, "y1"));
1033        BPoint to(GetFloatAttribute(attributes, "x2"), GetFloatAttribute(attributes, "y2"));
1034
1035        fState.fMatrix.Transform(&from);
1036        fState.fMatrix.Transform(&to);
1037
1038        StrokeLine(from, to);
1039    }
1040    else if (strcasecmp(name, "linearGradient") == 0) {
1041        fGradient = new named_gradient;
1042
1043        fGradient->name = strdup(GetStringAttribute(attributes, "id"));
1044        fGradient->color.red = 0;
1045        fGradient->color.green = 0;
1046        fGradient->color.blue = 0;
1047        fGradient->color.alpha = 255;
1048        fGradient->started = false;
1049    }
1050    else if (strcasecmp(name, "path") == 0) {
1051        BShape shape;
1052        GetShapeAttribute(attributes, "d", shape);
1053        fState.fMatrix.Transform(shape);
1054
1055        if (fState.fFill) {
1056            SetHighColor(fState.fFillColor);
1057            FillShape(&shape);
1058            SetHighColor(fState.fStrokeColor);
1059        }
1060        if (fState.fStroke)
1061            StrokeShape(&shape);
1062    }
1063    else if (strcasecmp(name, "polygon") == 0) {
1064        BShape shape;
1065        GetPolygonAttribute(attributes, "points", shape);
1066        shape.Close();
1067        fState.fMatrix.Transform(shape);
1068
1069        if (fState.fFill) {
1070            SetHighColor(fState.fFillColor);
1071            FillShape(&shape);
1072            SetHighColor(fState.fStrokeColor);
1073        }
1074        if (fState.fStroke)
1075            StrokeShape(&shape);
1076    }
1077    else if (strcasecmp(name, "polyline") == 0) {
1078        BShape shape;
1079        GetPolygonAttribute(attributes, "points", shape);
1080        fState.fMatrix.Transform(shape);
1081
1082        if (fState.fFill) {
1083            SetHighColor(fState.fFillColor);
1084            FillShape(&shape);
1085            SetHighColor(fState.fStrokeColor);
1086        }
1087        if (fState.fStroke)
1088            StrokeShape(&shape);
1089    }
1090    else if (strcasecmp(name, "radialGradient") == 0) {
1091        fGradient = new named_gradient;
1092
1093        fGradient->name = strdup(GetStringAttribute(attributes, "id"));
1094        fGradient->color.red = 0;
1095        fGradient->color.green = 0;
1096        fGradient->color.blue = 0;
1097        fGradient->color.alpha = 255;
1098        fGradient->started = false;
1099    }
1100    else if (strcasecmp(name, "stop") == 0) {
1101        rgb_color color = GetColorAttribute(attributes, "stop-color", 255);
1102
1103        if (fGradient) {
1104            if (fGradient->started) {
1105                fGradient->color.red = (int8)(((int32)fGradient->color.red + (int32)color.red) / 2);
1106                fGradient->color.green = (int8)(((int32)fGradient->color.green + (int32)color.green) / 2);
1107                fGradient->color.blue = (int8)(((int32)fGradient->color.blue + (int32)color.blue) / 2);
1108            }
1109            else {
1110                fGradient->color = color;
1111                fGradient->started = true;
1112            }
1113        }
1114    }
1115    else if (strcasecmp(name, "rect") == 0) {
1116        BPoint points[4];
1117
1118        points[0].x = points[3].x = GetFloatAttribute(attributes, "x");
1119        points[0].y= points[1].y = GetFloatAttribute(attributes, "y");
1120        points[1].x = points[2].x = points[0].x + GetFloatAttribute(attributes, "width");
1121        points[2].y = points[3].y = points[0].y + GetFloatAttribute(attributes, "height");
1122
1123        /*const char *_rx = element->Attribute("rx");
1124        const char *_ry = element->Attribute("ry");
1125
1126        if (_rx || _ry)
1127        {
1128            float rx, ry;
1129
1130            if (_rx)
1131            {
1132                rx = atof(_rx);
1133
1134                if (_ry)
1135                    ry = atof(_ry);
1136                else
1137                    ry = rx;
1138            }
1139            else
1140                rx = ry = atof(_ry);
1141
1142            if (fState.fFill)
1143            {
1144                SetHighColor(fState.fFillColor);
1145                FillRoundRect(rect, rx, ry);
1146                SetHighColor(fState.fStrokeColor);
1147            }
1148            if (fState.fStroke)
1149                StrokeRoundRect(rect, rx, ry);
1150        }
1151        else
1152        {
1153            if (fState.fFill)
1154            {
1155                SetHighColor(fState.fFillColor);
1156                FillRect(rect);
1157                SetHighColor(fState.fStrokeColor);
1158            }
1159            if (fState.fStroke)
1160                StrokeRect(rect);
1161        }*/
1162
1163        BShape shape;
1164
1165        shape.MoveTo(points[0]);
1166        shape.LineTo(points[1]);
1167        shape.LineTo(points[2]);
1168        shape.LineTo(points[3]);
1169        shape.Close();
1170
1171        fState.fMatrix.Transform(shape);
1172
1173        if (fState.fFill)
1174        {
1175            SetHighColor(fState.fFillColor);
1176            FillShape(&shape);
1177            SetHighColor(fState.fStrokeColor);
1178        }
1179        if (fState.fStroke)
1180            StrokeShape(&shape);
1181    }
1182    else if (strcasecmp(name, "text") == 0) {
1183        fTextPosition.Set(GetFloatAttribute(attributes, "x"), GetFloatAttribute(attributes, "y"));
1184        fState.fMatrix.Transform(&fTextPosition);
1185    }
1186}
1187//------------------------------------------------------------------------------
1188void Svg2PictureView::EndElement(const XML_Char *name) {
1189    if (strcasecmp(name, "linearGradient") == 0) {
1190        if (fGradient)
1191            fGradients.AddItem(fGradient);
1192        fGradient = NULL;
1193    }
1194    else if (strcasecmp(name, "radialGradient") == 0) {
1195        if (fGradient)
1196            fGradients.AddItem(fGradient);
1197        fGradient = NULL;
1198    }
1199    else if (strcasecmp(name, "text") == 0) {
1200        if (fState.fFill)
1201        {
1202            SetHighColor(fState.fFillColor);
1203            DrawString(fText.String(), fTextPosition);
1204            SetHighColor(fState.fStrokeColor);
1205        }
1206        if (fState.fStroke)
1207            DrawString(fText.String(), fTextPosition);
1208        printf("%f, %f\n", fTextPosition.x, fTextPosition.y);
1209    }
1210
1211    Pop();
1212}
1213//------------------------------------------------------------------------------
1214void Svg2PictureView::CharacterDataHandler(const XML_Char *s, int len) {
1215    fText.SetTo(s, len);
1216}
1217//------------------------------------------------------------------------------
1218void Svg2PictureView::Push() {
1219	_state_ *state = new _state_(fState);
1220
1221	fStack.AddItem(state);
1222}
1223//------------------------------------------------------------------------------
1224void Svg2PictureView::Pop() {
1225	if (fStack.CountItems() == 0)
1226		printf("Unbalanced Push/Pop\n");
1227
1228	_state_ *state = (_state_*)fStack.LastItem();
1229
1230	if (fState.fFlags & STROKE_FLAG)
1231	{
1232		if (state->fStroke)
1233			SetHighColor(state->fStrokeColor);
1234	}
1235
1236	if (fState.fFlags & FILL_FLAG)
1237	{
1238		if (state->fFill)
1239			SetHighColor(state->fFillColor);
1240	}
1241
1242	if (fState.fFlags & STROKE_WIDTH_FLAG)
1243		SetPenSize(state->fStrokeWidth);
1244
1245	if (fState.fFlags & LINE_MODE_FLAG)
1246		SetLineMode(state->fLineCap, state->fLineJoin, state->fLineMiterLimit);
1247
1248	if (fState.fFlags & FONT_SIZE_FLAG)
1249		SetFontSize(state->fFontSize);
1250
1251	fState = *state;
1252
1253	fStack.RemoveItem(state);
1254	delete state;
1255}
1256//------------------------------------------------------------------------------
1257void Svg2PictureView::_StartElement(Svg2PictureView *view, const XML_Char *name, const XML_Char **attributes) {
1258    view->StartElement(name, attributes);
1259}
1260//------------------------------------------------------------------------------
1261void Svg2PictureView::_EndElement(Svg2PictureView *view, const XML_Char *name) {
1262    view->EndElement(name);
1263}
1264//------------------------------------------------------------------------------
1265void Svg2PictureView::_CharacterDataHandler(Svg2PictureView *view, const XML_Char *s, int len) {
1266    view->CharacterDataHandler(s, len);
1267}
1268//------------------------------------------------------------------------------
1269