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