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