Fix transform code misnesting
[synfig.git] / synfig-core / src / modules / mod_svg / svg_parser.cpp
index 226f57e..968981c 100644 (file)
@@ -10,6 +10,7 @@
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
 **     Copyright (c) 2008 Chris Moore
 **     Copyright (c) 2009 Carlos A. Sosa Navarro
+**     Copyright (c) 2009 Nikita Kitaev
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -39,6 +40,14 @@ using namespace synfig;
 
 /* === G L O B A L S ======================================================= */
 
+//PARSER PREFERENCES
+
+//Seperate transformations: apply transformations on a per-layer basis, rather than on canvases
+#define SVG_SEP_TRANSFORMS 1
+
+//Resolve BLine transformations: resolve transformations instead of creating transformation layers
+#define SVG_RESOLVE_BLINE 1
+
 /* === P R O C E D U R E S ================================================= */
 
 Canvas::Handle
@@ -117,6 +126,9 @@ Svg_parser::set_id(String source){
 */
 //UPDATE
 
+
+/* === PARSERS ============================================================= */
+
 void
 Svg_parser::parser_node(const xmlpp::Node* node){
        const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
@@ -203,15 +215,7 @@ Svg_parser::parser_canvas (const xmlpp::Node* node){
                else nodeRoot->add_child("name")->set_child_text("Synfig Animation 1");
        }
        set_canvas=1;
-       AdjustPointUrl ();
 }
-//Toplevel parser
-
-//parser preferences
-//Seperate transformations: apply transformations on a per-layer basis, rather than on canvases
-//Resolve BLine transformations: resolve transformations instead of creating transformation layers
-#define SVG_SEP_TRANSFORMS 1
-#define SVG_RESOLVE_BLINE 1
 
 void
 Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String parent_style,Matrix* mtx_parent){
@@ -226,7 +230,7 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
                //resolve transformations
                Matrix* mtx=NULL;
                if(!transform.empty())
-                       mtx=build_transform (transform);
+                       mtx=parser_transform (transform);
                if (SVG_SEP_TRANSFORMS)
                {
                        if(mtx_parent){
@@ -287,9 +291,9 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
 
                //make simple fills
                if(nodename.compare("rect")==0 && typeFill!=0){
-                       rect_simple(nodeElement,child_fill,fill,fill_opacity,opacity);
+                       parser_rect(nodeElement,child_fill,fill,fill_opacity,opacity);
                        if(typeFill==2){
-                               build_url (child_fill,fill,NULL);
+                               build_fill (child_fill,fill,NULL);
                        }
                        parser_effects(nodeElement,child_layer,parent_style,mtx);
                        return;
@@ -297,35 +301,30 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
 
 
                //=======================================================================
-               std::list<std::list<Vertice*> > k;
+
+               std::list<BLine*> k;
                //if we are creating a bline
 
-               //First, create the list of vertices
+               //First, create the list of Verteces
                if (SVG_RESOLVE_BLINE) {
                        if(nodename.compare("path")==0){
                                k=parser_path_d (nodeElement->get_attribute_value("d"),mtx);
                        } else if(nodename.compare("polygon")==0){
-                               k=parser_polygon_path (nodeElement->get_attribute_value("points"),mtx);
+                               k=parser_path_polygon (nodeElement->get_attribute_value("points"),mtx);
                        }
                } else {
                        if(nodename.compare("path")==0){
                                k=parser_path_d (nodeElement->get_attribute_value("d"),NULL);
                        } else if(nodename.compare("polygon")==0){
-                               k=parser_polygon_path (nodeElement->get_attribute_value("points"),NULL);
+                               k=parser_path_polygon (nodeElement->get_attribute_value("points"),NULL);
                        }
                }
                
-               int n = k.size();
-               String bline_id[n];
-               String offset_id[n];
-               for (int i=0;i<n;i++){
-                       bline_id[i]=new_guid();
-                       offset_id[i]=new_guid();
-               }
+               std::list<BLine *>::iterator aux;               
+               //int n = k.size();
 
-               std::list<std::list<Vertice*> >::iterator aux = k.begin();
                if(typeFill!=0){//region layer
-                       for (int i=0; aux!=k.end(); aux++){
+                       for (aux = k.begin(); aux!=k.end(); aux++){
                                xmlpp::Element *child_region=child_fill->add_child("layer");
                                child_region->set_attribute("type","region");
                                child_region->set_attribute("active","true");
@@ -335,7 +334,7 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
                                build_param (child_region->add_child("param"),"amount","real","1.0000000000");
                                build_param (child_region->add_child("param"),"blend_method","integer","0");
                                build_color (child_region->add_child("param"),getRed(fill),getGreen(fill),getBlue(fill),atof(fill_opacity.data())*atof(opacity.data()));
-                               build_vector (child_region->add_child("param"),"offset",0,0,offset_id[i]);
+                               build_vector (child_region->add_child("param"),"offset",0,0, *(*aux)->offset_id );
                                build_param (child_region->add_child("param"),"invert","bool","false");
                                build_param (child_region->add_child("param"),"antialias","bool","true");
                                build_param (child_region->add_child("param"),"feather","real","0.0000000000");
@@ -343,19 +342,17 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
                                if(fill_rule.compare("evenodd")==0) build_param (child_region->add_child("param"),"winding_style","integer","1");
                                else build_param (child_region->add_child("param"),"winding_style","integer","0");
 
-                               build_bline (child_region->add_child("param"),*aux,loop,bline_id[i]);
-                               i++;
+                               build_bline (child_region->add_child("param"),*(*aux)->points,(*aux)->loop,*(*aux)->bline_id); 
                        }
                }
                if(typeFill==2){ //gradient in onto mode (fill)
                        if (SVG_RESOLVE_BLINE)
-                               build_url(child_fill,fill,mtx);
+                               build_fill(child_fill,fill,mtx);
                        else
-                               build_url(child_fill,fill,NULL);
+                               build_fill(child_fill,fill,NULL);
                }
 
                if(typeStroke!=0){//outline layer
-                       int i=0;
                        for (aux=k.begin(); aux!=k.end(); aux++){
                                xmlpp::Element *child_outline=child_stroke->add_child("layer");
                                child_outline->set_attribute("type","outline");
@@ -366,7 +363,7 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
                                build_param (child_outline->add_child("param"),"amount","real","1.0000000000");
                                build_param (child_outline->add_child("param"),"blend_method","integer","0");
                                build_color (child_outline->add_child("param"),getRed(stroke),getGreen(stroke),getBlue(stroke),atof(stroke_opacity.data())*atof(opacity.data()));
-                               build_vector (child_outline->add_child("param"),"offset",0,0,offset_id[i]);
+                               build_vector (child_outline->add_child("param"),"offset",0,0,*(*aux)->offset_id);
                                build_param (child_outline->add_child("param"),"invert","bool","false");
                                build_param (child_outline->add_child("param"),"antialias","bool","true");
                                build_param (child_outline->add_child("param"),"feather","real","0.0000000000");
@@ -374,7 +371,7 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
                                //outline in nonzero
                                build_param (child_outline->add_child("param"),"winding_style","integer","0");
 
-                               build_bline (child_outline->add_child("param"),*aux,loop,bline_id[i]);
+                               build_bline (child_outline->add_child("param"),*(*aux)->points,(*aux)->loop,*(*aux)->bline_id);
 
                                stroke_width=etl::strprintf("%f",getDimension(stroke_width)/kux);
                                build_param (child_outline->add_child("param"),"width","real",stroke_width);
@@ -390,56 +387,24 @@ Svg_parser::parser_graphics(const xmlpp::Node* node,xmlpp::Element* root,String
                                }
                                build_param (child_outline->add_child("param"),"loopyness","real","1.0000000000");
                                build_param (child_outline->add_child("param"),"homogeneous_width","bool","true");
-
-
-                               i++;
                        }
 
                        if(typeStroke==2){ //gradient in onto mode (stroke)
-                       if (SVG_RESOLVE_BLINE)
-                               build_url(child_stroke,fill,mtx);
-                       else
-                               build_url(child_stroke,fill,NULL);
-                       }
-                       if (SVG_RESOLVE_BLINE)
-                               parser_effects(nodeElement,child_layer,parent_style,NULL);
-                       else
-                               parser_effects(nodeElement,child_layer,parent_style,mtx);
-               
+                               if (SVG_RESOLVE_BLINE)
+                                       build_fill(child_stroke,fill,mtx);
+                               else
+                                       build_fill(child_stroke,fill,NULL);
+                       }       
                }
+
+               if (SVG_RESOLVE_BLINE)
+                       parser_effects(nodeElement,child_layer,parent_style,NULL);
+               else
+                       parser_effects(nodeElement,child_layer,parent_style,mtx);
        }
 }
 
-void
-Svg_parser::rect_simple(const xmlpp::Element* nodeElement,xmlpp::Element* root,String fill, String fill_opacity, String opacity){
-       Glib::ustring rect_id           =nodeElement->get_attribute_value("id");
-       Glib::ustring rect_x            =nodeElement->get_attribute_value("x");
-       Glib::ustring rect_y            =nodeElement->get_attribute_value("y");
-       Glib::ustring rect_width        =nodeElement->get_attribute_value("width");
-       Glib::ustring rect_height       =nodeElement->get_attribute_value("height");
-
-       xmlpp::Element *child_rect=root->add_child("layer");
-       child_rect->set_attribute("type","rectangle");
-       child_rect->set_attribute("active","true");
-       child_rect->set_attribute("version","0.2");
-       child_rect->set_attribute("desc",rect_id);
-
-       build_real(child_rect->add_child("param"),"z_depth",0.0);
-       build_real(child_rect->add_child("param"),"amount",1.0);
-       build_integer(child_rect->add_child("param"),"blend_method",0);
-       build_color (child_rect->add_child("param"),getRed (fill),getGreen (fill),getBlue(fill),atof(opacity.data())*atof(fill_opacity.data()));
-
-       float auxx=atof(rect_x.c_str());
-       float auxy=atof(rect_y.c_str());
-       coor2vect(&auxx,&auxy);
-       build_vector (child_rect->add_child("param"),"point1",auxx,auxy);
-       auxx= atof(rect_x.c_str()) + atof(rect_width.c_str());
-       auxy= atof(rect_y.c_str()) + atof(rect_height.c_str());
-       coor2vect(&auxx,&auxy);
-       build_vector (child_rect->add_child("param"),"point2",auxx,auxy);
-
-
-}
+/* === LAYER PARSERS ======================================================= */
 
 void
 Svg_parser::parser_layer(const xmlpp::Node* node,xmlpp::Element* root,String parent_style,Matrix* mtx){
@@ -482,16 +447,50 @@ Svg_parser::parser_layer(const xmlpp::Node* node,xmlpp::Element* root,String par
                                parser_graphics (*iter,child_canvas,layer_style,mtx);
                }
                }
-               if (! SVG_SEP_TRANSFORMS) parser_effects(nodeElement,child_canvas,parent_style,mtx);
+               if (SVG_SEP_TRANSFORMS) parser_effects(nodeElement,child_canvas,parent_style,NULL);
+               else parser_effects(nodeElement,child_canvas,parent_style,mtx);
        }
 }
 
