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