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