-std::list<std::list<Vertice*> >
-Svg_parser::parser_polygon_path(Glib::ustring polygon_points, Matrix* mtx){
-       std::list<std::list<Vertice*> > k0;
+void
+Svg_parser::parser_rect(const xmlpp::Element* nodeElement,xmlpp::Element* root,String fill, String fill_opacity, String opacity){
+       Glib::ustring rect_id           =nodeElement->get_attribute_value("id");
+       Glib::ustring rect_x            =nodeElement->get_attribute_value("x");
+       Glib::ustring rect_y            =nodeElement->get_attribute_value("y");
+       Glib::ustring rect_width        =nodeElement->get_attribute_value("width");
+       Glib::ustring rect_height       =nodeElement->get_attribute_value("height");
+
+       xmlpp::Element *child_rect=root->add_child("layer");
+       child_rect->set_attribute("type","rectangle");
+       child_rect->set_attribute("active","true");
+       child_rect->set_attribute("version","0.2");
+       child_rect->set_attribute("desc",rect_id);
+
+       build_real(child_rect->add_child("param"),"z_depth",0.0);
+       build_real(child_rect->add_child("param"),"amount",1.0);
+       build_integer(child_rect->add_child("param"),"blend_method",0);
+       build_color (child_rect->add_child("param"),getRed (fill),getGreen (fill),getBlue(fill),atof(opacity.data())*atof(fill_opacity.data()));
+
+       float auxx=atof(rect_x.c_str());
+       float auxy=atof(rect_y.c_str());
+       coor2vect(&auxx,&auxy);
+       build_vector (child_rect->add_child("param"),"point1",auxx,auxy);
+       auxx= atof(rect_x.c_str()) + atof(rect_width.c_str());
+       auxy= atof(rect_y.c_str()) + atof(rect_height.c_str());
+       coor2vect(&auxx,&auxy);
+       build_vector (child_rect->add_child("param"),"point2",auxx,auxy);
+
+
+}
+
+/* === CONVERT TO PATH PARSERS ============================================= */       
+
+std::list<BLine *>
+Svg_parser::parser_path_polygon(Glib::ustring polygon_points, Matrix* mtx){
+       std::list<BLine *> k0;
        if(polygon_points.empty())
                return k0;
-       std::list<Vertice*> k;
+       std::list<Vertex*> points;
        std::vector<String> tokens=get_tokens_path (polygon_points);
        unsigned int i;
        float ax,ay; ax=ay=0;
@@ -504,107 +503,17 @@ Svg_parser::parser_polygon_path(Glib::ustring polygon_points, Matrix* mtx){
                //adjust
                coor2vect(&ax,&ay);
                //save
-               k.push_back(newVertice(ax,ay));
+               points.push_back(newVertex(ax,ay));
        }
-       k0.push_front(k);
+       k0.push_front(newBLine(&points, true));
        return k0;
 }
 
-std::vector<String>
-Svg_parser::get_tokens_path(String path){ //mini path lexico-parser
-       std::vector<String> tokens;
-       String buffer;
-       int e=0;
-       unsigned int i=0;
-       char a;
-       while(i<path.size()){
-               a=path.at(i);
-               switch(e){
-                       case 0: //initial state
-                                       if(a=='m'){ e=1; i++;}
-                                       else if(a=='c'){ e= 2; i++;}
-                                       else if(a=='q'){ e= 3; i++;}
-                                       else if(a=='t'){ e= 4; i++;}
-                                       else if(a=='a'){ e= 5; i++;}
-                                       else if(a=='l'){ e= 6; i++;}
-                                       else if(a=='v'){ e= 7; i++;}
-                                       else if(a=='h'){ e= 8; i++;}
-                                       else if(a=='M'){ e= 9; i++;}
-                                       else if(a=='C'){ e=10; i++;}
-                                       else if(a=='Q'){ e=11; i++;}
-                                       else if(a=='T'){ e=12; i++;}
-                                       else if(a=='A'){ e=13; i++;}
-                                       else if(a=='L'){ e=14; i++;}
-                                       else if(a=='V'){ e=15; i++;}
-                                       else if(a=='H'){ e=16; i++;}
-                                       else if(a=='z' || a=='Z'){ e=17; i++;}
-                                       else if(a=='-' ||a=='.'|| isdigit (a)){ e=18;}
-                                       else if(a==','){ e=19; i++;}
-                                       else if(a==' '){i++;}
-                                       break;
-                       //relative
-                       case 1 : tokens.push_back("m"); e=0; break;//move
-                       case 2 : tokens.push_back("c"); e=0; break;//curve
-                       case 3 : tokens.push_back("q"); e=0; break;//quadratic
-                       case 4 : tokens.push_back("t"); e=0; break;//smooth quadratic
-                       case 5 : tokens.push_back("a"); e=0; break;//elliptic arc
-                       case 6 : tokens.push_back("l"); e=0; break;//line to
-                       case 7 : tokens.push_back("v"); e=0; break;//vertical
-                       case 8 : tokens.push_back("h"); e=0; break;//horizontal
-                       //absolute
-                       case 9 : tokens.push_back("M"); e=0; break;
-                       case 10: tokens.push_back("C"); e=0; break;
-                       case 11: tokens.push_back("Q"); e=0; break;
-                       case 12: tokens.push_back("T"); e=0; break;
-                       case 13: tokens.push_back("A"); e=0; break;
-                       case 14: tokens.push_back("L"); e=0; break;
-                       case 15: tokens.push_back("V"); e=0; break;
-                       case 16: tokens.push_back("H"); e=0; break;
-
-                       case 17: tokens.push_back("z"); e=0; break;//loop
-                       case 18: if(a=='-'||a=='.'|| isdigit (a)){
-                                               buffer.append(path.substr(i,1));i++;
-                                       }else{
-                                               e=20;
-                                       }
-                                       break;
-                       case 19: tokens.push_back(","); e=0; break;
-                       case 20: tokens.push_back(buffer);
-                                       buffer.clear();
-                                       e=0; break;
-                       default: break;
-               }
-       }
-       switch(e){//last element
-               case 1 : tokens.push_back("m"); break;
-               case 2 : tokens.push_back("c"); break;
-               case 3 : tokens.push_back("q"); break;
-               case 4 : tokens.push_back("t"); break;
-               case 5 : tokens.push_back("a"); break;
-               case 6 : tokens.push_back("l"); break;
-               case 7 : tokens.push_back("v"); break;
-               case 8 : tokens.push_back("h"); break;
-               case 9 : tokens.push_back("M"); break;
-               case 10: tokens.push_back("C"); break;
-               case 11: tokens.push_back("Q"); break;
-               case 12: tokens.push_back("T"); break;
-               case 13: tokens.push_back("A"); break;
-               case 14: tokens.push_back("L"); break;
-               case 15: tokens.push_back("V"); break;
-               case 16: tokens.push_back("H"); break;
-               case 17: tokens.push_back("z"); break;
-               case 18: tokens.push_back(buffer); break;
-               case 19: tokens.push_back(","); break;
-               case 20: tokens.push_back(buffer); break;
-               default: break;
-       }
-       return tokens;
-}
-
-std::list<std::list<Vertice*> >
+std::list<BLine *>
 Svg_parser::parser_path_d(String path_d,Matrix* mtx){
-       std::list<std::list<Vertice*> > k;
-       std::list<Vertice*> k1;
+       std::list<BLine *> k;
+       std::list<Vertex*> k1;
+
        std::vector<String> tokens=get_tokens_path(path_d);
        String command="M"; //the current command
        float ax,ay,tgx,tgy,tgx2,tgy2;//each method
@@ -612,7 +521,6 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
        float actual_x=0,actual_y=0; //in svg coordinate space
        float old_x=0,old_y=0; //needed in rare cases
        float init_x=0,init_y=0; //for closepath commands
-       loop=false;
 
        for(unsigned int i=0;i<tokens.size();i++){
                //if the token is a command, change the current command
@@ -631,9 +539,10 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
 
                //now parse the commands
                if(command.compare("M")==0 || command.compare("m")==0){ //move to
-                       if(!k1.empty())
-                               k.push_front(k1);
-                       k1.clear();
+                       if(!k1.empty()) {
+                               k.push_front(newBLine(&k1, false));
+                               k1.clear();
+                       }
                        //read
                        actual_x+=atof(tokens.at(i).data());
                        i++; if(tokens.at(i).compare(",")==0) i++;
@@ -646,7 +555,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        //operate and save
                        if(mtx) transformPoint2D(mtx,&ax,&ay);
                        coor2vect(&ax,&ay);
-                       k1.push_back(newVertice (ax,ay)); //first element
+                       k1.push_back(newVertex (ax,ay)); //first element
                        setSplit(k1.back(),TRUE);
                        //"If a moveto is followed by multiple pairs of coordinates,
                        // the subsequent pairs are treated as implicit lineto commands."
@@ -685,7 +594,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        if(isFirst(k1.front(),ax,ay)){
                                setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
                        }else{
-                               k1.push_back(newVertice (ax,ay));
+                               k1.push_back(newVertex (ax,ay));
                                setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
                                setSplit(k1.back(),TRUE);
                        }
@@ -712,7 +621,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        //save
                        setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
                        setSplit(k1.back(),FALSE);
-                       k1.push_back(newVertice (ax,ay));
+                       k1.push_back(newVertex (ax,ay));
                        setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
                }else if(command.compare("L")==0 || command.compare("l")==0){ //line to
                        //point
@@ -731,7 +640,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        if(isFirst(k1.front(),ax,ay)){
                                setTg1(k1.front(),k1.front()->x,k1.front()->y,k1.front()->x,k1.front()->y);
                        }else{
-                               k1.push_back(newVertice(ax,ay));
+                               k1.push_back(newVertex(ax,ay));
                                setTg1(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
                        }
                }else if(command.compare("H")==0 || command.compare("h")==0){// horizontal move
@@ -750,7 +659,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        if(isFirst(k1.front(),ax,ay)){
                                setTg1(k1.front(),k1.front()->x,k1.front()->y,k1.front()->x,k1.front()->y);
                        }else{
-                               k1.push_back(newVertice(ax,ay));
+                               k1.push_back(newVertex(ax,ay));
                                setTg1(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
                        }
                }else if(command.compare("V")==0 || command.compare("v")==0){//vertical
@@ -768,7 +677,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        if(isFirst(k1.front(),ax,ay)){
                                setTg1(k1.front(),k1.front()->x,k1.front()->y,k1.front()->x,k1.front()->y);
                        }else{
-                               k1.push_back(newVertice(ax,ay));
+                               k1.push_back(newVertex(ax,ay));
                                setTg1(k1.back(),k1.back()->x,k1.back()->y,k1.back()->x,k1.back()->y);
                        }
                }else if(command.compare("T")==0 || command.compare("t")==0){// I don't know what does it
@@ -780,14 +689,14 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        //isn't complete support, is only for circles
 
                        //this curve have 6 parameters
-                       //radio
-                       float radio_x,radio_y;
+                       //radius
+                       float radius_x,radius_y;
                        float angle;
                        bool sweep,large;
-                       //radio
-                       radio_x=atof(tokens.at(i).data());
+                       //radius
+                       radius_x=atof(tokens.at(i).data());
                        i++; if(tokens.at(i).compare(",")==0) i++;
-                       radio_y=atof(tokens.at(i).data());
+                       radius_y=atof(tokens.at(i).data());
                        //angle
                        i++; angle=atof(tokens.at(i).data());
                        //flags
@@ -800,10 +709,10 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        //how to draw?
                        if(!large && !sweep){
                                //points
-                               tgx2 = old_x + radio_x*0.5;
+                               tgx2 = old_x + radius_x*0.5;
                                tgy2 = old_y ;
                                tgx  = actual_x;
-                               tgy  = actual_y + radio_y*0.5;
+                               tgy  = actual_y + radius_y*0.5;
 
                                ax=actual_x;
                                ay=actual_y;
@@ -822,15 +731,15 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                                if(isFirst(k1.front(),ax,ay)){
                                        setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
                                }else{
-                                       k1.push_back(newVertice (ax,ay));
+                                       k1.push_back(newVertex (ax,ay));
                                        setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
                                        setSplit(k1.back(),TRUE);
                                }
                        }else if(!large &&  sweep){
                                //points
                                tgx2 = old_x;
-                               tgy2 = old_y + radio_y*0.5;
-                               tgx  = actual_x + radio_x*0.5;
+                               tgy2 = old_y + radius_y*0.5;
+                               tgx  = actual_x + radius_x*0.5;
                                tgy  = actual_y ;
 
                                ax=actual_x;
@@ -850,7 +759,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                                if(isFirst(k1.front(),ax,ay)){
                                        setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
                                }else{
-                                       k1.push_back(newVertice (ax,ay));
+                                       k1.push_back(newVertex (ax,ay));
                                        setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
                                        setSplit(k1.back(),TRUE);
                                }
@@ -862,16 +771,16 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                                if(old_x>actual_x) sense =-1;
                                float in_x,in_y,in_tgx1,in_tgy1,in_tgx2,in_tgy2;
                                in_x = (old_x+actual_x)/2;
-                               in_y = old_y - sense*radio_y;
-                               in_tgx1 = in_x - sense*(radio_x*0.5);
-                               in_tgx2 = in_x + sense*(radio_x*0.5);
+                               in_y = old_y - sense*radius_y;
+                               in_tgx1 = in_x - sense*(radius_x*0.5);
+                               in_tgx2 = in_x + sense*(radius_x*0.5);
                                in_tgy1 = in_y;
                                in_tgy2 = in_y;
                                //start/end points
                                tgx2=old_x;
-                               tgy2=actual_y - sense*(radio_y*0.5);
+                               tgy2=actual_y - sense*(radius_y*0.5);
                                tgx =actual_x;
-                               tgy =actual_y - sense*(radio_y*0.5);
+                               tgy =actual_y - sense*(radius_y*0.5);
 
                                ax=actual_x;
                                ay=actual_y;
@@ -897,7 +806,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                                //save the last tg2
                                setTg2(k1.back(),k1.back()->x,k1.back()->y,tgx2,tgy2);
                                //save the intermediate point
-                               k1.push_back(newVertice (in_x,in_y));
+                               k1.push_back(newVertex (in_x,in_y));
                                setTg1(k1.back(),k1.back()->x,k1.back()->y, in_tgx1 , in_tgy1);
                                setTg2(k1.back(),k1.back()->x,k1.back()->y, in_tgx2 , in_tgy2);
                                setSplit(k1.back(),TRUE); //this could be changed
@@ -905,15 +814,13 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                                if(isFirst(k1.front(),ax,ay)){
                                        setTg1(k1.front(),k1.front()->x,k1.front()->y,tgx,tgy);
                                }else{
-                                       k1.push_back(newVertice (ax,ay));
+                                       k1.push_back(newVertex (ax,ay));
                                        setTg1(k1.back(),k1.back()->x,k1.back()->y,tgx,tgy);
                                        setSplit(k1.back(),TRUE);
                                }
                        }
                }else if(command.compare("z")==0){
-                       loop=true;
-                       if(!k1.empty())
-                               k.push_front(k1);
+                       k.push_front(newBLine(&k1, true));
                        k1.clear();
                        if (i<tokens.size() && tokens.at(i).compare("M")!=0 && tokens.at(i).compare("m")!=0) {
                                //starting a new path, but not with a moveto
@@ -924,7 +831,7 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                                //operate and save
                                if(mtx) transformPoint2D(mtx,&ax,&ay);
                                coor2vect(&ax,&ay);
-                               k1.push_back(newVertice (ax,ay)); //first element
+                               k1.push_back(newVertex (ax,ay)); //first element
                                setSplit(k1.back(),TRUE);
                        }
                        i--; //decrement i to balance "i++" at command change
@@ -932,18 +839,41 @@ Svg_parser::parser_path_d(String path_d,Matrix* mtx){
                        std::cout<<"unsupported path token: "<<tokens.at(i)<<std::endl;
                }
        }
-       if(!k1.empty())
-               k.push_front(k1); //last element
+       if(!k1.empty()) {
+               k.push_front(newBLine(&k1, false)); //last element
+       }
        return k;
 }
 
+/* === EFFECTS PARSERS ===================================================== */
+
 void
 Svg_parser::parser_effects(const xmlpp::Element* nodeElement,xmlpp::Element* root,String parent_style,Matrix* mtx){
-       parser_transform(root, mtx);
+       build_transform(root, mtx);
+}
+
+/* === DEFS PARSERS ======================================================== */
+
+void
+Svg_parser::parser_defs(const xmlpp::Node* node){
+       const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
+       if(!nodeContent){
+               xmlpp::Node::NodeList list = node->get_children();
+               for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter){
+                       Glib::ustring name =(*iter)->get_name();
+                       if(name.compare("linearGradient")==0){
+                               parser_linearGradient(*iter);
+                       }else if(name.compare("radialGradient")==0){
+                               parser_radialGradient(*iter);
+                       }
+               }
+       }
 }
 
+/* === BUILDS ============================================================== */
+
 void
-Svg_parser::parser_transform(xmlpp::Element* root,Matrix* mtx){
+Svg_parser::build_transform(xmlpp::Element* root,Matrix* mtx){
        if (mtx) {
                xmlpp::Element *child_transform=root->add_child("layer");
                child_transform->set_attribute("type","warp");
@@ -980,46 +910,6 @@ Svg_parser::parser_transform(xmlpp::Element* root,Matrix* mtx){
        }
 }
 
-
-void
-Svg_parser::parser_defs(const xmlpp::Node* node){
-       const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
-       if(!nodeContent){
-               xmlpp::Node::NodeList list = node->get_children();
-               for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter){
-                       Glib::ustring name =(*iter)->get_name();
-                       if(name.compare("linearGradient")==0){
-                               parser_linearGradient(*iter);
-                       }else if(name.compare("radialGradient")==0){
-                               parser_radialGradient(*iter);
-                       }
-               }
-       }
-}
-
-void
-Svg_parser::AdjustPointUrl(){
-/*
-       if(!lg.empty()){//linealgradient
-               std::list<LinearGradient*>::iterator aux=lg.begin();
-               while(aux!=lg.end()){
-                       LinearGradient* auxlg=*aux;
-                       coor2vect (&auxlg->x1,&auxlg->y1);
-                       coor2vect (&auxlg->x2,&auxlg->y2);
-                       aux++;
-               }
-       }
-       if(!rg.empty()){//radialgradient
-               std::list<RadialGradient*>::iterator aux=rg.begin();
-               while(aux!=rg.end()){
-                       RadialGradient* auxrg=*aux;
-                       coor2vect (&auxrg->cx,&auxrg->cy);
-                       auxrg->r= auxrg->r/kux;
-                       aux++;
-               }
-       }
-*/
-}
 std::list<ColorStop*>*
 Svg_parser::find_colorStop(String name){
        if(!name.empty()){
@@ -1039,8 +929,9 @@ Svg_parser::find_colorStop(String name){
        }
        return NULL;
 }
+
 void
-Svg_parser::build_url(xmlpp::Element* root, String name,Matrix *mtx){
+Svg_parser::build_fill(xmlpp::Element* root, String name,Matrix *mtx){
        if(!name.empty()){
                int start=name.find_first_of("#")+1;
                int end=name.find_first_of(")");
@@ -1182,7 +1073,7 @@ Svg_parser::build_radialGradient(xmlpp::Element* root,RadialGradient* data,Matri
                        }else if (data->transform){
                                mtx2=data->transform;
                        }
-                       parser_transform(child_layer,mtx2);
+                       build_transform(child_layer,mtx2);
                        
                }else {
                        gradient=root->add_child("layer");
@@ -1198,7 +1089,7 @@ Svg_parser::build_radialGradient(xmlpp::Element* root,RadialGradient* data,Matri
                child_stops->set_attribute("name","gradient");
                build_stop_color (child_stops->add_child("gradient"),data->stops);
 
-               //here the center point and radio
+               //here the center point and radius
                float cx=data->cx;
                float cy=data->cy;
                float r =data->r;
@@ -1228,7 +1119,7 @@ Svg_parser::parser_linearGradient(const xmlpp::Node* node){
                //resolve transformations
                Matrix* mtx=NULL;
                if(!transform.empty())
-                       mtx=build_transform (transform);
+                       mtx=parser_transform (transform);
 
                std::list<ColorStop*> *stops;
                if(!link.empty()){
@@ -1281,7 +1172,7 @@ Svg_parser::parser_radialGradient(const xmlpp::Node* node){
                //resolve transformations
                Matrix* mtx=NULL;
                if(!transform.empty())
-                       mtx=build_transform (transform);
+                       mtx=parser_transform (transform);
 
                std::list<ColorStop*> *stops=NULL;
                if(!link.empty()){
@@ -1360,7 +1251,18 @@ Svg_parser::newRadialGradient(String name,float cx,float cy,float r,std::list<Co
        return data;
 }
 
-//builds
+BLine*
+Svg_parser::newBLine(std::list<Vertex*> *points,bool loop){
+       BLine* data;
+       data=(BLine*)malloc(sizeof(BLine));
+       //sprintf(data->name,"%s",name.data());
+       data->points=new std::list<Vertex*> (*points);
+       data->loop=loop;
+       data->bline_id=new String(new_guid());
+       data->offset_id=new String(new_guid());
+       return data;
+}
+
 void
 Svg_parser::build_gamma(xmlpp::Element* root,float gamma){
        root->set_attribute("type","colorcorrect");
@@ -1369,56 +1271,6 @@ Svg_parser::build_gamma(xmlpp::Element* root,float gamma){
        root->set_attribute("desc","Gamma");
        build_real (root->add_child("param"),"gamma",gamma);
 }
-Matrix*
-Svg_parser::build_transform(const String transform){
-       Matrix* a=NULL;
-       String tf(transform);
-       removeIntoS(&tf);
-       std::vector<String> tokens=tokenize(tf," ");
-       std::vector<String>::iterator aux=tokens.begin();
-       while(aux!=tokens.end()){
-               if((*aux).compare(0,9,"translate")==0){
-                       float dx,dy;
-                       int start,end;
-                       start   =(*aux).find_first_of("(")+1;
-                       end             =(*aux).find_first_of(",");
-                       dx              =atof((*aux).substr(start,end-start).data());
-                       start   =(*aux).find_first_of(",")+1;
-                       end             =(*aux).size()-1;
-                       dy              =atof((*aux).substr(start,end-start).data());
-                       if(matrixIsNull(a))
-                               a=newMatrix(1,0,0,1,dx,dy);
-                       else
-                               multiplyMatrix(&a,newMatrix(1,0,0,1,dx,dy));
-               }else if((*aux).compare(0,5,"scale")==0){
-                       if(matrixIsNull(a))
-                               a=newMatrix(1,0,0,1,0,0);
-               }else if((*aux).compare(0,6,"rotate")==0){
-                       float angle,seno,coseno;
-                       int start,end;
-                       start   =(*aux).find_first_of("(")+1;
-                       end             =(*aux).size()-1;
-                       angle=getRadian (atof((*aux).substr(start,end-start).data()));
-                       seno   =sin(angle);
-                       coseno =cos(angle);
-                       if(matrixIsNull(a))
-                               a=newMatrix(coseno,seno,-1*seno,coseno,0,0);
-                       else
-                               multiplyMatrix(&a,newMatrix(coseno,seno,-1*seno,coseno,0,0));
-               }else if((*aux).compare(0,6,"matrix")==0){
-                       int start       =(*aux).find_first_of('(')+1;
-                       int end         =(*aux).find_first_of(')');
-                       if(matrixIsNull(a))
-                               a=newMatrix((*aux).substr(start,end-start));
-                       else
-                               multiplyMatrix(&a,newMatrix((*aux).substr(start,end-start)));
-               }else{
-                       a=newMatrix(1,0,0,1,0,0);
-               }
-               aux++;
-       }
-       return a;
-}
 
 void
 Svg_parser::build_translate(xmlpp::Element* root,float dx,float dy){
@@ -1436,11 +1288,11 @@ Svg_parser::build_rotate(xmlpp::Element* root,float dx,float dy,float angle){
        build_real   (root->add_child("param"),"amount",angle);
 }
 void
-Svg_parser::build_points(xmlpp::Element* root,std::list<Vertice*> p){
+Svg_parser::build_points(xmlpp::Element* root,std::list<Vertex*> p){
        root->set_attribute("name","vector_list");
        xmlpp::Element *child=root->add_child("dynamic_list");
        child->set_attribute("type","vector");
-       std::list<Vertice*>::iterator aux = p.begin();
+       std::list<Vertex*>::iterator aux = p.begin();
        while(aux!=p.end()){
                xmlpp::Element *child_entry=child->add_child("entry");
                xmlpp::Element *child_vector=child_entry->add_child("vector");
@@ -1450,7 +1302,7 @@ Svg_parser::build_points(xmlpp::Element* root,std::list<Vertice*> p){
        }
 }
 void
-Svg_parser::build_vertice(xmlpp::Element* root , Vertice *p){
+Svg_parser::build_vertex(xmlpp::Element* root , Vertex *p){
        xmlpp::Element *child_comp=root->add_child("composite");
        child_comp->set_attribute("type","bline_point");
        build_vector (child_comp->add_child("param"),"point",p->x,p->y);
@@ -1462,18 +1314,18 @@ Svg_parser::build_vertice(xmlpp::Element* root , Vertice *p){
        xmlpp::Element *child_t1=child_comp->add_child("t1");
        xmlpp::Element *child_rc=child_t1->add_child("radial_composite");
        child_rc->set_attribute("type","vector");
-       build_param (child_rc->add_child("radius"),"","real",p->radio1);
+       build_param (child_rc->add_child("radius"),"","real",p->radius1);
        build_param (child_rc->add_child("theta"),"","angle",p->angle1);
        //tangent 2
        xmlpp::Element *child_t2=child_comp->add_child("t2");
        xmlpp::Element *child_rc2=child_t2->add_child("radial_composite");
        child_rc2->set_attribute("type","vector");
-       build_param (child_rc2->add_child("radius"),"","real",p->radio2);
+       build_param (child_rc2->add_child("radius"),"","real",p->radius2);
        build_param (child_rc2->add_child("theta"),"","angle",p->angle2);
 
 }
 void
-Svg_parser::build_bline(xmlpp::Element* root,std::list<Vertice*> p,bool loop,String blineguid){
+Svg_parser::build_bline(xmlpp::Element* root,std::list<Vertex*> p,bool loop,String blineguid){
        root->set_attribute("name","bline");
        xmlpp::Element *child=root->add_child("bline");
        child->set_attribute("type","bline_point");
@@ -1482,9 +1334,9 @@ Svg_parser::build_bline(xmlpp::Element* root,std::list<Vertice*> p,bool loop,Str
        else
                child->set_attribute("loop","false");
        if(!blineguid.empty())  child->set_attribute("guid",blineguid);
-       std::list<Vertice*>::iterator aux = p.begin();
+       std::list<Vertex*>::iterator aux = p.begin();
        while(aux!=p.end()){
-               if(*aux) build_vertice (child->add_child("entry"),*aux);
+               if(*aux) build_vertex (child->add_child("entry"),*aux);
                aux++;
        }
 }
@@ -1589,7 +1441,7 @@ Svg_parser::nodeStartBasicLayer(xmlpp::Element* root){
        return child->add_child("canvas");
 }
 
-//extra methods
+/* === COORDINATES & TRANSFORMATIONS ======================================= */
 void
 Svg_parser::coor2vect(float *x,float *y){
        float sx, sy;
@@ -1604,7 +1456,7 @@ Svg_parser::coor2vect(float *x,float *y){
 }
 
 void
-Svg_parser::setTg1(Vertice *p,float p1x,float p1y,float p2x,float p2y){
+Svg_parser::setTg1(Vertex *p,float p1x,float p1y,float p2x,float p2y){
        float rd=0,ag=0;
        float d1x,d1y,d2x,d2y,dx,dy;
        d1x=p1x*60;
@@ -1638,11 +1490,11 @@ Svg_parser::setTg1(Vertice *p,float p1x,float p1y,float p2x,float p2y){
                ag=PI;
        }
        ag= (ag*180)/PI;
-       p->radio1=rd;
+       p->radius1=rd;
        p->angle1=ag;
 }
 void
-Svg_parser::setTg2(Vertice* p,float p1x,float p1y,float p2x,float p2y){
+Svg_parser::setTg2(Vertex* p,float p1x,float p1y,float p2x,float p2y){
        float rd=0,ag=0;
        float d1x,d1y,d2x,d2y,dx,dy;
        d1x=p1x*60;
@@ -1682,33 +1534,164 @@ Svg_parser::setTg2(Vertice* p,float p1x,float p1y,float p2x,float p2y){
        }
        ag= (ag*180)/PI;
        ag=ag-180;
-       p->radio2=rd;
+       p->radius2=rd;
        p->angle2=ag;
 }
 
 void
-Svg_parser::setSplit(Vertice* p,bool val){
+Svg_parser::setSplit(Vertex* p,bool val){
        if(p!=NULL){
                p->split=val;
        }
 }
 int
-Svg_parser::isFirst(Vertice* nodo,float a, float b){
+Svg_parser::isFirst(Vertex* nodo,float a, float b){
        if(nodo->x==a && nodo->y==b)
                return 1;
        return 0;
 }
 
-Vertice*
-Svg_parser::newVertice(float x,float y){
-       Vertice* vert;
-       vert=(Vertice*)malloc(sizeof(Vertice));
+Vertex*
+Svg_parser::newVertex(float x,float y){
+       Vertex* vert;
+       vert=(Vertex*)malloc(sizeof(Vertex));
        vert->x=x;
        vert->y=y;
-       vert->radio1=vert->radio2=vert->angle1=vert->angle2=0;
+       vert->radius1=vert->radius2=vert->angle1=vert->angle2=0;
        return vert;
 }
 
+//matrices
+Matrix*
+Svg_parser::parser_transform(const String transform){
+       Matrix* a=NULL;
+       String tf(transform);
+       removeIntoS(&tf);
+       std::vector<String> tokens=tokenize(tf," ");
+       std::vector<String>::iterator aux=tokens.begin();
+       while(aux!=tokens.end()){
+               if((*aux).compare(0,9,"translate")==0){
+                       float dx,dy;
+                       int start,end;
+                       start   =(*aux).find_first_of("(")+1;
+                       end             =(*aux).find_first_of(",");
+                       dx              =atof((*aux).substr(start,end-start).data());
+                       start   =(*aux).find_first_of(",")+1;
+                       end             =(*aux).size()-1;
+                       dy              =atof((*aux).substr(start,end-start).data());
+                       if(matrixIsNull(a))
+                               a=newMatrix(1,0,0,1,dx,dy);
+                       else
+                               multiplyMatrix(&a,newMatrix(1,0,0,1,dx,dy));
+               }else if((*aux).compare(0,5,"scale")==0){
+                       if(matrixIsNull(a))
+                               a=newMatrix(1,0,0,1,0,0);
+               }else if((*aux).compare(0,6,"rotate")==0){
+                       float angle,seno,coseno;
+                       int start,end;
+                       start   =(*aux).find_first_of("(")+1;
+                       end             =(*aux).size()-1;
+                       angle=getRadian (atof((*aux).substr(start,end-start).data()));
+                       seno   =sin(angle);
+                       coseno =cos(angle);
+                       if(matrixIsNull(a))
+                               a=newMatrix(coseno,seno,-1*seno,coseno,0,0);
+                       else
+                               multiplyMatrix(&a,newMatrix(coseno,seno,-1*seno,coseno,0,0));
+               }else if((*aux).compare(0,6,"matrix")==0){
+                       int start       =(*aux).find_first_of('(')+1;
+                       int end         =(*aux).find_first_of(')');
+                       if(matrixIsNull(a))
+                               a=newMatrix((*aux).substr(start,end-start));
+                       else
+                               multiplyMatrix(&a,newMatrix((*aux).substr(start,end-start)));
+               }else{
+                       a=newMatrix(1,0,0,1,0,0);
+               }
+               aux++;
+       }
+       return a;
+}
+
+Matrix*
+Svg_parser::newMatrix(Matrix *a){
+       Matrix* data;
+       data=(Matrix*)malloc(sizeof(Matrix));
+       data->a=a->a;           data->b=a->b;           data->c=a->c;
+       data->d=a->d;           data->e=a->e;           data->f=a->f;
+       return data;
+}
+Matrix*
+Svg_parser::newMatrix(float a,float b,float c,float d,float e,float f){
+       Matrix* data;
+       data=(Matrix*)malloc(sizeof(Matrix));
+       data->a=a;              data->b=b;              data->c=c;
+       data->d=d;              data->e=e;              data->f=f;
+       return data;
+}
+Matrix*
+Svg_parser::newMatrix(const String mvector){
+       if(!mvector.empty()){
+               Matrix* data=(Matrix*)malloc(sizeof(Matrix));
+               std::vector<String> tokens=tokenize(mvector,",");
+               if(tokens.size()!=6) return newMatrix(1,0,0,1,0,0);
+               data->a=atof(tokens.at(0).data());
+               data->b=atof(tokens.at(1).data());
+               data->c=atof(tokens.at(2).data());
+               data->d=atof(tokens.at(3).data());
+               data->e=atof(tokens.at(4).data());
+               data->f=atof(tokens.at(5).data());
+               return data;
+       }else{
+               return newMatrix(1,0,0,1,0,0);
+       }
+}
+void
+Svg_parser::transformPoint2D(Matrix *mtx,float *a,float *b){
+       float auxa,auxb;
+       auxa=0;
+       auxb=0;
+       auxa= (*a)*(mtx->a) + (*b)*(mtx->c) + (mtx->e);
+       auxb= (*a)*(mtx->b) + (*b)*(mtx->d) + (mtx->f);
+       *a=auxa;
+       *b=auxb;
+       return;
+}
+void
+Svg_parser::composeMatrix(Matrix **mtx,Matrix* mtx1,Matrix* mtx2){
+       Matrix* aux=newMatrix(0,0,0,0,0,0);
+       aux->a=(mtx1->a)*(mtx2->a)+(mtx1->c)*(mtx2->b);
+       aux->b=(mtx1->b)*(mtx2->a)+(mtx1->d)*(mtx2->b);
+       aux->c=(mtx1->a)*(mtx2->c)+(mtx1->c)*(mtx2->d);
+       aux->d=(mtx1->b)*(mtx2->c)+(mtx1->d)*(mtx2->d);
+       aux->e=(mtx1->a)*(mtx2->e)+(mtx1->c)*(mtx2->f)+(mtx1->e);
+       aux->f=(mtx1->b)*(mtx2->e)+(mtx1->d)*(mtx2->f)+(mtx1->f);
+       *mtx=aux;
+}
+void
+Svg_parser::multiplyMatrix(Matrix **mtx1,Matrix *mtx2){
+       Matrix* aux=newMatrix(0,0,0,0,0,0);
+       aux->a=((*mtx1)->a)*(mtx2->a)+((*mtx1)->c)*(mtx2->b);
+       aux->b=((*mtx1)->b)*(mtx2->a)+((*mtx1)->d)*(mtx2->b);
+       aux->c=((*mtx1)->a)*(mtx2->c)+((*mtx1)->c)*(mtx2->d);
+       aux->d=((*mtx1)->b)*(mtx2->c)+((*mtx1)->d)*(mtx2->d);
+       aux->e=((*mtx1)->a)*(mtx2->e)+((*mtx1)->c)*(mtx2->f)+((*mtx1)->e);
+       aux->f=((*mtx1)->b)*(mtx2->e)+((*mtx1)->d)*(mtx2->f)+((*mtx1)->f);
+       (*mtx1)->a=aux->a;
+       (*mtx1)->b=aux->b;
+       (*mtx1)->c=aux->c;
+       (*mtx1)->d=aux->d;
+       (*mtx1)->e=aux->e;
+       (*mtx1)->f=aux->f;
+}
+bool
+Svg_parser::matrixIsNull(Matrix *mtx){
+       if(mtx == NULL) return true;
+       return false;
+}
+
+/* === EXTRA METHODS ======================================================= */
+
 int
 Svg_parser::extractSubAttribute(const String attribute, String name,String* value){
        int encounter=0;
@@ -1760,6 +1743,97 @@ Svg_parser::loadAttribute(String name,const String path_style,const String maste
        return value;
 }
 
+std::vector<String>
+Svg_parser::get_tokens_path(String path){ //mini path lexico-parser
+       std::vector<String> tokens;
+       String buffer;
+       int e=0;
+       unsigned int i=0;
+       char a;
+       while(i<path.size()){
+               a=path.at(i);
+               switch(e){
+                       case 0: //initial state
+                                       if(a=='m'){ e=1; i++;}
+                                       else if(a=='c'){ e= 2; i++;}
+                                       else if(a=='q'){ e= 3; i++;}
+                                       else if(a=='t'){ e= 4; i++;}
+                                       else if(a=='a'){ e= 5; i++;}
+                                       else if(a=='l'){ e= 6; i++;}
+                                       else if(a=='v'){ e= 7; i++;}
+                                       else if(a=='h'){ e= 8; i++;}
+                                       else if(a=='M'){ e= 9; i++;}
+                                       else if(a=='C'){ e=10; i++;}
+                                       else if(a=='Q'){ e=11; i++;}
+                                       else if(a=='T'){ e=12; i++;}
+                                       else if(a=='A'){ e=13; i++;}
+                                       else if(a=='L'){ e=14; i++;}
+                                       else if(a=='V'){ e=15; i++;}
+                                       else if(a=='H'){ e=16; i++;}
+                                       else if(a=='z' || a=='Z'){ e=17; i++;}
+                                       else if(a=='-' ||a=='.'|| isdigit (a)){ e=18;}
+                                       else if(a==','){ e=19; i++;}
+                                       else if(a==' '){i++;}
+                                       break;
+                       //relative
+                       case 1 : tokens.push_back("m"); e=0; break;//move
+                       case 2 : tokens.push_back("c"); e=0; break;//curve
+                       case 3 : tokens.push_back("q"); e=0; break;//quadratic
+                       case 4 : tokens.push_back("t"); e=0; break;//smooth quadratic
+                       case 5 : tokens.push_back("a"); e=0; break;//elliptic arc
+                       case 6 : tokens.push_back("l"); e=0; break;//line to
+                       case 7 : tokens.push_back("v"); e=0; break;//vertical
+                       case 8 : tokens.push_back("h"); e=0; break;//horizontal
+                       //absolute
+                       case 9 : tokens.push_back("M"); e=0; break;
+                       case 10: tokens.push_back("C"); e=0; break;
+                       case 11: tokens.push_back("Q"); e=0; break;
+                       case 12: tokens.push_back("T"); e=0; break;
+                       case 13: tokens.push_back("A"); e=0; break;
+                       case 14: tokens.push_back("L"); e=0; break;
+                       case 15: tokens.push_back("V"); e=0; break;
+                       case 16: tokens.push_back("H"); e=0; break;
+
+                       case 17: tokens.push_back("z"); e=0; break;//loop
+                       case 18: if(a=='-'||a=='.'|| isdigit (a)){
+                                               buffer.append(path.substr(i,1));i++;
+                                       }else{
+                                               e=20;
+                                       }
+                                       break;
+                       case 19: tokens.push_back(","); e=0; break;
+                       case 20: tokens.push_back(buffer);
+                                       buffer.clear();
+                                       e=0; break;
+                       default: break;
+               }
+       }
+       switch(e){//last element
+               case 1 : tokens.push_back("m"); break;
+               case 2 : tokens.push_back("c"); break;
+               case 3 : tokens.push_back("q"); break;
+               case 4 : tokens.push_back("t"); break;
+               case 5 : tokens.push_back("a"); break;
+               case 6 : tokens.push_back("l"); break;
+               case 7 : tokens.push_back("v"); break;
+               case 8 : tokens.push_back("h"); break;
+               case 9 : tokens.push_back("M"); break;
+               case 10: tokens.push_back("C"); break;
+               case 11: tokens.push_back("Q"); break;
+               case 12: tokens.push_back("T"); break;
+               case 13: tokens.push_back("A"); break;
+               case 14: tokens.push_back("L"); break;
+               case 15: tokens.push_back("V"); break;
+               case 16: tokens.push_back("H"); break;
+               case 17: tokens.push_back("z"); break;
+               case 18: tokens.push_back(buffer); break;
+               case 19: tokens.push_back(","); break;
+               case 20: tokens.push_back(buffer); break;
+               default: break;
+       }
+       return tokens;
+}
+
 int
 Svg_parser::randomLetter(){
        int a=rand()%2;
@@ -1890,83 +1964,6 @@ Svg_parser::getDimension(const String ac){
        }
        return af;
 }
-//matrix operations
-Matrix*
-Svg_parser::newMatrix(Matrix *a){
-       Matrix* data;
-       data=(Matrix*)malloc(sizeof(Matrix));
-       data->a=a->a;           data->b=a->b;           data->c=a->c;
-       data->d=a->d;           data->e=a->e;           data->f=a->f;
-       return data;
-}
-Matrix*
-Svg_parser::newMatrix(float a,float b,float c,float d,float e,float f){
-       Matrix* data;
-       data=(Matrix*)malloc(sizeof(Matrix));
-       data->a=a;              data->b=b;              data->c=c;
-       data->d=d;              data->e=e;              data->f=f;
-       return data;
-}
-Matrix*
-Svg_parser::newMatrix(const String mvector){
-       if(!mvector.empty()){
-               Matrix* data=(Matrix*)malloc(sizeof(Matrix));
-               std::vector<String> tokens=tokenize(mvector,",");
-               if(tokens.size()!=6) return newMatrix(1,0,0,1,0,0);
-               data->a=atof(tokens.at(0).data());
-               data->b=atof(tokens.at(1).data());
-               data->c=atof(tokens.at(2).data());
-               data->d=atof(tokens.at(3).data());
-               data->e=atof(tokens.at(4).data());
-               data->f=atof(tokens.at(5).data());
-               return data;
-       }else{
-               return newMatrix(1,0,0,1,0,0);
-       }
-}
-void
-Svg_parser::transformPoint2D(Matrix *mtx,float *a,float *b){
-       float auxa,auxb;
-       auxa=0;
-       auxb=0;
-       auxa= (*a)*(mtx->a) + (*b)*(mtx->c) + (mtx->e);
-       auxb= (*a)*(mtx->b) + (*b)*(mtx->d) + (mtx->f);
-       *a=auxa;
-       *b=auxb;
-       return;
-}
-void
-Svg_parser::composeMatrix(Matrix **mtx,Matrix* mtx1,Matrix* mtx2){
-       Matrix* aux=newMatrix(0,0,0,0,0,0);
-       aux->a=(mtx1->a)*(mtx2->a)+(mtx1->c)*(mtx2->b);
-       aux->b=(mtx1->b)*(mtx2->a)+(mtx1->d)*(mtx2->b);
-       aux->c=(mtx1->a)*(mtx2->c)+(mtx1->c)*(mtx2->d);
-       aux->d=(mtx1->b)*(mtx2->c)+(mtx1->d)*(mtx2->d);
-       aux->e=(mtx1->a)*(mtx2->e)+(mtx1->c)*(mtx2->f)+(mtx1->e);
-       aux->f=(mtx1->b)*(mtx2->e)+(mtx1->d)*(mtx2->f)+(mtx1->f);
-       *mtx=aux;
-}
-void
-Svg_parser::multiplyMatrix(Matrix **mtx1,Matrix *mtx2){
-       Matrix* aux=newMatrix(0,0,0,0,0,0);
-       aux->a=((*mtx1)->a)*(mtx2->a)+((*mtx1)->c)*(mtx2->b);
-       aux->b=((*mtx1)->b)*(mtx2->a)+((*mtx1)->d)*(mtx2->b);
-       aux->c=((*mtx1)->a)*(mtx2->c)+((*mtx1)->c)*(mtx2->d);
-       aux->d=((*mtx1)->b)*(mtx2->c)+((*mtx1)->d)*(mtx2->d);
-       aux->e=((*mtx1)->a)*(mtx2->e)+((*mtx1)->c)*(mtx2->f)+((*mtx1)->e);
-       aux->f=((*mtx1)->b)*(mtx2->e)+((*mtx1)->d)*(mtx2->f)+((*mtx1)->f);
-       (*mtx1)->a=aux->a;
-       (*mtx1)->b=aux->b;
-       (*mtx1)->c=aux->c;
-       (*mtx1)->d=aux->d;
-       (*mtx1)->e=aux->e;
-       (*mtx1)->f=aux->f;
-}
-bool
-Svg_parser::matrixIsNull(Matrix *mtx){
-       if(mtx == NULL) return true;
-       return false;
-}
 
 float
 Svg_parser::getRadian(float sexa){