xref: /haiku/src/tests/kits/interface/picture/SVGViewView.cpp (revision 44cceee67e056d8e34cb017d5f5c07b9fac874c0)
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 
15 named_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 -------------------------------------------------------
169 Svg2PictureView::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 
178 Svg2PictureView::~Svg2PictureView()
179 {
180 	delete fPicture;
181 }
182 
183 
184 void
185 Svg2PictureView::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 
212 void
213 Svg2PictureView::Draw(BRect updateRect)
214 {
215 	if (fPicture)
216 		DrawPicture(fPicture);
217 }
218 
219 
220 //------------------------------------------------------------------------------
221 bool 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 //------------------------------------------------------------------------------
228 float 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 //------------------------------------------------------------------------------
238 const 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 //------------------------------------------------------------------------------
248 rgb_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 //------------------------------------------------------------------------------
328 void 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 //------------------------------------------------------------------------------
374 void 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 //------------------------------------------------------------------------------
445 double 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 //------------------------------------------------------------------------------
455 char *SkipFloat(char *string) {
456 	if (*string == '-')
457 		string++;
458 
459 	int32 len = strspn(string, "1234567890.");
460 
461 	return string + len;
462 }
463 //------------------------------------------------------------------------------
464 char *FindFloat(char *string) {
465 	return strpbrk(string, "1234567890-.");
466 }
467 //------------------------------------------------------------------------------
468 float GetFloat(char **string) {
469 	*string = FindFloat(*string);
470 	float f = atof(*string);
471 	*string = SkipFloat(*string);
472 	return f;
473 }
474 //------------------------------------------------------------------------------
475 void 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 //------------------------------------------------------------------------------
874 void 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 //------------------------------------------------------------------------------
984 void 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 //------------------------------------------------------------------------------
1189 void 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 //------------------------------------------------------------------------------
1215 void Svg2PictureView::CharacterDataHandler(const XML_Char *s, int len) {
1216     fText.SetTo(s, len);
1217 }
1218 //------------------------------------------------------------------------------
1219 void Svg2PictureView::Push() {
1220 	_state_ *state = new _state_(fState);
1221 
1222 	fStack.AddItem(state);
1223 }
1224 //------------------------------------------------------------------------------
1225 void 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 //------------------------------------------------------------------------------
1258 void Svg2PictureView::_StartElement(Svg2PictureView *view, const XML_Char *name, const XML_Char **attributes) {
1259     view->StartElement(name, attributes);
1260 }
1261 //------------------------------------------------------------------------------
1262 void Svg2PictureView::_EndElement(Svg2PictureView *view, const XML_Char *name) {
1263     view->EndElement(name);
1264 }
1265 //------------------------------------------------------------------------------
1266 void Svg2PictureView::_CharacterDataHandler(Svg2PictureView *view, const XML_Char *s, int len) {
1267     view->CharacterDataHandler(s, len);
1268 }
1269 //------------------------------------------------------------------------------
1270