#include "Painter.h" namespace Upp { Painter& Painter::Path(CParser& p) { Pointf current(0, 0); bool done = false; int previousCmd = 0; while(!p.IsEof()) { while(p.Char(',')); int c = p.GetChar(); p.Spaces(); bool rel = IsLower(c); Pointf t, t1, t2; auto ReadDouble = [&] { while(p.Char(',')); return p.IsDouble2() ? p.ReadDouble() : 0; }; auto ReadPointP = [&](Pointf current, bool rel) { Pointf t; t.x = ReadDouble(); t.y = ReadDouble(); if(rel) t += current; return t; }; auto ReadPoint = [&] { return ReadPointP(current, rel); }; auto IsDouble = [&] { while(p.Char(',')) {} return p.IsDouble2(); }; switch(ToUpper(c)) { case 'M': current = ReadPoint(); Move(current); case 'L': while(IsDouble()) { current = ReadPoint(); Line(current); } done = true; break; case 'Z': Close(); done = true; break; case 'H': while(IsDouble()) { current.x = p.ReadDouble() + rel * current.x; Line(current); done = true; } break; case 'V': while(IsDouble()) { current.y = p.ReadDouble() + rel * current.y; Line(current); done = true; } break; case 'C': while(IsDouble()) { t1 = ReadPoint(); t2 = ReadPoint(); current = ReadPoint(); Cubic(t1, t2, current); done = true; } break; case 'S': while(IsDouble()) { Pointf now = current; t2 = ReadPoint(); current = ReadPoint(); if(previousCmd != 'C' && previousCmd != 'S') Cubic(now, t2, current); else Cubic(t2, current); while(p.Char(',')); done = true; } break; case 'Q': while(IsDouble()) { t1 = ReadPoint(); current = ReadPoint(); Quadratic(t1, current); done = true; } break; case 'T': while(IsDouble()) { Pointf now = current; current = ReadPoint(); if(previousCmd != 'Q' && previousCmd != 'T') Quadratic(now, current); else Quadratic(current); done = true; } break; case 'A': while(IsDouble()) { t1 = ReadPointP(Pointf(0, 0), false); double xangle = ReadDouble(); auto ReadBool = [&] { while(p.Char(',')); if(p.Char('1')) return true; p.Char('0'); return false; }; bool large = ReadBool(); bool sweep = ReadBool(); current = ReadPoint(); SvgArc(t1, xangle * M_PI / 180.0, large, sweep, current); done = true; } break; default: if(!done) Move(0, 0); // to clear previous path return *this; } previousCmd = ToUpper(c); } if(!done) Move(0, 0); // to clear previous path return *this; } Painter& Painter::Path(const char *path) { try { CParser p(path); Path(p); } catch(CParser::Error) {} return *this; } }