1 /* === S Y N F I G ========================================================= */
2 /*!	\file svg_parser.cpp
3 **	\brief Implementation of the Svg parser
4 **	\brief Based on SVG XML specification 1.1
5 **	\brief See: http://www.w3.org/TR/xml11/ for deatils
6 **
7 **	$Id:$
8 **
9 **	\legal
10 **	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
11 **	Copyright (c) 2008 Chris Moore
12 **	Copyright (c) 2009 Carlos A. Sosa Navarro
13 **	Copyright (c) 2009 Nikita Kitaev
14 **
15 **	This package is free software; you can redistribute it and/or
16 **	modify it under the terms of the GNU General Public License as
17 **	published by the Free Software Foundation; either version 2 of
18 **	the License, or (at your option) any later version.
19 **
20 **	This package is distributed in the hope that it will be useful,
21 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
22 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 **	General Public License for more details.
24 **	\endlegal
25 */
26 /* ========================================================================= */
27 
28 /* === H E A D E R S ======================================================= */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #include <synfig/localization.h>
35 #include <synfig/general.h>
36 
37 #include <iostream>
38 #include <cstring>
39 #include "svg_parser.h"
40 
41 /* === U S I N G =========================================================== */
42 
43 using namespace synfig;
44 
45 /* === G L O B A L S ======================================================= */
46 
47 //PARSER PREFERENCES
48 
49 //Seperate transformations: apply transformations on a per-layer basis, rather than on canvases
50 #define SVG_SEP_TRANSFORMS 1
51 
52 //Resolve BLine transformations: resolve transformations instead of creating transformation layers
53 #define SVG_RESOLVE_BLINE 1
54 
55 /* === P R O C E D U R E S ================================================= */
56 
57 Canvas::Handle
open_svg(std::string _filepath,String & errors,String & warnings)58 synfig::open_svg(std::string _filepath,String &errors, String &warnings){
59 	Canvas::Handle canvas;
60 	Svg_parser parser;
61 	try
62 	{
63 		canvas=parser.load_svg_canvas(_filepath,errors,warnings);
64 		//canvas->set_id(parser.get_id());
65 	}catch(...){
66 		std::cout<<"error"<<std::endl;
67 	}
68 	return canvas;
69 }
70 
71 Canvas::Handle
load_svg_canvas(std::string _filepath,String & errors,String & warnings)72 Svg_parser::load_svg_canvas(std::string _filepath,String &errors, String &warnings){
73 	ChangeLocale locale(LC_NUMERIC, "C");
74 
75 	filepath = _filepath;
76 	#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
77   	try{
78   	#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
79 		//load parser
80 		parser.set_substitute_entities();
81 		parser.parse_file(filepath);
82 		//set_id(filepath);
83 		if(parser){
84 		  	const xmlpp::Node* pNode = parser.get_document()->get_root_node();
85 		  	parser_node(pNode);
86 		}
87 	#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
88   	}catch(const std::exception& ex){
89     	std::cout << "Exception caught: " << ex.what() << std::endl;
90   	}
91   	#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
92 	Canvas::Handle canvas;
93 	if(nodeRoot){
94 		//canvas=synfig::open_canvas(nodeRoot,_filepath,errors,warnings);
95 		canvas=synfig::open_canvas(nodeRoot,errors,warnings);
96 	}
97 	return canvas;
98 }
99 
Svg_parser()100 Svg_parser::Svg_parser():
101 	nodeRoot(NULL),
102 	uid(0),
103 	kux(60),
104 	set_canvas(0), //we must run parser_canvas method
105 	ox(0),
106 	oy(0)
107 {
108 	// 0.5 in gamma parameter of color correct layer is 1/0.5 = 2 (thinking) it must be 2.2!!!!
109 	gamma.set_gamma(2.2);
110 }
111 /*
112 String
113 Svg_parser::get_id(){
114 	if(!id_name.empty()) return id_name;
115 	return "random_id";
116 }
117 void
118 Svg_parser::set_id(String source){
119 	const char bad_chars[]=" :#@$^&()*";
120 	int start= 	source.find_last_of('/')+1;
121 	int end=	source.find_last_of('.');
122 	String x=source.substr(start,end-start);
123 	if(!x.empty()){
124 		for(unsigned int i=0;i<sizeof(bad_chars);i++){
125 			unsigned int pos=x.find_first_of(bad_chars[i]);
126 			if(pos!=String::npos)
127 				x.erase(pos,1);
128 		}
129 	}
130 	if(!x.empty()){
131 		id_name=x;
132 	}else{
133 		id_name="id_arbitrario";
134 	}
135 }
136 */
137 //UPDATE
138 
139 
140 /* === PARSERS ============================================================= */
141 
142 void
parser_node(const xmlpp::Node * node)143 Svg_parser::parser_node(const xmlpp::Node* node){
144   	const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
145   	const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node);
146   	const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::CommentNode*>(node);
147 
148   	if(nodeText && nodeText->is_white_space()) //Let's ignore the indenting - you don't always want to do this.
149     	return;
150 
151   	Glib::ustring nodename = node->get_name();
152   	if(!nodeText && !nodeComment && !nodename.empty()){
153 		if(nodename.compare("svg")==0){
154 			parser_svg (node);
155 		}else if(nodename.compare("namedview")==0){
156 			parser_canvas(node);
157 		}else if(nodename.compare("defs")==0){
158 			parser_defs (node);
159 		}else{
160 			if(set_canvas==0) parser_canvas (node);
161 			parser_graphics(node,nodeRoot,"",NULL);
162 			if(nodename.compare("g")==0) return;
163 		}
164   	}
165   	if(!nodeContent){
166     	xmlpp::Node::NodeList list = node->get_children();
167     	for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter){
168       		parser_node(*iter); //recursive
169     	}
170   	}
171 }
172 
173 //parser elements
174 void
parser_svg(const xmlpp::Node * node)175 Svg_parser::parser_svg (const xmlpp::Node* node){
176 	if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)){
177 		width	=etl::strprintf("%f",getDimension(nodeElement->get_attribute_value("width")));
178 		height	=etl::strprintf("%f",getDimension(nodeElement->get_attribute_value("height")));
179 		docname=nodeElement->get_attribute_value("docname","");
180 	}
181 }
182 void
parser_canvas(const xmlpp::Node * node)183 Svg_parser::parser_canvas (const xmlpp::Node* node){
184 	if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)){
185 		if(width.compare("")==0){
186 			width=nodeElement->get_attribute_value("width","");
187 		}
188 		if(height.compare("")==0){
189 			height=nodeElement->get_attribute_value("height","");
190 		}
191 		if(width.compare("")==0 && height.compare("")!=0){
192 			width=height;
193 		}
194 		if(width.compare("")!=0 && height.compare("")==0){
195 			height=width;
196 		}
197 		if(height.compare("")==0 && width.compare("")==0){
198 			width="1024";
199 			height="768";
200 		}
201 		//build
202 		nodeRoot=document.create_root_node("canvas", "", "");
203 		nodeRoot->set_attribute("version","0.5");
204 		nodeRoot->set_attribute("width",width);
205 		nodeRoot->set_attribute("height",height);
206 		nodeRoot->set_attribute("xres","2834.645752");
207 		nodeRoot->set_attribute("yres","2834.645752");
208 		float view_x;
209 		float view_y;
210 		view_x=atof(width.c_str())/kux;
211 		view_y=atof(height.c_str())/kux;
212 		view_x=view_x/2.0;
213 		view_y=view_y/2.0;
214 		char attr_view_box[60];
215 		sprintf(attr_view_box,"%f %f %f %f",-1.0*view_x,view_y,view_x,-1.0*view_y);
216 		nodeRoot->set_attribute("view-box",attr_view_box);
217 		ox=atof(width.c_str() )/2;
218 		oy=atof(height.c_str())/2;
219 		nodeRoot->set_attribute("antialias","1");
220 		nodeRoot->set_attribute("fps","24.000");
221 		nodeRoot->set_attribute("begin-time","0f");
222 		nodeRoot->set_attribute("end-time","5s");
223 		nodeRoot->set_attribute("bgcolor","0.500000 0.500000 0.500000 1.000000");
224 		if(!id_name.empty()) nodeRoot->add_child("name")->set_child_text(id_name);
225 		else nodeRoot->add_child("name")->set_child_text("Synfig Animation 1");
226 	}
227 	set_canvas=1;
228 }
229 
230 void
parser_graphics(const xmlpp::Node * node,xmlpp::Element * root,String parent_style,SVGMatrix * mtx_parent)231 Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String parent_style,SVGMatrix* mtx_parent){
232 	if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)){
233 		Glib::ustring nodename = node->get_name();
234 		if (nodename.compare("g")==0 || nodename.compare("path")==0 || nodename.compare("polygon")==0 || nodename.compare("rect")==0){} else return;
235 
236 		//load sub-attributes
237 		Glib::ustring id			=nodeElement->get_attribute_value("id");
238 		Glib::ustring transform	=nodeElement->get_attribute_value("transform");
239 
240 		//resolve transformations
241 		SVGMatrix* mtx=NULL;
242 		if(!transform.empty())
243 			mtx=parser_transform (transform);
244 		if (SVG_SEP_TRANSFORMS)
245 		{
246 			if(mtx_parent){
247 				if(mtx)
248 					composeSVGMatrix(&mtx,mtx_parent,mtx);
249 				else
250 					mtx=newSVGMatrix(mtx_parent);
251 			}
252 		}
253 		if(nodename.compare("g")==0){
254 			parser_layer (node,root->add_child("layer"),parent_style,mtx);
255 			return;
256 		}
257 
258 		Glib::ustring obj_style	=nodeElement->get_attribute_value("style");
259 		Glib::ustring obj_fill			=nodeElement->get_attribute_value("fill");
260 
261 		//style
262 		String fill			    =loadAttribute("fill",obj_style,parent_style,obj_fill,"none");
263 		String fill_rule		=loadAttribute("fill-rule",obj_style,parent_style,"evenodd");
264 		String stroke			=loadAttribute("stroke",obj_style,parent_style,"none");
265 		String stroke_width		=loadAttribute("stroke-width",obj_style,parent_style,"1px");
266 		String stroke_linecap	=loadAttribute("stroke-linecap",obj_style,parent_style,"butt");
267 		String stroke_linejoin	=loadAttribute("stroke-linejoin",obj_style,parent_style,"miter");
268 		String stroke_opacity	=loadAttribute("stroke-opacity",obj_style,parent_style,"1");
269 		String fill_opacity		=loadAttribute("fill-opacity",obj_style,parent_style,"1");
270 		String opacity			=loadAttribute("opacity",obj_style,parent_style,"1");
271 
272 
273 		//Fill
274 		int typeFill=0; //nothing
275 
276 		if(fill.compare("none")!=0){
277 			typeFill=1; //simple
278 		}
279 		if(typeFill==1 && fill.compare(0,3,"url")==0){
280 			typeFill=2;	//gradient
281 		}
282 		//Stroke
283 		int typeStroke=0;//nothing
284 
285 		if(stroke.compare("none")!=0){
286 			typeStroke=1; //simple
287 		}
288 		if(typeStroke==1 && stroke.compare(0,3,"url")==0){
289 			typeStroke=2;	//gradient
290 		}
291 
292 		xmlpp::Element* child_layer = root;
293 		xmlpp::Element* child_fill;
294 		xmlpp::Element* child_stroke;
295 
296 		//make simple fills
297 		if(nodename.compare("rect")==0 && typeFill!=0){
298 			if (mtx) child_layer = nodeStartBasicLayer(root->add_child("layer"), id);
299 			child_fill=child_layer;
300 			parser_rect(nodeElement,child_fill,fill,fill_opacity,opacity);
301 			if(typeFill==2){
302 				build_fill (child_fill,fill,NULL);
303 			}
304 			parser_effects(nodeElement,child_layer,parent_style,mtx);
305 			return;
306 		}
307 		if ((!(SVG_RESOLVE_BLINE) && mtx) || typeFill==2 || typeStroke==2)
308 			child_layer = nodeStartBasicLayer(root->add_child("layer"), id);
309 		child_fill=child_layer;
310 		child_stroke=child_layer;
311 
312 		//=======================================================================
313 
314 		std::list<BLine*> k;
315 		//if we are creating a bline
316 
317 		//First, create the list of Verteces
318 		if (SVG_RESOLVE_BLINE) {
319 			if(nodename.compare("path")==0){
320 				k=parser_path_d (nodeElement->get_attribute_value("d"),mtx);
321 			} else if(nodename.compare("polygon")==0){
322 				k=parser_path_polygon (nodeElement->get_attribute_value("points"),mtx);
323 			}
324 		} else {
325 			if(nodename.compare("path")==0){
326 				k=parser_path_d (nodeElement->get_attribute_value("d"),NULL);
327 			} else if(nodename.compare("polygon")==0){
328 				k=parser_path_polygon (nodeElement->get_attribute_value("points"),NULL);
329 			}
330 		}
331 
332 		std::list<BLine *>::iterator aux;
333 		//int n = k.size();
334 
335 		if(typeFill!=0){//region layer
336 			/*if(typeFill==2){
337 				child_fill=nodeStartBasicLayer(child_fill->add_child("layer"));
338 			}*/
339 			for (aux = k.begin(); aux!=k.end(); aux++){
340 				xmlpp::Element *child_region=child_fill->add_child("layer");
341 				child_region->set_attribute("type","region");
342 				child_region->set_attribute("active","true");
343 				child_region->set_attribute("version","0.1");
344 				child_region->set_attribute("desc",id);
345 				build_param (child_region->add_child("param"),"z_depth","real","0.0000000000");
346 				build_param (child_region->add_child("param"),"amount","real","1.0000000000");
347 				build_param (child_region->add_child("param"),"blend_method","integer","0");
348 				build_color (child_region->add_child("param"),getRed(fill),getGreen(fill),getBlue(fill),atof(fill_opacity.data())*atof(opacity.data()));
349 				build_vector (child_region->add_child("param"),"offset",0,0, *(*aux)->offset_id );
350 				build_param (child_region->add_child("param"),"invert","bool","false");
351 				build_param (child_region->add_child("param"),"antialias","bool","true");
352 				build_param (child_region->add_child("param"),"feather","real","0.0000000000");
353 				build_param (child_region->add_child("param"),"blurtype","integer","1");
354 				if(fill_rule.compare("evenodd")==0) build_param (child_region->add_child("param"),"winding_style","integer","1");
355 				else build_param (child_region->add_child("param"),"winding_style","integer","0");
356 
357 				build_bline (child_region->add_child("param"),*(*aux)->points,(*aux)->loop,*(*aux)->bline_id);
358 			}
359 		}
360 		if(typeFill==2){ //gradient in onto mode (fill)
361 			if (SVG_RESOLVE_BLINE)
362 				build_fill(child_fill,fill,mtx);
363 			else
364 				build_fill(child_fill,fill,NULL);
365 		}
366 
367 		if(typeStroke!=0){//outline layer
368 			if(typeStroke==2){
369 				child_stroke=nodeStartBasicLayer(child_stroke->add_child("layer"),"stroke");
370 			}
371 			for (aux=k.begin(); aux!=k.end(); aux++){
372 				xmlpp::Element *child_outline=child_stroke->add_child("layer");
373 				child_outline->set_attribute("type","outline");
374 				child_outline->set_attribute("active","true");
375 				child_outline->set_attribute("version","0.2");
376 				child_outline->set_attribute("desc",id);
377 				build_param (child_outline->add_child("param"),"z_depth","real","0.0000000000");
378 				build_param (child_outline->add_child("param"),"amount","real","1.0000000000");
379 				build_param (child_outline->add_child("param"),"blend_method","integer","0");
380 				build_color (child_outline->add_child("param"),getRed(stroke),getGreen(stroke),getBlue(stroke),atof(stroke_opacity.data())*atof(opacity.data()));
381 				build_vector (child_outline->add_child("param"),"offset",0,0,*(*aux)->offset_id);
382 				build_param (child_outline->add_child("param"),"invert","bool","false");
383 				build_param (child_outline->add_child("param"),"antialias","bool","true");
384 				build_param (child_outline->add_child("param"),"feather","real","0.0000000000");
385 				build_param (child_outline->add_child("param"),"blurtype","integer","1");
386 				//outline in nonzero
387 				build_param (child_outline->add_child("param"),"winding_style","integer","0");
388 
389 				build_bline (child_outline->add_child("param"),*(*aux)->points,(*aux)->loop,*(*aux)->bline_id);
390 
391 				stroke_width=etl::strprintf("%f",getDimension(stroke_width)/kux);
392 				build_param (child_outline->add_child("param"),"width","real",stroke_width);
393 				build_param (child_outline->add_child("param"),"expand","real","0.0000000000");
394 				if(stroke_linejoin.compare("miter")==0) build_param (child_outline->add_child("param"),"sharp_cusps","bool","true");
395 				else build_param (child_outline->add_child("param"),"sharp_cusps","bool","false");
396 				if(stroke_linecap.compare("butt")==0){
397 					build_param (child_outline->add_child("param"),"round_tip[0]","bool","false");
398 					build_param (child_outline->add_child("param"),"round_tip[1]","bool","false");
399 				}else{
400 					build_param (child_outline->add_child("param"),"round_tip[0]","bool","true");
401 					build_param (child_outline->add_child("param"),"round_tip[1]","bool","true");
402 				}
403 				build_param (child_outline->add_child("param"),"loopyness","real","1.0000000000");
404 				build_param (child_outline->add_child("param"),"homogeneous_width","bool","true");
405 			}
406 
407 			if(typeStroke==2){ //gradient in onto mode (stroke)
408 				if (SVG_RESOLVE_BLINE)
409 					build_fill(child_stroke,stroke,mtx);
410 				else
411 					build_fill(child_stroke,stroke,NULL);
412 			}
413 		}
414 
415 		if (SVG_RESOLVE_BLINE)
416 			parser_effects(nodeElement,child_layer,parent_style,NULL);
417 		else
418 			parser_effects(nodeElement,child_layer,parent_style,mtx);
419 	}
420 }
421 
422 /* === LAYER PARSERS ======================================================= */
423 
424 void
parser_layer(const xmlpp::Node * node,xmlpp::Element * root,String parent_style,SVGMatrix * mtx)425 Svg_parser::parser_layer(const xmlpp::Node* node,xmlpp::Element* root,String parent_style,SVGMatrix* mtx){
426 	if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)){
427 		Glib::ustring label		=nodeElement->get_attribute_value("label");
428 		Glib::ustring style		=nodeElement->get_attribute_value("style");
429 		Glib::ustring fill		=nodeElement->get_attribute_value("fill");
430 
431 		String layer_style;
432 		if(!style.empty()){
433 			layer_style=style;
434 		}else if(!fill.empty()){
435 			layer_style.append("fill:");
436 			layer_style.append(fill);
437 		}else if(!parent_style.empty()){
438 			layer_style=parent_style;
439 		}
440 		//build
441 		root->set_attribute("type","group");
442 		root->set_attribute("active","true");
443 		root->set_attribute("version","0.1");
444 		if(!label.empty())	root->set_attribute("desc",label);
445 		else		root->set_attribute("desc","Inline Canvas");
446 
447 		build_real(root->add_child("param"),"z_depth",0.0);
448 		build_real(root->add_child("param"),"amount",1.0);
449 		build_integer(root->add_child("param"),"blend_method",0);
450 		build_vector (root->add_child("param"),"origin",0,0);
451 
452 		//printf(" canvas attributes ");
453 		//canvas
454 		xmlpp::Element *child_canvas=root->add_child("param");
455 		child_canvas->set_attribute("name","canvas");
456 		child_canvas=child_canvas->add_child("canvas");
457 		const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
458 		if(!nodeContent){
459     		xmlpp::Node::NodeList list = node->get_children();
460     		for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter){
461 				Glib::ustring name =(*iter)->get_name();
462 				parser_graphics (*iter,child_canvas,layer_style,mtx);
463     		}
464   		}
465 		if (SVG_SEP_TRANSFORMS) parser_effects(nodeElement,child_canvas,parent_style,NULL);
466 		else parser_effects(nodeElement,child_canvas,parent_style,mtx);
467 	}
468 }
469 
470 void
parser_rect(const xmlpp::Element * nodeElement,xmlpp::Element * root,String fill,String fill_opacity,String opacity)471 Svg_parser::parser_rect(const xmlpp::Element* nodeElement,xmlpp::Element* root,String fill, String fill_opacity, String opacity){
472 	Glib::ustring rect_id		=nodeElement->get_attribute_value("id");
473 	Glib::ustring rect_x		=nodeElement->get_attribute_value("x");
474 	Glib::ustring rect_y		=nodeElement->get_attribute_value("y");
475 	Glib::ustring rect_width	=nodeElement->get_attribute_value("width");
476 	Glib::ustring rect_height	=nodeElement->get_attribute_value("height");
477 
478 	xmlpp::Element *child_rect=root->add_child("layer");
479 	child_rect->set_attribute("type","rectangle");
480 	child_rect->set_attribute("active","true");
481 	child_rect->set_attribute("version","0.2");
482 	child_rect->set_attribute("desc",rect_id);
483 
484 	build_real(child_rect->add_child("param"),"z_depth",0.0);
485 	build_real(child_rect->add_child("param"),"amount",1.0);
486 	build_integer(child_rect->add_child("param"),"blend_method",0);
487 	build_color (child_rect->add_child("param"),getRed (fill),getGreen (fill),getBlue(fill),atof(opacity.data())*atof(fill_opacity.data()));
488 
489 	float auxx=atof(rect_x.c_str());
490 	float auxy=atof(rect_y.c_str());
491 	coor2vect(&auxx,&auxy);
492 	build_vector (child_rect->add_child("param"),"point1",auxx,auxy);
493 	auxx= atof(rect_x.c_str()) + atof(rect_width.c_str());
494 	auxy= atof(rect_y.c_str()) + atof(rect_height.c_str());
495 	coor2vect(&auxx,&auxy);
496 	build_vector (child_rect->add_child("param"),"point2",auxx,auxy);
497 
498 
499 }
500 
501 /* === CONVERT TO PATH PARSERS ============================================= */
502 
503 std::list<BLine *>
parser_path_polygon(Glib::ustring polygon_points,SVGMatrix * mtx)504 Svg_parser::parser_path_polygon(Glib::ustring polygon_points, SVGMatrix* mtx){
505 	std::list<BLine *> k0;
506 	if(polygon_points.empty())
507 		return k0;
508 	std::list<Vertex*> points;
509 	std::vector<String> tokens=get_tokens_path (polygon_points);
510 	unsigned int i;
511 	float ax,ay; ax=ay=0;
512 	for(i=0;i<tokens.size();i++){
513 		ax=atof(tokens.at(i).data());
514 		i++; if(tokens.at(i).compare(",")==0) i++;
515 		ay=atof(tokens.at(i).data());
516 		//mtx
517 		if(mtx) transformPoint2D(mtx,&ax,&ay);
518 		//adjust
519 		coor2vect(&ax,&ay);
520 		//save
521 		points.push_back(newVertex(ax,ay));
522 	}
523 	k0.push_front(newBLine(&points, true));
524 	return k0;
525 }
526 
527 std::list<BLine *>
parser_path_d(String path_d,SVGMatrix * mtx)528 Svg_parser::parser_path_d(String path_d,SVGMatrix* mtx){
529 	std::list<BLine *> k;
530 	std::list<Vertex*> k1;
531 
532 	std::vector<String> tokens=get_tokens_path(path_d);
533 	String command="M"; //the current command
534 	float ax,ay,tgx,tgy,tgx2,tgy2;//each method
535 	ax=ay=0;
536 	float actual_x=0,actual_y=0; //in svg coordinate space
537 	float old_x=0,old_y=0; //needed in rare cases
538 	float init_x=0,init_y=0; //for closepath commands
539 
540 	for(unsigned int i=0;i<tokens.size();i++){
541 		//if the token is a command, change the current command
542 		if(tokens.at(i).compare("M")==0 || tokens.at(i).compare("m")==0 || tokens.at(i).compare("L")==0 || tokens.at(i).compare("l")==0 || tokens.at(i).compare("H")==0 || tokens.at(i).compare("h")==0 || tokens.at(i).compare("V")==0 || tokens.at(i).compare("v")==0 || tokens.at(i).compare("C")==0 || tokens.at(i).compare("c")==0 || tokens.at(i).compare("S")==0 || tokens.at(i).compare("s")==0 || tokens.at(i).compare("Q")==0 || tokens.at(i).compare("q")==0 || tokens.at(i).compare("T")==0 || tokens.at(i).compare("t")==0 || tokens.at(i).compare("A")==0 || tokens.at(i).compare("a")==0 || tokens.at(i).compare("z")==0) {
543 			command=tokens.at(i);
544 			i++;
545 		}
546 
547 		old_x=actual_x;
548 		old_y=actual_y;
549 		//if command is absolute, set actual_x/y to zero
550 		if(command.compare("M")==0 || command.compare("L")==0 || command.compare("C")==0 || command.compare("S")==0 || command.compare("Q")==0 || command.compare("T")==0 || command.compare("A")==0 || command.compare("H")==0 || command.compare("V")==0) {
551 			actual_x=0;
552 			actual_y=0;
553 		}
554 
555 		//now parse the commands
556 		if(command.compare("M")==0 || command.compare("m")==0){ //move to
557 			if(!k1.empty()) {
558 				k.push_front(newBLine(&k1, false));
559 				k1.clear();
560 			}
561 			//read
562 			actual_x+=atof(tokens.at(i).data());
563 			i++; if(tokens.at(i).compare(",")==0) i++;
564 			actual_y+=atof(tokens.at(i).data());
565 
566 			init_x=actual_x;
567 			init_y=actual_y;
568 			ax=actual_x;
569 			ay=actual_y;
570 			//operate and save
571 			if(mtx) transformPoint2D(mtx,&ax,&ay);
572 			coor2vect(&ax,&ay);
573 			k1.push_back(newVertex (ax,ay)); //first element
574 			setSplit(k1.back(),TRUE);
575 			//"If a moveto is followed by multiple pairs of coordinates,
576 			// the subsequent pairs are treated as implicit lineto commands."
577 			if (command.compare("M")==0)
578 				command="L";
579 			else
580 				command="l";
581 		}else if(command.compare("C")==0 || command.compare("c")==0){ //curve
582 			//tg2
583 			tgx2=actual_x+atof(tokens.at(i).data());
584 			i++; if(tokens.at(i).compare(",")==0) i++;
585 			tgy2=actual_y+atof(tokens.at(i).data());
586 			//tg1
587 			i++; tgx=actual_x+atof(tokens.at(i).data());
588 			i++; if(tokens.at(i).compare(",")==0) i++;
589 			tgy=actual_y+atof(tokens.at(i).data());
590 			//point
591 			i++; actual_x+=atof(tokens.at(i).data());
592 			i++; if(tokens.at(i).compare(",")==0) i++;
593 			actual_y+=atof(tokens.at(i).data());
594 
595 			ax=actual_x;
596 			ay=actual_y;
597 			//mtx
598 			if(mtx){
599 				transformPoint2D(mtx,&tgx2,&tgy2);
600 				transformPoint2D(mtx,&ax,&ay);
601 				transformPoint2D(mtx,&tgx,&tgy);
602 			}
603 			//adjust
604 			coor2vect(&tgx2,&tgy2);
605 			coor2vect(&ax,&ay);
606 			coor2vect(&tgx,&tgy);
607 			//save
608 			setTg2(k1.back(),k1.back()->x,k1.back()->y,tgx2,tgy2);
609 			if(isFirst(k1.front(),ax,ay)){
610 				setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
611 			}else{
612 				k1.push_back(newVertex (ax,ay));
613 				setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
614 				setSplit(k1.back(),TRUE);
615 			}
616 		}else if(command.compare("Q")==0 || command.compare("q")==0){ //quadractic curve
617 			//tg1 and tg2
618 			tgx=actual_x+atof(tokens.at(i).data());
619 			i++; if(tokens.at(i).compare(",")==0) i++;
620 			tgy=actual_y+atof(tokens.at(i).data());
621 			//point
622 			i++; actual_x+=atof(tokens.at(i).data());
623 			i++; if(tokens.at(i).compare(",")==0) i++;
624 			actual_y+=atof(tokens.at(i).data());
625 
626 			ax=actual_x;
627 			ay=actual_y;
628 			//mtx
629 			if(mtx){
630 				transformPoint2D(mtx,&ax,&ay);
631 				transformPoint2D(mtx,&tgx,&tgy);
632 			}
633 			//adjust
634 			coor2vect(&ax,&ay);
635 			coor2vect(&tgx,&tgy);
636 			//save
637 			setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
638 			setSplit(k1.back(),FALSE);
639 			k1.push_back(newVertex (ax,ay));
640 			setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
641 		}else if(command.compare("L")==0 || command.compare("l")==0){ //line to
642 			//point
643 			actual_x+=atof(tokens.at(i).data());
644 			i++; if(tokens.at(i).compare(",")==0) i++;
645 			actual_y+=atof(tokens.at(i).data());
646 
647 			ax=actual_x;
648 			ay=actual_y;
649 			//mtx
650 			if(mtx) transformPoint2D(mtx,&ax,&ay);
651 			//adjust
652 			coor2vect(&ax,&ay);
653 			//save
654 			setTg2(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
655 			if(isFirst(k1.front(),ax,ay)){
656 				setTg1(k1.front(),k1.front()->x,k1.front()->y,k1.front()->x,k1.front()->y);
657 			}else{
658 				k1.push_back(newVertex(ax,ay));
659 				setTg1(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
660 			}
661 		}else if(command.compare("H")==0 || command.compare("h")==0){// horizontal move
662 			//the same that L but only Horizontal movement
663 			//point
664 			actual_x+=atof(tokens.at(i).data());
665 
666 			ax=actual_x;
667 			ay=old_y;
668 			//mtx
669 			if(mtx) transformPoint2D(mtx,&ax,&ay);
670 			//adjust
671 			coor2vect(&ax,&ay);
672 			//save
673 			setTg2(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
674 			if(isFirst(k1.front(),ax,ay)){
675 				setTg1(k1.front(),k1.front()->x,k1.front()->y,k1.front()->x,k1.front()->y);
676 			}else{
677 				k1.push_back(newVertex(ax,ay));
678 				setTg1(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
679 			}
680 		}else if(command.compare("V")==0 || command.compare("v")==0){//vertical
681 			//point
682 			actual_y+=atof(tokens.at(i).data());
683 
684 			ax=old_x;
685 			ay=actual_y;
686 			//mtx
687 			if(mtx) transformPoint2D(mtx,&ax,&ay);
688 			//adjust
689 			coor2vect(&ax,&ay);
690 			//save
691 			setTg2(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
692 			if(isFirst(k1.front(),ax,ay)){
693 				setTg1(k1.front(),k1.front()->x,k1.front()->y,k1.front()->x,k1.front()->y);
694 			}else{
695 				k1.push_back(newVertex(ax,ay));
696 				setTg1(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
697 			}
698 		}else if(command.compare("T")==0 || command.compare("t")==0){// I don't know what does it
699 			actual_x+=atof(tokens.at(i).data());
700 			i++; if(tokens.at(i).compare(",")==0) i++;
701 			actual_y+=atof(tokens.at(i).data());
702 		}else if(command.compare("A")==0 || command.compare("a")==0){//elliptic arc
703 
704 			//isn't complete support, is only for circles
705 
706 			//this curve have 6 parameters
707 			//radius
708 			float radius_x,radius_y;
709 			// todo: why 'angle' never used?
710 			//float angle;
711 			bool sweep,large;
712 			//radius
713 			radius_x=atof(tokens.at(i).data());
714 			i++; if(tokens.at(i).compare(",")==0) i++;
715 			radius_y=atof(tokens.at(i).data());
716 			//angle
717 			// todo: why 'angle' never used?
718 			i++; // angle=atof(tokens.at(i).data());
719 			//flags
720 			i++; large=atoi(tokens.at(i).data());
721 			i++; sweep=atoi(tokens.at(i).data());
722 			//point
723 			i++; actual_x+=atof(tokens.at(i).data());
724 			i++; if(tokens.at(i).compare(",")==0) i++;
725 			actual_y+=atof(tokens.at(i).data());
726 			//how to draw?
727 			if(!large && !sweep){
728 				//points
729 				tgx2 = old_x + radius_x*0.5;
730 				tgy2 = old_y ;
731 				tgx  = actual_x;
732 				tgy  = actual_y + radius_y*0.5;
733 
734 				ax=actual_x;
735 				ay=actual_y;
736 				//transformations
737 				if(mtx){
738 					transformPoint2D(mtx,&tgx2,&tgy2);
739 					transformPoint2D(mtx,&ax,&ay);
740 					transformPoint2D(mtx,&tgx,&tgy);
741 				}
742 				//adjust
743 				coor2vect(&tgx2,&tgy2);
744 				coor2vect(&ax,&ay);
745 				coor2vect(&tgx,&tgy);
746 				//save
747 				setTg2(k1.back(),k1.back()->x,k1.back()->y,tgx2,tgy2);
748 				if(isFirst(k1.front(),ax,ay)){
749 					setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
750 				}else{
751 					k1.push_back(newVertex (ax,ay));
752 					setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
753 					setSplit(k1.back(),TRUE);
754 				}
755 			}else if(!large &&  sweep){
756 				//points
757 				tgx2 = old_x;
758 				tgy2 = old_y + radius_y*0.5;
759 				tgx  = actual_x + radius_x*0.5;
760 				tgy  = actual_y ;
761 
762 				ax=actual_x;
763 				ay=actual_y;
764 				//transformations
765 				if(mtx){
766 					transformPoint2D(mtx,&tgx2,&tgy2);
767 					transformPoint2D(mtx,&ax,&ay);
768 					transformPoint2D(mtx,&tgx,&tgy);
769 				}
770 				//adjust
771 				coor2vect(&tgx2,&tgy2);
772 				coor2vect(&ax,&ay);
773 				coor2vect(&tgx,&tgy);
774 				//save
775 				setTg2(k1.back(),k1.back()->x,k1.back()->y,tgx2,tgy2);
776 				if(isFirst(k1.front(),ax,ay)){
777 					setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
778 				}else{
779 					k1.push_back(newVertex (ax,ay));
780 					setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
781 					setSplit(k1.back(),TRUE);
782 				}
783 			}else if( large && !sweep){//rare
784 				//this need more than one vertex
785 			}else if( large &&  sweep){//circles in inkscape are made with this kind of arc
786 				//intermediate point
787 				int sense=1;
788 				if(old_x>actual_x) sense =-1;
789 				float in_x,in_y,in_tgx1,in_tgy1,in_tgx2,in_tgy2;
790 				in_x = (old_x+actual_x)/2;
791 				in_y = old_y - sense*radius_y;
792 				in_tgx1 = in_x - sense*(radius_x*0.5);
793 				in_tgx2 = in_x + sense*(radius_x*0.5);
794 				in_tgy1 = in_y;
795 				in_tgy2 = in_y;
796 				//start/end points
797 				tgx2=old_x;
798 				tgy2=actual_y - sense*(radius_y*0.5);
799 				tgx =actual_x;
800 				tgy =actual_y - sense*(radius_y*0.5);
801 
802 				ax=actual_x;
803 				ay=actual_y;
804 				//transformations
805 				if(mtx){
806 					transformPoint2D(mtx,&tgx2,&tgy2);
807 					transformPoint2D(mtx,&tgx ,&tgy );
808 					transformPoint2D(mtx,&ax,&ay);
809 
810 					transformPoint2D(mtx,&in_tgx2,&in_tgy2);
811 					transformPoint2D(mtx,&in_tgx1,&in_tgy1);
812 					transformPoint2D(mtx,&in_x,&in_y);
813 				}
814 				//adjust
815 				coor2vect(&tgx2 , &tgy2);
816 				coor2vect(&ax   , &ay  );
817 				coor2vect(&tgx  , &tgy );
818 
819 				coor2vect(&in_tgx2 , &in_tgy2);
820 				coor2vect(&in_tgx1 , &in_tgy1);
821 				coor2vect(&in_x    , &in_y   );
822 
823 				//save the last tg2
824 				setTg2(k1.back(),k1.back()->x,k1.back()->y,tgx2,tgy2);
825 				//save the intermediate point
826 				k1.push_back(newVertex (in_x,in_y));
827 				setTg1(k1.back(),k1.back()->x,k1.back()->y, in_tgx1 , in_tgy1);
828 				setTg2(k1.back(),k1.back()->x,k1.back()->y, in_tgx2 , in_tgy2);
829 				setSplit(k1.back(),TRUE); //this could be changed
830 				//save the new point
831 				if(isFirst(k1.front(),ax,ay)){
832 					setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
833 				}else{
834 					k1.push_back(newVertex (ax,ay));
835 					setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
836 					setSplit(k1.back(),TRUE);
837 				}
838 			}
839 		}else if(command.compare("z")==0){
840 			k.push_front(newBLine(&k1, true));
841 			k1.clear();
842 			if (i<tokens.size() && tokens.at(i).compare("M")!=0 && tokens.at(i).compare("m")!=0) {
843 				//starting a new path, but not with a moveto
844 				actual_x=init_x;
845 				actual_y=init_y;
846 				ax=actual_x;
847 				ay=actual_y;
848 				//operate and save
849 				if(mtx) transformPoint2D(mtx,&ax,&ay);
850 				coor2vect(&ax,&ay);
851 				k1.push_back(newVertex (ax,ay)); //first element
852 				setSplit(k1.back(),TRUE);
853 			}
854 			i--; //decrement i to balance "i++" at command change
855 		}else{
856 			std::cout<<"unsupported path token: "<<tokens.at(i).c_str()<<std::endl;
857 		}
858 	}
859 	if(!k1.empty()) {
860 		k.push_front(newBLine(&k1, false)); //last element
861 	}
862 	return k;
863 }
864 
865 /* === EFFECTS PARSERS ===================================================== */
866 
867 void
parser_effects(const xmlpp::Element *,xmlpp::Element * root,String,SVGMatrix * mtx)868 Svg_parser::parser_effects(const xmlpp::Element* /*nodeElement*/,xmlpp::Element* root,String /*parent_style*/,SVGMatrix* mtx){
869 	build_transform(root, mtx);
870 }
871 
872 /* === DEFS PARSERS ======================================================== */
873 
874 void
parser_defs(const xmlpp::Node * node)875 Svg_parser::parser_defs(const xmlpp::Node* node){
876 	const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
877 	if(!nodeContent){
878 		xmlpp::Node::NodeList list = node->get_children();
879 		for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter){
880 			Glib::ustring name =(*iter)->get_name();
881 			if(name.compare("linearGradient")==0){
882 				parser_linearGradient(*iter);
883 			}else if(name.compare("radialGradient")==0){
884 				parser_radialGradient(*iter);
885 			}
886  		}
887   	}
888 }
889 
890 /* === BUILDS ============================================================== */
891 
892 void
build_transform(xmlpp::Element * root,SVGMatrix * mtx)893 Svg_parser::build_transform(xmlpp::Element* root,SVGMatrix* mtx){
894 	if (mtx) {
895 		xmlpp::Element *child_transform=root->add_child("layer");
896 		child_transform->set_attribute("type","warp");
897 		child_transform->set_attribute("active","true");
898 		child_transform->set_attribute("version","0.1");
899 		child_transform->set_attribute("desc","Transform");
900 
901 		float x,y;
902 		x=100;y=100;coor2vect(&x,&y);
903 		build_vector (child_transform->add_child("param"),"src_tl",x,y);
904 
905 		x=200;y=200;coor2vect(&x,&y);
906 		build_vector (child_transform->add_child("param"),"src_br",x,y);
907 
908 
909 		x=100;y=100;
910 		transformPoint2D(mtx,&x,&y);coor2vect(&x,&y);
911 		build_vector (child_transform->add_child("param"),"dest_tl",x,y);
912 
913 		x=200;y=100;
914 		transformPoint2D(mtx,&x,&y);coor2vect(&x,&y);
915 		build_vector (child_transform->add_child("param"),"dest_tr",x,y);
916 
917 		x=200;y=200;
918 		transformPoint2D(mtx,&x,&y);coor2vect(&x,&y);
919 		build_vector (child_transform->add_child("param"),"dest_br",x,y);
920 
921 		x=100;y=200;
922 		transformPoint2D(mtx,&x,&y);coor2vect(&x,&y);
923 		build_vector (child_transform->add_child("param"),"dest_bl",x,y);
924 
925 		build_param (child_transform->add_child("param"),"clip","bool","false");
926 		build_param (child_transform->add_child("param"),"horizon","real","4.0");
927 	}
928 }
929 
930 std::list<ColorStop*>*
find_colorStop(String name)931 Svg_parser::find_colorStop(String name){
932 	if(!name.empty()){
933 		if(lg.empty()&& rg.empty())
934 			return NULL;
935 
936 		String find= name;
937 		if(find.at(0)=='#') find.erase(0,1);
938 		else return NULL;
939 		std::list<LinearGradient*>::iterator aux=lg.begin();
940 		while(aux!=lg.end()){//only find into linear gradients
941 			if(find.compare((*aux)->name)==0){
942 				return (*aux)->stops;
943 			}
944 			aux++;
945 		}
946 	}
947 	return NULL;
948 }
949 
950 void
build_fill(xmlpp::Element * root,String name,SVGMatrix * mtx)951 Svg_parser::build_fill(xmlpp::Element* root, String name,SVGMatrix *mtx){
952 	if(!name.empty()){
953 		int start=name.find_first_of("#")+1;
954 		int end=name.find_first_of(")");
955 		String find= name.substr(start,end-start);
956 		bool encounter=false;
957 		if(!lg.empty()){
958 			std::list<LinearGradient*>::iterator aux=lg.begin();
959 			while(aux!=lg.end()){
960 				if(find.compare((*aux)->name)==0){
961 					build_linearGradient (root,*aux,mtx);
962 					encounter=true;
963 				}
964 				aux++;
965 			}
966 		}
967 		if(!encounter && !rg.empty()){
968 			std::list<RadialGradient*>::iterator aux=rg.begin();
969 			while(aux!=rg.end()){
970 				if(find.compare((*aux)->name)==0){
971 					build_radialGradient (root,*aux,mtx);
972 					encounter=true;
973 				}
974 				aux++;
975 			}
976 		}
977 	}
978 }
979 void
build_stop_color(xmlpp::Element * root,std::list<ColorStop * > * stops)980 Svg_parser::build_stop_color(xmlpp::Element* root, std::list<ColorStop*> *stops){
981 	std::list<ColorStop*>::iterator aux_stop=stops->begin();
982 	while(aux_stop!=stops->end()){
983 		xmlpp::Element *child=root->add_child("color");
984 		child->set_attribute("pos",etl::strprintf("%f",(*aux_stop)->pos));
985 		child->add_child("r")->set_child_text(etl::strprintf("%f",(*aux_stop)->r));
986 		child->add_child("g")->set_child_text(etl::strprintf("%f",(*aux_stop)->g));
987 		child->add_child("b")->set_child_text(etl::strprintf("%f",(*aux_stop)->b));
988 		child->add_child("a")->set_child_text(etl::strprintf("%f",(*aux_stop)->a));
989 		aux_stop++;
990 	}
991 }
992 void
build_linearGradient(xmlpp::Element * root,LinearGradient * data,SVGMatrix * mtx)993 Svg_parser::build_linearGradient(xmlpp::Element* root,LinearGradient* data,SVGMatrix* mtx){
994 	if(data){
995 		xmlpp::Element* gradient=root->add_child("layer");
996 
997 		gradient->set_attribute("type","linear_gradient");
998 		gradient->set_attribute("active","true");
999 		gradient->set_attribute("desc",data->name);
1000 		build_param (gradient->add_child("param"),"z_depth","real","0");
1001 		build_param (gradient->add_child("param"),"amount","real","1");
1002 		//straight onto
1003 		build_param (gradient->add_child("param"),"blend_method","integer","21");
1004 		float x1,y1,x2,y2;
1005 		x1=data->x1;
1006 		y1=data->y1;
1007 		x2=data->x2;
1008 		y2=data->y2;
1009 
1010 
1011 		if (mtx || data->transform){
1012 			SVGMatrix *mtx2=NULL;
1013 			if (mtx && data->transform){
1014 				composeSVGMatrix(&mtx2,mtx,data->transform);
1015 			}else if (mtx){
1016 				mtx2=mtx;
1017 			}else if (data->transform){
1018 				mtx2=data->transform;
1019 			}
1020 			//matrix transforms the gradient as a whole
1021 			//it does not preserve angles, so we cant' simply transform both points
1022 			float x3, y3, k;
1023 			//set point (x3,y3) on the same gradient line as (x2,y2)
1024 			//the gradient line is perpendicular to (x1,y1)(x2,y2)
1025 			x3=x2+(y2-y1);
1026 			y3=y2-(x2-x1);
1027 			//transform everything
1028 			transformPoint2D(mtx2,&x1,&y1);
1029 			transformPoint2D(mtx2,&x2,&y2);
1030 			transformPoint2D(mtx2,&x3,&y3);
1031 
1032 			if (x2!=x3 && y2!=y3) {//divide by zero check
1033 
1034 				//set k as slope between (x2,y2) and (x3,y3)
1035 				//k is the slope of gradient lines post-transformation
1036 				k=(y3-y2)/(x3-x2);
1037 				//set point (x2,y2) on the gradient line passing through (x3,y3)
1038 				//so that the line (x1,y1)(x2,y2) is perpendicular to (x2,y2)(x3,y3)
1039 				x2= (x3*k+x1/k+y1-y3)/(k+(1/k));
1040 				y2= k*(x2-x3)+y3;
1041 			} else if (x2==x3 && y2!=y3) {
1042 				y2=y1;
1043 			} else if (x2!=x3 && y2==y3) {
1044 				x2=x1;
1045 			} else {
1046 				std::cout<<"SVG Import warning: gradient points equal each other"<<std::endl;
1047 			}
1048 		}
1049 
1050 		coor2vect (&x1,&y1);
1051 		coor2vect (&x2,&y2);
1052 
1053 		build_vector (gradient->add_child("param"),"p1",x1,y1);
1054 		build_vector (gradient->add_child("param"),"p2",x2,y2);
1055 		//gradient link
1056 		xmlpp::Element *child_stops=gradient->add_child("param");
1057 		child_stops->set_attribute("name","gradient");
1058 		child_stops->set_attribute("guid",GUID::hasher(data->name).get_string());
1059 		build_stop_color (child_stops->add_child("gradient"),data->stops);
1060 		build_param (gradient->add_child("param"),"loop","bool","false");
1061 		build_param (gradient->add_child("param"),"zigzag","bool","false");
1062 	}
1063 }
1064 void
build_radialGradient(xmlpp::Element * root,RadialGradient * data,SVGMatrix * mtx)1065 Svg_parser::build_radialGradient(xmlpp::Element* root,RadialGradient* data,SVGMatrix* mtx){
1066 	if(data){
1067 		xmlpp::Element* gradient;
1068 
1069 		if (mtx || data->transform) {
1070 			xmlpp::Element* layer=root->add_child("layer");
1071 
1072 			layer->set_attribute("type","group");
1073 			layer->set_attribute("active","true");
1074 			layer->set_attribute("version","0.1");
1075 			layer->set_attribute("desc",data->name);
1076 			build_param (layer->add_child("param"),"z_depth","real","0");
1077 			build_param (layer->add_child("param"),"amount","real","1");
1078 			build_param (layer->add_child("param"),"blend_method","integer","21"); //straight onto
1079 			build_vector (layer->add_child("param"),"origin",0,0);
1080 			xmlpp::Element *child=layer->add_child("param");
1081 			child->set_attribute("name","canvas");
1082 			xmlpp::Element* child_layer=child->add_child("canvas");
1083 
1084 			gradient=child_layer->add_child("layer");
1085 			gradient->set_attribute("desc",data->name);
1086 			build_param (gradient->add_child("param"),"blend_method","integer","0"); //composite
1087 			SVGMatrix *mtx2=NULL;
1088 			if (mtx && data->transform){
1089 				composeSVGMatrix(&mtx2,mtx,data->transform);
1090 			}else if (mtx){
1091 				mtx2=mtx;
1092 			}else if (data->transform){
1093 				mtx2=data->transform;
1094 			}
1095 			build_transform(child_layer,mtx2);
1096 
1097 		}else {
1098 			gradient=root->add_child("layer");
1099 			gradient->set_attribute("desc",data->name);
1100 			build_param (gradient->add_child("param"),"blend_method","integer","21"); //straight onto
1101 		}
1102 
1103 		gradient->set_attribute("type","radial_gradient");
1104 		gradient->set_attribute("active","true");
1105 		build_param (gradient->add_child("param"),"z_depth","real","0");
1106 		build_param (gradient->add_child("param"),"amount","real","1");
1107 		//gradient link
1108 		xmlpp::Element *child_stops=gradient->add_child("param");
1109 		child_stops->set_attribute("name","gradient");
1110 		child_stops->set_attribute("guid",GUID::hasher(data->name).get_string());
1111 		build_stop_color (child_stops->add_child("gradient"),data->stops);
1112 
1113 		//here the center point and radius
1114 		float cx=data->cx;
1115 		float cy=data->cy;
1116 		float r =data->r;
1117 
1118 		//adjust
1119 		coor2vect (&cx,&cy);
1120 		r=r/kux;
1121 		build_vector (gradient->add_child("param"),"center",cx,cy);
1122 		build_param (gradient->add_child("param"),"radius","real",r);
1123 
1124 		build_param (gradient->add_child("param"),"loop","bool","false");
1125 		build_param (gradient->add_child("param"),"zigzag","bool","false");
1126 	}
1127 }
1128 
1129 void
parser_linearGradient(const xmlpp::Node * node)1130 Svg_parser::parser_linearGradient(const xmlpp::Node* node){
1131 	if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)){
1132 		Glib::ustring id	=nodeElement->get_attribute_value("id");
1133 		float x1			=atof(nodeElement->get_attribute_value("x1").data());
1134 		float y1			=atof(nodeElement->get_attribute_value("y1").data());
1135 		float x2			=atof(nodeElement->get_attribute_value("x2").data());
1136 		float y2			=atof(nodeElement->get_attribute_value("y2").data());
1137 		Glib::ustring link	=nodeElement->get_attribute_value("href");
1138 		Glib::ustring transform	=nodeElement->get_attribute_value("gradientTransform");
1139 
1140 		if(link.empty())
1141 			link = nodeElement->get_attribute_value("href","xlink");
1142 
1143 		//resolve transformations
1144 		SVGMatrix* mtx=NULL;
1145 		if(!transform.empty())
1146 			mtx=parser_transform (transform);
1147 
1148 		std::list<ColorStop*> *stops;
1149 		if(!link.empty()){
1150 			stops=find_colorStop (link);
1151 		}else{
1152 			//color stops
1153 			stops=new std::list<ColorStop*>();
1154 			const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
1155 			if(!nodeContent){
1156     			xmlpp::Node::NodeList list = node->get_children();
1157     			for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter){
1158 					Glib::ustring name =(*iter)->get_name();
1159 					if(name.compare("stop")==0){
1160 						const xmlpp::Element* nodeIter = dynamic_cast<const xmlpp::Element*>(*iter);
1161 						Glib::ustring style	=nodeIter->get_attribute_value("style");
1162 						float offset=atof(nodeIter->get_attribute_value("offset").data());
1163 						String stop_color;
1164 						String opacity;
1165 						if(!style.empty()){
1166 							extractSubAttribute (style,"stop-color",&stop_color);
1167 							extractSubAttribute (style,"stop-opacity",&opacity);
1168 						}
1169 						if(opacity.empty()) opacity="1";
1170 						if(stop_color.empty()) stop_color="#000000";//black for default :S
1171 						stops->push_back(newColorStop(stop_color,atof(opacity.data()),offset));
1172 					}
1173     			}
1174 			}
1175 		}
1176 		if(stops)
1177 			lg.push_back(newLinearGradient(id,x1,y1,x2,y2,stops,mtx));
1178 	}
1179 }
1180 
1181 void
parser_radialGradient(const xmlpp::Node * node)1182 Svg_parser::parser_radialGradient(const xmlpp::Node* node){
1183 	if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)){
1184 		Glib::ustring id	=nodeElement->get_attribute_value("id");
1185 		float cx			=atof(nodeElement->get_attribute_value("cx").data());
1186 		float cy			=atof(nodeElement->get_attribute_value("cy").data());
1187 		float fx			=atof(nodeElement->get_attribute_value("fx").data());
1188 		float fy			=atof(nodeElement->get_attribute_value("fy").data());
1189 		float r				=atof(nodeElement->get_attribute_value("r").data());
1190 		Glib::ustring link	=nodeElement->get_attribute_value("href");//basic
1191 		Glib::ustring transform	=nodeElement->get_attribute_value("gradientTransform");
1192 
1193 		if(link.empty())
1194 			link = nodeElement->get_attribute_value("href","xlink");
1195 
1196 		if (cx!=fx || cy!=fy)
1197 			std::cout<<"SVG Parser: ignoring focus attributes for radial gradient";
1198 
1199 		//resolve transformations
1200 		SVGMatrix* mtx=NULL;
1201 		if(!transform.empty())
1202 			mtx=parser_transform (transform);
1203 
1204 		std::list<ColorStop*> *stops=NULL;
1205 		if(!link.empty()){
1206 			//inkscape always use link, i dont need parser stops here, but it's posible
1207 			stops=find_colorStop (link);
1208 		}
1209 		if(stops)
1210 			rg.push_back(newRadialGradient(id,cx,cy,r,stops,mtx));
1211 	}
1212 }
1213 
1214 ColorStop*
newColorStop(String color,float opacity,float pos)1215 Svg_parser::newColorStop(String color,float opacity,float pos){
1216 	ColorStop* _stop;
1217 	_stop=(ColorStop*)malloc(sizeof(ColorStop));
1218 	float r=getRed(color);
1219 	float g=getGreen(color);
1220 	float b=getBlue(color);
1221 	float a=opacity;
1222 	Color ret=adjustGamma(r/255,g/255,b/255,a);
1223 	_stop->r=ret.get_r();
1224 	_stop->g=ret.get_g();
1225 	_stop->b=ret.get_b();
1226 	_stop->a=ret.get_a();
1227 	_stop->pos=pos;
1228 	return _stop;
1229 }
1230 Color
adjustGamma(float r,float g,float b,float a)1231 Svg_parser::adjustGamma(float r,float g,float b,float a){
1232 	Color ret(r,g,b,a);
1233 	if(gamma.get_gamma_r()!=1.0){
1234 		if(ret.get_r() < 0)
1235 			ret.set_r(-gamma.r_F32_to_F32(-ret.get_r()));
1236 		else
1237 			ret.set_r(gamma.r_F32_to_F32(ret.get_r()));
1238 	}
1239 	if(gamma.get_gamma_g()!=1.0){
1240 		if(ret.get_g() < 0)
1241 			ret.set_g(-gamma.g_F32_to_F32(-ret.get_g()));
1242 		else
1243 			ret.set_g(gamma.g_F32_to_F32(ret.get_g()));
1244 	}
1245 	if(gamma.get_gamma_b()!=1.0){
1246 		if(ret.get_b() < 0)
1247 			ret.set_b(-gamma.b_F32_to_F32(-ret.get_b()));
1248 		else
1249 			ret.set_b(gamma.b_F32_to_F32(ret.get_b()));
1250 	}
1251 	return ret;
1252 }
1253 
1254 LinearGradient*
newLinearGradient(String name,float x1,float y1,float x2,float y2,std::list<ColorStop * > * stops,SVGMatrix * transform)1255 Svg_parser::newLinearGradient(String name,float x1,float y1, float x2,float y2,std::list<ColorStop*> *stops, SVGMatrix* transform){
1256 	LinearGradient* data;
1257 	data=(LinearGradient*)malloc(sizeof(LinearGradient));
1258 	sprintf(data->name,"%s",name.data());
1259 	data->x1=x1;
1260 	data->y1=y1;
1261 	data->x2=x2;
1262 	data->y2=y2;
1263 	data->stops=stops;
1264 	data->transform=transform;
1265    	return data;
1266 }
1267 
1268 RadialGradient*
newRadialGradient(String name,float cx,float cy,float r,std::list<ColorStop * > * stops,SVGMatrix * transform)1269 Svg_parser::newRadialGradient(String name,float cx,float cy,float r,std::list<ColorStop*> *stops, SVGMatrix* transform){
1270 	RadialGradient* data;
1271 	data=(RadialGradient*)malloc(sizeof(RadialGradient));
1272 	sprintf(data->name,"%s",name.data());
1273 	data->cx=cx;
1274 	data->cy=cy;
1275 	data->r=r;
1276 	data->stops=stops;
1277 	data->transform=transform;
1278 	return data;
1279 }
1280 
1281 BLine*
newBLine(std::list<Vertex * > * points,bool loop)1282 Svg_parser::newBLine(std::list<Vertex*> *points,bool loop){
1283 	BLine* data;
1284 	data=(BLine*)malloc(sizeof(BLine));
1285 	//sprintf(data->name,"%s",name.data());
1286 	data->points=new std::list<Vertex*> (*points);
1287 	data->loop=loop;
1288 	data->bline_id=new String(new_guid());
1289 	data->offset_id=new String(new_guid());
1290 	return data;
1291 }
1292 
1293 void
build_gamma(xmlpp::Element * root,float gamma)1294 Svg_parser::build_gamma(xmlpp::Element* root,float gamma){
1295 	root->set_attribute("type","colorcorrect");
1296 	root->set_attribute("active","true");
1297 	root->set_attribute("version","0.1");
1298 	root->set_attribute("desc","Gamma");
1299 	build_real (root->add_child("param"),"gamma",gamma);
1300 }
1301 
1302 void
build_translate(xmlpp::Element * root,float dx,float dy)1303 Svg_parser::build_translate(xmlpp::Element* root,float dx,float dy){
1304 	root->set_attribute("type","translate");
1305 	root->set_attribute("active","true");
1306 	root->set_attribute("version","0.1");
1307 	build_vector (root->add_child("param"),"origin",dx,dy);
1308 }
1309 void
build_rotate(xmlpp::Element * root,float dx,float dy,float angle)1310 Svg_parser::build_rotate(xmlpp::Element* root,float dx,float dy,float angle){
1311 	root->set_attribute("type","rotate");
1312 	root->set_attribute("active","true");
1313 	root->set_attribute("version","0.1");
1314 	build_vector (root->add_child("param"),"origin",dx,dy);
1315 	build_real   (root->add_child("param"),"amount",angle);
1316 }
1317 void
build_points(xmlpp::Element * root,std::list<Vertex * > p)1318 Svg_parser::build_points(xmlpp::Element* root,std::list<Vertex*> p){
1319 	root->set_attribute("name","vector_list");
1320 	xmlpp::Element *child=root->add_child("dynamic_list");
1321 	child->set_attribute("type","vector");
1322 	std::list<Vertex*>::iterator aux = p.begin();
1323 	while(aux!=p.end()){
1324 		xmlpp::Element *child_entry=child->add_child("entry");
1325 		xmlpp::Element *child_vector=child_entry->add_child("vector");
1326 		child_vector->add_child("x")->set_child_text(etl::strprintf("%f",(*aux)->x));
1327 		child_vector->add_child("y")->set_child_text(etl::strprintf("%f",(*aux)->y));
1328 		aux++;
1329 	}
1330 }
1331 void
build_vertex(xmlpp::Element * root,Vertex * p)1332 Svg_parser::build_vertex(xmlpp::Element* root , Vertex *p){
1333 	xmlpp::Element *child_comp=root->add_child("composite");
1334 	child_comp->set_attribute("type","bline_point");
1335 	build_vector (child_comp->add_child("param"),"point",p->x,p->y);
1336 	build_param (child_comp->add_child("width"),"","real","1.0000000000");
1337 	build_param (child_comp->add_child("origin"),"","real","0.5000000000");
1338 	if(p->split) build_param (child_comp->add_child("split"),"","bool","true");
1339 	else build_param (child_comp->add_child("split"),"","bool","false");
1340 	//tangent 1
1341 	xmlpp::Element *child_t1=child_comp->add_child("t1");
1342 	xmlpp::Element *child_rc=child_t1->add_child("radial_composite");
1343 	child_rc->set_attribute("type","vector");
1344 	build_param (child_rc->add_child("radius"),"","real",p->radius1);
1345 	build_param (child_rc->add_child("theta"),"","angle",p->angle1);
1346 	//tangent 2
1347 	xmlpp::Element *child_t2=child_comp->add_child("t2");
1348 	xmlpp::Element *child_rc2=child_t2->add_child("radial_composite");
1349 	child_rc2->set_attribute("type","vector");
1350 	build_param (child_rc2->add_child("radius"),"","real",p->radius2);
1351 	build_param (child_rc2->add_child("theta"),"","angle",p->angle2);
1352 
1353 }
1354 void
build_bline(xmlpp::Element * root,std::list<Vertex * > p,bool loop,String blineguid)1355 Svg_parser::build_bline(xmlpp::Element* root,std::list<Vertex*> p,bool loop,String blineguid){
1356 	root->set_attribute("name","bline");
1357 	xmlpp::Element *child=root->add_child("bline");
1358 	child->set_attribute("type","bline_point");
1359 	if(loop)
1360 		child->set_attribute("loop","true");
1361 	else
1362 		child->set_attribute("loop","false");
1363 	if(!blineguid.empty())	child->set_attribute("guid",blineguid);
1364 	std::list<Vertex*>::iterator aux = p.begin();
1365 	while(aux!=p.end()){
1366 		if(*aux) build_vertex (child->add_child("entry"),*aux);
1367 		aux++;
1368 	}
1369 }
1370 
1371 void
build_param(xmlpp::Element * root,String name,String type,String value)1372 Svg_parser::build_param(xmlpp::Element* root,String name,String type,String value){
1373 	if(!type.empty() && !value.empty()){
1374 		if(!name.empty())	root->set_attribute("name",name);
1375 		xmlpp::Element *child=root->add_child(type);
1376 		child->set_attribute("value",value);
1377 	}else{
1378 		root->get_parent()->remove_child(root);
1379 	}
1380 }
1381 void
build_param(xmlpp::Element * root,String name,String type,float value)1382 Svg_parser::build_param(xmlpp::Element* root,String name,String type,float value){
1383 	if(!type.empty()){
1384 		if(!name.empty()) root->set_attribute("name",name);
1385 		xmlpp::Element *child=root->add_child(type);
1386 		child->set_attribute("value",etl::strprintf ("%f",value));
1387 	}else{
1388 		root->get_parent()->remove_child(root);
1389 	}
1390 }
1391 void
build_param(xmlpp::Element * root,String name,String type,int value)1392 Svg_parser::build_param(xmlpp::Element* root,String name,String type,int value){
1393 	if(!type.empty()){
1394 			if(!name.empty()) root->set_attribute("name",name);
1395 			xmlpp::Element *child=root->add_child(type);
1396 			char *enteroc=new char[10];
1397 			sprintf(enteroc,"%d",value);
1398 			child->set_attribute("value",enteroc);
1399 			delete [] enteroc;
1400 	}else{
1401 		root->get_parent()->remove_child(root);
1402 	}
1403 }
1404 
1405 void
build_integer(xmlpp::Element * root,String name,int value)1406 Svg_parser::build_integer(xmlpp::Element* root,String name,int value){
1407 	if(name.compare("")!=0) root->set_attribute("name",name);
1408 	xmlpp::Element *child=root->add_child("integer");
1409 	char *enteroc=new char[10];
1410 	sprintf(enteroc,"%d",value);
1411 	child->set_attribute("value",enteroc);
1412 }
1413 void
build_real(xmlpp::Element * root,String name,float value)1414 Svg_parser::build_real(xmlpp::Element* root,String name,float value){
1415 	if(name.compare("")!=0) root->set_attribute("name",name);
1416 	xmlpp::Element *child=root->add_child("real");
1417 	char *realc=new char[20];
1418 	sprintf(realc,"%f",value);
1419 	child->set_attribute("value",realc);
1420 }
1421 
1422 void
build_color(xmlpp::Element * root,float r,float g,float b,float a)1423 Svg_parser::build_color(xmlpp::Element* root,float r,float g,float b,float a){
1424 	if(r>255 || g>255 || b>255 || a>1 || r<0 || g<0 || b<0 || a<0){
1425 		root->get_parent()->remove_child(root);
1426 		printf("Color aborted\n");
1427 		return;
1428 	}
1429 	Color ret=adjustGamma(r/255,g/255,b/255,a);
1430 
1431 	root->set_attribute("name","color");
1432 	xmlpp::Element *child=root->add_child("color");
1433 	child->add_child("r")->set_child_text(etl::strprintf("%f",ret.get_r()));
1434 	child->add_child("g")->set_child_text(etl::strprintf("%f",ret.get_g()));
1435 	child->add_child("b")->set_child_text(etl::strprintf("%f",ret.get_b()));
1436 	child->add_child("a")->set_child_text(etl::strprintf("%f",ret.get_a()));
1437 }
1438 void
build_vector(xmlpp::Element * root,String name,float x,float y)1439 Svg_parser::build_vector(xmlpp::Element* root,String name,float x,float y){
1440 
1441 	if(name.compare("")!=0) root->set_attribute("name",name);
1442 	xmlpp::Element *child=root->add_child("vector");
1443 	child->add_child("x")->set_child_text(etl::strprintf("%f",x));
1444 	child->add_child("y")->set_child_text(etl::strprintf("%f",y));
1445 
1446 }
1447 void
build_vector(xmlpp::Element * root,String name,float x,float y,String guid)1448 Svg_parser::build_vector (xmlpp::Element* root,String name,float x,float y,String guid){
1449 	if(name.compare("")!=0) root->set_attribute("name",name);
1450 	xmlpp::Element *child=root->add_child("vector");
1451 	if(!guid.empty()) child->set_attribute("guid",guid);
1452 	child->add_child("x")->set_child_text(etl::strprintf("%f",x));
1453 	child->add_child("y")->set_child_text(etl::strprintf("%f",y));
1454 }
1455 
1456 xmlpp::Element*
nodeStartBasicLayer(xmlpp::Element * root,String name)1457 Svg_parser::nodeStartBasicLayer(xmlpp::Element* root, String name){
1458 	root->set_attribute("type","group");
1459 	root->set_attribute("active","true");
1460 	root->set_attribute("version","0.1");
1461 	root->set_attribute("desc",name);
1462 	build_param (root->add_child("param"),"z_depth","real","0");
1463 	build_param (root->add_child("param"),"amount","real","1");
1464 	build_param (root->add_child("param"),"blend_method","integer","0");
1465 	build_vector (root->add_child("param"),"origin",0,0);
1466 	xmlpp::Element *child=root->add_child("param");
1467 	child->set_attribute("name","canvas");
1468 	return child->add_child("canvas");
1469 }
1470 
1471 /* === COORDINATES & TRANSFORMATIONS ======================================= */
1472 void
coor2vect(float * x,float * y)1473 Svg_parser::coor2vect(float *x,float *y){
1474 	float sx, sy;
1475 	sx=*x;
1476 	sy=*y;
1477 	sy= atof(height.c_str())-sy;
1478 	sx= sx - ox;
1479 	sy= sy - oy;
1480 	sx= sx / kux;
1481 	sy= sy / kux;
1482 	*x=sx; *y=sy;
1483 }
1484 
1485 void
setTg1(Vertex * p,float p1x,float p1y,float p2x,float p2y)1486 Svg_parser::setTg1(Vertex *p,float p1x,float p1y,float p2x,float p2y){
1487 	float rd=0,ag=0;
1488 	float d1x,d1y,d2x,d2y,dx,dy;
1489 	d1x=p1x*60;
1490 	d1y=p1y*60;
1491 	d2x=p2x*60;
1492 	d2y=p2y*60;
1493 	dx=d2x-d1x;
1494 	dy=d2y-d1y;
1495 	dx=dx*3;
1496 	dy=dy*3;
1497 	dx=dx/60;
1498 	dy=dy/60;
1499 	rd=sqrt(dx*dx + dy*dy);
1500 	if(dx>0 && dy>0){
1501 		ag=PI + atan(dy/dx);
1502 	}else if(dx>0 && dy<0){
1503 		ag=PI + atan(dy/dx);
1504 	}else if(dx<0 && dy<0){
1505 		ag=atan(dy/dx);
1506 	}else if(dx<0 && dy>0){
1507 		ag= 2*PI+atan(dy/dx);
1508 	}else if(dx==0 && dy>0){
1509 		ag=-1*PI/2;
1510 	}else if(dx==0 && dy<0){
1511 		ag=PI/2;
1512 	}else if(dx==0 && dy==0){
1513 		ag=0;
1514 	}else if(dx<0 && dy==0){
1515 		ag=0;
1516 	}else if(dx>0 && dy==0){
1517 		ag=PI;
1518 	}
1519 	ag= (ag*180)/PI;
1520 	p->radius1=rd;
1521 	p->angle1=ag;
1522 }
1523 void
setTg2(Vertex * p,float p1x,float p1y,float p2x,float p2y)1524 Svg_parser::setTg2(Vertex* p,float p1x,float p1y,float p2x,float p2y){
1525 	float rd=0,ag=0;
1526 	float d1x,d1y,d2x,d2y,dx,dy;
1527 	d1x=p1x*60;
1528 	d1y=p1y*60;
1529 	d2x=p2x*60;
1530 	d2y=p2y*60;
1531 	dx=d2x-d1x;
1532 	dy=d2y-d1y;
1533 	dx=dx*3;
1534 	dy=dy*3;
1535 	dx=dx/60;
1536 	dy=dy/60;
1537 
1538 	rd=sqrt(dx*dx + dy*dy);
1539 	if(dx>0 && dy>0){
1540 		ag=PI + atan(dy/dx);
1541 	//	printf("case 180-270\n");
1542 	}else if(dx>0 && dy<0){
1543 		ag=PI + atan(dy/dx);
1544 	//	printf("case 90-180\n");
1545 	}else if(dx<0 && dy<0){
1546 		ag=atan(dy/dx);
1547 	//	printf("case 0-90\n");
1548 	}else if(dx<0 && dy>0){
1549 		ag= 2*PI+atan(dy/dx);
1550 	//	printf("case 270-360\n");
1551 	}else if(dx==0 && dy>0){
1552 		ag=-1*PI/2;
1553 	}else if(dx==0 && dy<0){
1554 		ag=PI/2;
1555 	}else if(dx==0 && dy==0){
1556 		ag=0;
1557 	}else if(dx<0 && dy==0){
1558 		ag=0;
1559 	}else if(dx>0 && dy==0){
1560 		ag=PI;
1561 	}
1562 	ag= (ag*180)/PI;
1563 	ag=ag-180;
1564 	p->radius2=rd;
1565 	p->angle2=ag;
1566 }
1567 
1568 void
setSplit(Vertex * p,bool val)1569 Svg_parser::setSplit(Vertex* p,bool val){
1570 	if(p!=NULL){
1571 		p->split=val;
1572 	}
1573 }
1574 int
isFirst(Vertex * nodo,float a,float b)1575 Svg_parser::isFirst(Vertex* nodo,float a, float b){
1576 	if(nodo->x==a && nodo->y==b)
1577 		return 1;
1578 	return 0;
1579 }
1580 
1581 Vertex*
newVertex(float x,float y)1582 Svg_parser::newVertex(float x,float y){
1583 	Vertex* vert;
1584 	vert=(Vertex*)malloc(sizeof(Vertex));
1585 	vert->x=x;
1586 	vert->y=y;
1587 	vert->radius1=vert->radius2=vert->angle1=vert->angle2=0;
1588 	return vert;
1589 }
1590 
1591 //matrices
1592 SVGMatrix*
parser_transform(const String transform)1593 Svg_parser::parser_transform(const String transform){
1594 	SVGMatrix* a=NULL;
1595 	String tf(transform);
1596 	removeIntoS(&tf);
1597 	std::vector<String> tokens=tokenize(tf," ");
1598 	std::vector<String>::iterator aux=tokens.begin();
1599 	while(aux!=tokens.end()){
1600 		if((*aux).compare(0,9,"translate")==0){
1601 			float dx,dy;
1602 			int start,end;
1603 			start	=(*aux).find_first_of("(")+1;
1604 			end		=(*aux).find_first_of(",");
1605 			dx		=atof((*aux).substr(start,end-start).data());
1606 			start	=(*aux).find_first_of(",")+1;
1607 			end		=(*aux).size()-1;
1608 			dy		=atof((*aux).substr(start,end-start).data());
1609 			if(matrixIsNull(a))
1610 				a=newSVGMatrix(1,0,0,1,dx,dy);
1611 			else
1612 				multiplySVGMatrix(&a,newSVGMatrix(1,0,0,1,dx,dy));
1613 		}else if((*aux).compare(0,5,"scale")==0){
1614 			if(matrixIsNull(a))
1615 				a=newSVGMatrix(1,0,0,1,0,0);
1616 		}else if((*aux).compare(0,6,"rotate")==0){
1617 			float angle,seno,coseno;
1618 			int start,end;
1619 			start	=(*aux).find_first_of("(")+1;
1620 			end		=(*aux).size()-1;
1621 			angle=getRadian (atof((*aux).substr(start,end-start).data()));
1622 			seno   =sin(angle);
1623 			coseno =cos(angle);
1624 			if(matrixIsNull(a))
1625 				a=newSVGMatrix(coseno,seno,-1*seno,coseno,0,0);
1626 			else
1627 				multiplySVGMatrix(&a,newSVGMatrix(coseno,seno,-1*seno,coseno,0,0));
1628 		}else if((*aux).compare(0,6,"matrix")==0){
1629 			int start	=(*aux).find_first_of('(')+1;
1630 			int end		=(*aux).find_first_of(')');
1631 			if(matrixIsNull(a))
1632 				a=newSVGMatrix((*aux).substr(start,end-start));
1633 			else
1634 				multiplySVGMatrix(&a,newSVGMatrix((*aux).substr(start,end-start)));
1635 		}else{
1636 			a=newSVGMatrix(1,0,0,1,0,0);
1637 		}
1638 		aux++;
1639 	}
1640 	return a;
1641 }
1642 
1643 SVGMatrix*
newSVGMatrix(SVGMatrix * a)1644 Svg_parser::newSVGMatrix(SVGMatrix *a){
1645 	SVGMatrix* data;
1646 	data=(SVGMatrix*)malloc(sizeof(SVGMatrix));
1647 	data->a=a->a;		data->b=a->b;		data->c=a->c;
1648 	data->d=a->d;		data->e=a->e;		data->f=a->f;
1649 	return data;
1650 }
1651 SVGMatrix*
newSVGMatrix(float a,float b,float c,float d,float e,float f)1652 Svg_parser::newSVGMatrix(float a,float b,float c,float d,float e,float f){
1653 	SVGMatrix* data;
1654 	data=(SVGMatrix*)malloc(sizeof(SVGMatrix));
1655 	data->a=a;		data->b=b;		data->c=c;
1656 	data->d=d;		data->e=e;		data->f=f;
1657 	return data;
1658 }
1659 SVGMatrix*
newSVGMatrix(const String mvector)1660 Svg_parser::newSVGMatrix(const String mvector){
1661 	if(!mvector.empty()){
1662 		std::vector<String> tokens=tokenize(mvector,",");
1663 		if(tokens.size()!=6) return newSVGMatrix(1,0,0,1,0,0);
1664 		SVGMatrix* data=(SVGMatrix*)malloc(sizeof(SVGMatrix));
1665 		data->a=atof(tokens.at(0).data());
1666 		data->b=atof(tokens.at(1).data());
1667 		data->c=atof(tokens.at(2).data());
1668 		data->d=atof(tokens.at(3).data());
1669 		data->e=atof(tokens.at(4).data());
1670 		data->f=atof(tokens.at(5).data());
1671 		return data;
1672 	}else{
1673 		return newSVGMatrix(1,0,0,1,0,0);
1674 	}
1675 }
1676 void
transformPoint2D(SVGMatrix * mtx,float * a,float * b)1677 Svg_parser::transformPoint2D(SVGMatrix *mtx,float *a,float *b){
1678 	float auxa,auxb;
1679 	auxa=0;
1680 	auxb=0;
1681 	auxa= (*a)*(mtx->a) + (*b)*(mtx->c) + (mtx->e);
1682 	auxb= (*a)*(mtx->b) + (*b)*(mtx->d) + (mtx->f);
1683 	*a=auxa;
1684 	*b=auxb;
1685 	return;
1686 }
1687 void
composeSVGMatrix(SVGMatrix ** mtx,SVGMatrix * mtx1,SVGMatrix * mtx2)1688 Svg_parser::composeSVGMatrix(SVGMatrix **mtx,SVGMatrix* mtx1,SVGMatrix* mtx2){
1689 	SVGMatrix* aux=newSVGMatrix(0,0,0,0,0,0);
1690 	aux->a=(mtx1->a)*(mtx2->a)+(mtx1->c)*(mtx2->b);
1691 	aux->b=(mtx1->b)*(mtx2->a)+(mtx1->d)*(mtx2->b);
1692 	aux->c=(mtx1->a)*(mtx2->c)+(mtx1->c)*(mtx2->d);
1693 	aux->d=(mtx1->b)*(mtx2->c)+(mtx1->d)*(mtx2->d);
1694 	aux->e=(mtx1->a)*(mtx2->e)+(mtx1->c)*(mtx2->f)+(mtx1->e);
1695 	aux->f=(mtx1->b)*(mtx2->e)+(mtx1->d)*(mtx2->f)+(mtx1->f);
1696 	*mtx=aux;
1697 }
1698 void
multiplySVGMatrix(SVGMatrix ** mtx1,SVGMatrix * mtx2)1699 Svg_parser::multiplySVGMatrix(SVGMatrix **mtx1,SVGMatrix *mtx2){
1700 	SVGMatrix* aux=newSVGMatrix(0,0,0,0,0,0);
1701 	aux->a=((*mtx1)->a)*(mtx2->a)+((*mtx1)->c)*(mtx2->b);
1702 	aux->b=((*mtx1)->b)*(mtx2->a)+((*mtx1)->d)*(mtx2->b);
1703 	aux->c=((*mtx1)->a)*(mtx2->c)+((*mtx1)->c)*(mtx2->d);
1704 	aux->d=((*mtx1)->b)*(mtx2->c)+((*mtx1)->d)*(mtx2->d);
1705 	aux->e=((*mtx1)->a)*(mtx2->e)+((*mtx1)->c)*(mtx2->f)+((*mtx1)->e);
1706 	aux->f=((*mtx1)->b)*(mtx2->e)+((*mtx1)->d)*(mtx2->f)+((*mtx1)->f);
1707 	(*mtx1)->a=aux->a;
1708 	(*mtx1)->b=aux->b;
1709 	(*mtx1)->c=aux->c;
1710 	(*mtx1)->d=aux->d;
1711 	(*mtx1)->e=aux->e;
1712 	(*mtx1)->f=aux->f;
1713 }
1714 bool
matrixIsNull(SVGMatrix * mtx)1715 Svg_parser::matrixIsNull(SVGMatrix *mtx){
1716 	if(mtx == NULL) return true;
1717 	return false;
1718 }
1719 
1720 /* === EXTRA METHODS ======================================================= */
1721 
1722 int
extractSubAttribute(const String attribute,String name,String * value)1723 Svg_parser::extractSubAttribute(const String attribute, String name,String* value){
1724 	int encounter=0;
1725 	if(!attribute.empty()){
1726 		String str(attribute);
1727 		removeS(&str);
1728 		std::vector<String> tokens=tokenize(str,";");
1729 		std::vector<String>::iterator aux=tokens.begin();
1730 		while(aux!=tokens.end()){
1731 			int mid= (*aux).find_first_of(":");
1732 			if((*aux).substr(0,mid).compare(name)==0){
1733 				int end=(*aux).size();
1734 				*value=(*aux).substr(mid+1,end-mid);
1735 				return 1;
1736 			}
1737 			aux++;
1738 		}
1739 	}
1740 	return encounter;
1741 }
1742 String
loadAttribute(String name,const String path_style,const String master_style,const String defaultVal)1743 Svg_parser::loadAttribute(String name,const String path_style,const String master_style,const String defaultVal){
1744 	String value;
1745 	int fnd=0;
1746 	if(!path_style.empty())
1747 		fnd=extractSubAttribute(path_style,name,&value);
1748 	if(fnd==0){
1749 		if(!master_style.empty())
1750 			fnd=extractSubAttribute(master_style,name,&value);
1751 		if(fnd==0)
1752 			value=defaultVal;
1753 	}
1754 	return value;
1755 }
1756 String
loadAttribute(String name,const String path_style,const String master_style,const String subattribute,const String defaultVal)1757 Svg_parser::loadAttribute(String name,const String path_style,const String master_style,const String subattribute,const String defaultVal){
1758 	String value;
1759 	int fnd=0;
1760 	if(!path_style.empty())
1761 		fnd=extractSubAttribute(path_style,name,&value);
1762 	if(fnd==0 && !master_style.empty())
1763 			fnd=extractSubAttribute(master_style,name,&value);
1764 	if(fnd==0){
1765 		if(!subattribute.empty())
1766 			value=subattribute;
1767 		else
1768 			value=defaultVal;
1769 	}
1770 	return value;
1771 }
1772 
1773 std::vector<String>
get_tokens_path(String path)1774 Svg_parser::get_tokens_path(String path){ //mini path lexico-parser
1775 	std::vector<String> tokens;
1776 	String buffer;
1777 	int e=0;
1778 	unsigned int i=0;
1779 	char a;
1780 	while(i<path.size()){
1781 		a=path.at(i);
1782 		switch(e){
1783 			case 0: //initial state
1784 					if(a=='m'){ e=1; i++;}
1785 					else if(a=='c'){ e= 2; i++;}
1786 					else if(a=='q'){ e= 3; i++;}
1787 					else if(a=='t'){ e= 4; i++;}
1788 					else if(a=='a'){ e= 5; i++;}
1789 					else if(a=='l'){ e= 6; i++;}
1790 					else if(a=='v'){ e= 7; i++;}
1791 					else if(a=='h'){ e= 8; i++;}
1792 					else if(a=='M'){ e= 9; i++;}
1793 					else if(a=='C'){ e=10; i++;}
1794 					else if(a=='Q'){ e=11; i++;}
1795 					else if(a=='T'){ e=12; i++;}
1796 					else if(a=='A'){ e=13; i++;}
1797 					else if(a=='L'){ e=14; i++;}
1798 					else if(a=='V'){ e=15; i++;}
1799 					else if(a=='H'){ e=16; i++;}
1800 					else if(a=='z' || a=='Z'){ e=17; i++;}
1801 					else if(a=='-' || a=='.' || a=='e' || a=='E' || isdigit (a)){ e=18;}
1802 					else if(a==','){ e=19; i++;}
1803 					else if(a==' '){i++;}
1804 					else {
1805 						synfig::warning("unknown token in SVG path '%c'", a);
1806 						i++;
1807 					}
1808 					break;
1809 			//relative
1810 			case 1 : tokens.push_back("m"); e=0; break;//move
1811 			case 2 : tokens.push_back("c"); e=0; break;//curve
1812 			case 3 : tokens.push_back("q"); e=0; break;//quadratic
1813 			case 4 : tokens.push_back("t"); e=0; break;//smooth quadratic
1814 			case 5 : tokens.push_back("a"); e=0; break;//elliptic arc
1815 			case 6 : tokens.push_back("l"); e=0; break;//line to
1816 			case 7 : tokens.push_back("v"); e=0; break;//vertical
1817 			case 8 : tokens.push_back("h"); e=0; break;//horizontal
1818 			//absolute
1819 			case 9 : tokens.push_back("M"); e=0; break;
1820 			case 10: tokens.push_back("C"); e=0; break;
1821 			case 11: tokens.push_back("Q"); e=0; break;
1822 			case 12: tokens.push_back("T"); e=0; break;
1823 			case 13: tokens.push_back("A"); e=0; break;
1824 			case 14: tokens.push_back("L"); e=0; break;
1825 			case 15: tokens.push_back("V"); e=0; break;
1826 			case 16: tokens.push_back("H"); e=0; break;
1827 
1828 			case 17: tokens.push_back("z"); e=0; break;//loop
1829 			case 18: if(a=='-' || a=='.' || a=='e' || a=='E' || isdigit (a)){
1830 						buffer.append(path.substr(i,1));i++;
1831 					}else{
1832 						e=20;
1833 					}
1834 					break;
1835 			case 19: tokens.push_back(","); e=0; break;
1836 			case 20: tokens.push_back(buffer);
1837 					buffer.clear();
1838 					e=0; break;
1839 			default: break;
1840 		}
1841 	}
1842 	switch(e){//last element
1843 		case 1 : tokens.push_back("m"); break;
1844 		case 2 : tokens.push_back("c"); break;
1845 		case 3 : tokens.push_back("q"); break;
1846 		case 4 : tokens.push_back("t"); break;
1847 		case 5 : tokens.push_back("a"); break;
1848 		case 6 : tokens.push_back("l"); break;
1849 		case 7 : tokens.push_back("v"); break;
1850 		case 8 : tokens.push_back("h"); break;
1851 		case 9 : tokens.push_back("M"); break;
1852 		case 10: tokens.push_back("C"); break;
1853 		case 11: tokens.push_back("Q"); break;
1854 		case 12: tokens.push_back("T"); break;
1855 		case 13: tokens.push_back("A"); break;
1856 		case 14: tokens.push_back("L"); break;
1857 		case 15: tokens.push_back("V"); break;
1858 		case 16: tokens.push_back("H"); break;
1859 		case 17: tokens.push_back("z"); break;
1860 		case 18: tokens.push_back(buffer); break;
1861 		case 19: tokens.push_back(","); break;
1862 		case 20: tokens.push_back(buffer); break;
1863 		default: break;
1864 	}
1865 	return tokens;
1866 }
1867 
1868 int
randomLetter()1869 Svg_parser::randomLetter(){
1870 	int a=rand()%2;
1871 	if(a) return (49 + rand()%9);
1872 	else return  (65 + rand()%24);
1873 }
1874 
1875 int
getRed(String hex)1876 Svg_parser::getRed(String hex){
1877 	if(hex.at(0)=='#'){
1878 		//allow for 3-digit hex codes (#rgb = #rrggbb)
1879 		if (hex.length()<7) return (16+1) * hextodec(hex.substr(1,1));
1880 		return hextodec(hex.substr(1,2));
1881 	}else if(hex.compare(0,3,"rgb")==0 || hex.compare(0,3,"RGB")==0){
1882 		int start=hex.find_first_of("(")+1;
1883 		int end	=hex.find_last_of(")");
1884 		String aux=tokenize(hex.substr(start,end-start),",").at(0);
1885 		return atoi(aux.data());
1886 	}
1887 	return getColor(hex,1);
1888 }
1889 int
getGreen(String hex)1890 Svg_parser::getGreen(String hex){
1891 	if(hex.at(0)=='#'){
1892 		if (hex.length()<7) return (16+1) * hextodec(hex.substr(2,1));
1893 		return hextodec(hex.substr(3,2));
1894 	}else if(hex.compare(0,3,"rgb")==0 || hex.compare(0,3,"RGB")==0){
1895 		int start=hex.find_first_of("(")+1;
1896 		int end	=hex.find_last_of(")");
1897 		String aux=tokenize(hex.substr(start,end-start),",").at(1);
1898 		return atoi(aux.data());
1899 	}
1900 	return getColor(hex,2);
1901 }
1902 int
getBlue(String hex)1903 Svg_parser::getBlue(String hex){
1904 	if(hex.at(0)=='#'){
1905 		if (hex.length()<7) return (16+1) * hextodec(hex.substr(3,1));
1906 		return hextodec(hex.substr(5,2));
1907 	}else if(hex.compare(0,3,"rgb")==0 || hex.compare(0,3,"RGB")==0){
1908 		int start=hex.find_first_of("(")+1;
1909 		int end	=hex.find_last_of(")");
1910 		String aux=tokenize(hex.substr(start,end-start),",").at(2);
1911 		return atoi(aux.data());
1912 	}
1913 	return getColor(hex,3);
1914 }
1915 int
hextodec(String hex)1916 Svg_parser::hextodec(String hex){
1917 	int result=0;
1918 	if(!hex.empty()){
1919 		int top=hex.size();
1920 		int ihex[top];
1921 		int i=0;
1922 		while(i<top){
1923 			if(hex.at(i)=='0')
1924 				ihex[i]=0;
1925 			else if(hex.at(i)=='1')
1926 				ihex[i]=1;
1927 			else if(hex.at(i)=='2')
1928 				ihex[i]=2;
1929 			else if(hex.at(i)=='3')
1930 				ihex[i]=3;
1931 			else if(hex.at(i)=='4')
1932 				ihex[i]=4;
1933 			else if(hex.at(i)=='5')
1934 				ihex[i]=5;
1935 			else if(hex.at(i)=='6')
1936 				ihex[i]=6;
1937 			else if(hex.at(i)=='7')
1938 				ihex[i]=7;
1939 			else if(hex.at(i)=='8')
1940 				ihex[i]=8;
1941 			else if(hex.at(i)=='9')
1942 				ihex[i]=9;
1943 			else if(hex.at(i)=='a')
1944 				ihex[i]=10;
1945 			else if(hex.at(i)=='b')
1946 				ihex[i]=11;
1947 			else if(hex.at(i)=='c')
1948 				ihex[i]=12;
1949 			else if(hex.at(i)=='d')
1950 				ihex[i]=13;
1951 			else if(hex.at(i)=='e')
1952 				ihex[i]=14;
1953 			else if(hex.at(i)=='f')
1954 				ihex[i]=15;
1955 			else
1956 				return 0;
1957 			i++;
1958 		}
1959 		i=0;
1960 		while(i<top){
1961 			result+=pow(16,i)*ihex[top-i-1];
1962 			i++;
1963 		}
1964 	}
1965 	return result;
1966 }
1967 
1968 float
getDimension(const String ac)1969 Svg_parser::getDimension(const String ac){
1970 	if(ac.empty()){
1971 		return 0;
1972 	}
1973 	int length=ac.size();
1974 	float af=0;
1975 	if(isdigit(ac.at(length-1))){
1976 		af=atof(ac.data());
1977 	}else if(ac.at(length-1)=='%'){
1978 			return 1024;
1979 	}else{
1980 		String mtc=ac.substr(length-2,length);
1981 		String nmc=ac.substr(0,length-2);
1982 		if(mtc.compare("px")==0){
1983 			af=atof(nmc.data());
1984 		}else if(mtc.compare("pt")==0){
1985 			af=atof(nmc.data())*1.25;
1986 		}else if(mtc.compare("em")==0){
1987 			af=atof(nmc.data())*16;
1988 		}else if(mtc.compare("mm")==0){
1989 			af=atof(nmc.data())*3.54;
1990 		}else if(mtc.compare("pc")==0){
1991 			af=atof(nmc.data())*15;
1992 		}else if(mtc.compare("cm")==0){
1993 			af=atof(nmc.data())*35.43;
1994 		}else if(mtc.compare("in")==0){
1995 			af=atof(nmc.data())*90;
1996 		}else{
1997 			return 1024;
1998 		}
1999 	}
2000 	return af;
2001 }
2002 
2003 float
getRadian(float sexa)2004 Svg_parser::getRadian(float sexa){
2005 	return (sexa*2*PI)/360;
2006 }
2007 void
removeS(String * input)2008 Svg_parser::removeS(String *input){
2009 	for(unsigned int i=0;i<input->size();i++){
2010 		if(input->at(i)==' '){
2011 			input->erase(i,1);
2012 		}
2013 	}
2014 }
2015 void
removeIntoS(String * input)2016 Svg_parser::removeIntoS(String *input){
2017 	bool into=false;
2018 	for(unsigned int i=0;i<input->size();i++){
2019 		if(input->at(i)=='('){
2020 			into=true;
2021 		}else if(input->at(i)==')'){
2022 			into=false;
2023 		}else if(into && input->at(i)==' '){
2024 			input->erase(i,1);
2025 		}
2026 	}
2027 }
2028 std::vector<String>
tokenize(const String & str,const String & delimiters)2029 Svg_parser::tokenize(const String& str,const String& delimiters){
2030 	std::vector<String> tokens;
2031 	String::size_type lastPos = str.find_first_not_of(delimiters, 0);
2032 	String::size_type pos = str.find_first_of(delimiters, lastPos);
2033 	while (String::npos != pos || String::npos != lastPos){
2034 		tokens.push_back(str.substr(lastPos, pos - lastPos));
2035 		lastPos = str.find_first_not_of(delimiters, pos);
2036 		pos = str.find_first_of(delimiters, lastPos);
2037 	}
2038 	return tokens;
2039 }
2040 String
new_guid()2041 Svg_parser::new_guid(){
2042 	uid++;
2043 	return GUID::hasher(uid).get_string();
2044 }
2045 
2046 
2047 #define COLOR_NAME(color, r, g, b) else if(name.compare(0,strlen(color),color)==0) \
2048                    {switch(position) \
2049 		               {case 1: return r; case 2: return g; case 3: return b;}  }
2050 
2051 int
getColor(String name,int position)2052 Svg_parser::getColor(String name, int position){
2053 	if (position<1 || position>3) return 0;
2054 	COLOR_NAME("aliceblue",240, 248, 255)
2055 	COLOR_NAME("antiquewhite",250, 235, 215)
2056 	COLOR_NAME("aqua", 0, 255, 255)
2057 	COLOR_NAME("aquamarine",127, 255, 212)
2058 	COLOR_NAME("azure",240, 255, 255)
2059 	COLOR_NAME("beige",245, 245, 220)
2060 	COLOR_NAME("bisque",255, 228, 196)
2061 	COLOR_NAME("black", 0, 0, 0)
2062 	COLOR_NAME("blanchedalmond",255, 235, 205)
2063 	COLOR_NAME("blue", 0, 0, 255)
2064 	COLOR_NAME("blueviolet",138, 43, 226)
2065 	COLOR_NAME("brown",165, 42, 42)
2066 	COLOR_NAME("burlywood",222, 184, 135)
2067 	COLOR_NAME("cadetblue", 95, 158, 160)
2068 	COLOR_NAME("chartreuse",127, 255, 0)
2069 	COLOR_NAME("chocolate",210, 105, 30)
2070 	COLOR_NAME("coral",255, 127, 80)
2071 	COLOR_NAME("cornflowerblue",100, 149, 237)
2072 	COLOR_NAME("cornsilk",255, 248, 220)
2073 	COLOR_NAME("crimson",220, 20, 60)
2074 	COLOR_NAME("cyan", 0, 255, 255)
2075 	COLOR_NAME("darkblue", 0, 0, 139)
2076 	COLOR_NAME("darkcyan", 0, 139, 139)
2077 	COLOR_NAME("darkgoldenrod",184, 134, 11)
2078 	COLOR_NAME("darkgray",169, 169, 169)
2079 	COLOR_NAME("darkgreen", 0, 100, 0)
2080 	COLOR_NAME("darkgrey",169, 169, 169)
2081 	COLOR_NAME("darkkhaki",189, 183, 107)
2082 	COLOR_NAME("darkmagenta",139, 0, 139)
2083 	COLOR_NAME("darkolivegreen", 85, 107, 47)
2084 	COLOR_NAME("darkorange",255, 140, 0)
2085 	COLOR_NAME("darkorchid",153, 50, 204)
2086 	COLOR_NAME("darkred",139, 0, 0)
2087 	COLOR_NAME("darksalmon",233, 150, 122)
2088 	COLOR_NAME("darkseagreen",143, 188, 143)
2089 	COLOR_NAME("darkslateblue", 72, 61, 139)
2090 	COLOR_NAME("darkslategray", 47, 79, 79)
2091 	COLOR_NAME("darkslategrey", 47, 79, 79)
2092 	COLOR_NAME("darkturquoise", 0, 206, 209)
2093 	COLOR_NAME("darkviolet",148, 0, 211)
2094 	COLOR_NAME("deeppink",255, 20, 147)
2095 	COLOR_NAME("deepskyblue", 0, 191, 255)
2096 	COLOR_NAME("dimgray",105, 105, 105)
2097 	COLOR_NAME("dimgrey",105, 105, 105)
2098 	COLOR_NAME("dodgerblue", 30, 144, 255)
2099 	COLOR_NAME("firebrick",178, 34, 34)
2100 	COLOR_NAME("floralwhite",255, 250, 240)
2101 	COLOR_NAME("forestgreen", 34, 139, 34)
2102 	COLOR_NAME("fuchsia",255, 0, 255)
2103 	COLOR_NAME("gainsboro",220, 220, 220)
2104 	COLOR_NAME("ghostwhite",248, 248, 255)
2105 	COLOR_NAME("gold",255, 215, 0)
2106 	COLOR_NAME("goldenrod",218, 165, 32)
2107 	COLOR_NAME("gray",128, 128, 128)
2108 	COLOR_NAME("grey",128, 128, 128)
2109 	COLOR_NAME("green", 0, 128, 0)
2110 	COLOR_NAME("greenyellow",173, 255, 47)
2111 	COLOR_NAME("honeydew",240, 255, 240)
2112 	COLOR_NAME("hotpink",255, 105, 180)
2113 	COLOR_NAME("indianred",205, 92, 92)
2114 	COLOR_NAME("indigo", 75, 0, 130)
2115 	COLOR_NAME("ivory",255, 255, 240)
2116 	COLOR_NAME("khaki",240, 230, 140)
2117 	COLOR_NAME("lavender",230, 230, 250)
2118 	COLOR_NAME("lavenderblush",255, 240, 245)
2119 	COLOR_NAME("lawngreen",124, 252, 0)
2120 	COLOR_NAME("lemonchiffon",255, 250, 205)
2121 	COLOR_NAME("lightblue",173, 216, 230)
2122 	COLOR_NAME("lightcoral",240, 128, 128)
2123 	COLOR_NAME("lightcyan",224, 255, 255)
2124 	COLOR_NAME("lightgoldenrodyellow",250, 250, 210)
2125 	COLOR_NAME("lightgray",211, 211, 211)
2126 	COLOR_NAME("lightgreen",144, 238, 144)
2127 	COLOR_NAME("lightgrey",211, 211, 211)
2128 	COLOR_NAME("lightpink",255, 182, 193)
2129 	COLOR_NAME("lightsalmon",255, 160, 122)
2130 	COLOR_NAME("lightseagreen", 32, 178, 170)
2131 	COLOR_NAME("lightskyblue",135, 206, 250)
2132 	COLOR_NAME("lightslategray",119, 136, 153)
2133 	COLOR_NAME("lightslategrey",119, 136, 153)
2134 	COLOR_NAME("lightsteelblue",176, 196, 222)
2135 	COLOR_NAME("lightyellow",255, 255, 224)
2136 	COLOR_NAME("lime", 0, 255, 0)
2137 	COLOR_NAME("limegreen", 50, 205, 50)
2138 	COLOR_NAME("linen",250, 240, 230)
2139 	COLOR_NAME("magenta",255, 0, 255)
2140 	COLOR_NAME("maroon",128, 0, 0)
2141 	COLOR_NAME("mediumaquamarine",102, 205, 170)
2142 	COLOR_NAME("mediumblue", 0, 0, 205)
2143 	COLOR_NAME("mediumorchid",186, 85, 211)
2144 	COLOR_NAME("mediumpurple",147, 112, 219)
2145 	COLOR_NAME("mediumseagreen", 60, 179, 113)
2146 	COLOR_NAME("mediumslateblue",123, 104, 238)
2147 	COLOR_NAME("mediumspringgreen", 0, 250, 154)
2148 	COLOR_NAME("mediumturquoise", 72, 209, 204)
2149 	COLOR_NAME("mediumvioletred",199, 21, 133)
2150 	COLOR_NAME("midnightblue", 25, 25, 112)
2151 	COLOR_NAME("mintcream",245, 255, 250)
2152 	COLOR_NAME("mistyrose",255, 228, 225)
2153 	COLOR_NAME("moccasin",255, 228, 181)
2154 	COLOR_NAME("navajowhite",255, 222, 173)
2155 	COLOR_NAME("navy", 0, 0, 128)
2156 	COLOR_NAME("oldlace",253, 245, 230)
2157 	COLOR_NAME("olive",128, 128, 0)
2158 	COLOR_NAME("olivedrab",107, 142, 35)
2159 	COLOR_NAME("orange",255, 165, 0)
2160 	COLOR_NAME("orangered",255, 69, 0)
2161 	COLOR_NAME("orchid",218, 112, 214)
2162 	COLOR_NAME("palegoldenrod",238, 232, 170)
2163 	COLOR_NAME("palegreen",152, 251, 152)
2164 	COLOR_NAME("paleturquoise",175, 238, 238)
2165 	COLOR_NAME("palevioletred",219, 112, 147)
2166 	COLOR_NAME("papayawhip",255, 239, 213)
2167 	COLOR_NAME("peachpuff",255, 218, 185)
2168 	COLOR_NAME("peru",205, 133, 63)
2169 	COLOR_NAME("pink",255, 192, 203)
2170 	COLOR_NAME("plum",221, 160, 221)
2171 	COLOR_NAME("powderblue",176, 224, 230)
2172 	COLOR_NAME("purple",128, 0, 128)
2173 	COLOR_NAME("red",255, 0, 0)
2174 	COLOR_NAME("rosybrown",188, 143, 143)
2175 	COLOR_NAME("royalblue", 65, 105, 225)
2176 	COLOR_NAME("saddlebrown",139, 69, 19)
2177 	COLOR_NAME("salmon",250, 128, 114)
2178 	COLOR_NAME("sandybrown",244, 164, 96)
2179 	COLOR_NAME("seagreen", 46, 139, 87)
2180 	COLOR_NAME("seashell",255, 245, 238)
2181 	COLOR_NAME("sienna",160, 82, 45)
2182 	COLOR_NAME("silver",192, 192, 192)
2183 	COLOR_NAME("skyblue",135, 206, 235)
2184 	COLOR_NAME("slateblue",106, 90, 205)
2185 	COLOR_NAME("slategray",112, 128, 144)
2186 	COLOR_NAME("slategrey",112, 128, 144)
2187 	COLOR_NAME("snow",255, 250, 250)
2188 	COLOR_NAME("springgreen", 0, 255, 127)
2189 	COLOR_NAME("steelblue", 70, 130, 180)
2190 	COLOR_NAME("tan",210, 180, 140)
2191 	COLOR_NAME("teal", 0, 128, 128)
2192 	COLOR_NAME("thistle",216, 191, 216)
2193 	COLOR_NAME("tomato",255, 99, 71)
2194 	COLOR_NAME("turquoise", 64, 224, 208)
2195 	COLOR_NAME("violet",238, 130, 238)
2196 	COLOR_NAME("wheat",245, 222, 179)
2197 	COLOR_NAME("white",255, 255, 255)
2198 	COLOR_NAME("whitesmoke",245, 245, 245)
2199 	COLOR_NAME("yellow",255, 255, 0)
2200 	COLOR_NAME("yellowgreen",154, 205, 50)
2201 	return 0;
2202 }
2203 #undef COLOR_NAME
2204