[haiku-commits] Change in haiku[master]: Icon-O-Matic: replace SVG parser with nanosvg

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 10 May 2020 16:58:19 +0000

From Adrien Destugues <pulkomandy@xxxxxxxxx>:

Adrien Destugues has uploaded this change for review. ( 
https://review.haiku-os.org/c/haiku/+/2661 ;)


Change subject: Icon-O-Matic: replace SVG parser with nanosvg
......................................................................

Icon-O-Matic: replace SVG parser with nanosvg

The parser is based on an old example from agg. NanoSVG is originally
based on the same code, but has lots of bugfixes and is actively
maintained. So it makes sense to use it.

This is incomplete, there are several regressions so far.

Nanosvg revision 25241c5a8f8451d41ab1b02ab2d865b01600d949
---
M src/apps/icon-o-matic/Jamfile
M src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp
M src/apps/icon-o-matic/import_export/svg/DocumentBuilder.h
D src/apps/icon-o-matic/import_export/svg/PathTokenizer.cpp
D src/apps/icon-o-matic/import_export/svg/PathTokenizer.h
D src/apps/icon-o-matic/import_export/svg/SVGGradients.cpp
D src/apps/icon-o-matic/import_export/svg/SVGGradients.h
M src/apps/icon-o-matic/import_export/svg/SVGImporter.cpp
D src/apps/icon-o-matic/import_export/svg/SVGParser.cpp
D src/apps/icon-o-matic/import_export/svg/SVGParser.h
A src/apps/icon-o-matic/import_export/svg/nanosvg.h
11 files changed, 3,132 insertions(+), 2,690 deletions(-)



  git pull ssh://git.haiku-os.org:22/haiku refs/changes/61/2661/1

diff --git a/src/apps/icon-o-matic/Jamfile b/src/apps/icon-o-matic/Jamfile
index 14a10e0..b2d19f4 100644
--- a/src/apps/icon-o-matic/Jamfile
+++ b/src/apps/icon-o-matic/Jamfile
@@ -233,11 +233,8 @@

        # import_export/svg
        DocumentBuilder.cpp
-       PathTokenizer.cpp
        SVGExporter.cpp
-       SVGGradients.cpp
        SVGImporter.cpp
-       SVGParser.cpp

        # shape
        PathManipulator.cpp
diff --git a/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp 
b/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp
index 39fd6d5..492ac0b 100644
--- a/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp
+++ b/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.cpp
@@ -6,21 +6,8 @@
  *             Stephan Aßmus <superstippi@xxxxxx>
  */

-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.2
-// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Contact: mcseem@xxxxxxxxxxxxx
-//               mcseemagg@xxxxxxxxx
-//               http://www.antigrain.com
-//----------------------------------------------------------------------------

+#define NANOSVG_IMPLEMENTATION
 #include "DocumentBuilder.h"

 #include <new>
@@ -28,8 +15,6 @@

 #include <Bitmap.h>

-#include <agg_bounding_rect.h>
-
 #include "AutoDeleter.h"
 #include "GradientTransformable.h"
 #include "Icon.h"
@@ -39,167 +24,25 @@
 #include "StrokeTransformer.h"
 #include "Style.h"
 #include "StyleContainer.h"
-#include "SVGGradients.h"
 #include "SVGImporter.h"
 #include "VectorPath.h"

+#include <agg_math_stroke.h>
+#include <agg_trans_affine.h>
+
 using std::nothrow;

-namespace agg {
-namespace svg {
-
 // constructor
-DocumentBuilder::DocumentBuilder()
-       : fGradients(20),
-         fCurrentGradient(NULL),
-         fWidth(0),
+DocumentBuilder::DocumentBuilder(NSVGimage* source)
+       : fWidth(0),
          fHeight(0),
          fViewBox(0.0, 0.0, -1.0, -1.0),
-         fTitle("")
+         fTitle(""),
+         fSource(source)
 {
 }


-// remove_all
-void
-DocumentBuilder::remove_all()
-{
-       fPathStorage.remove_all();
-       fAttributesStorage.remove_all();
-       fAttributesStack.remove_all();
-       fTransform.reset();
-}
-
-// begin_path
-void
-DocumentBuilder::begin_path()
-{
-       push_attr();
-       unsigned idx = fPathStorage.start_new_path();
-       fAttributesStorage.add(path_attributes(cur_attr(), idx));
-}
-
-// end_path
-void
-DocumentBuilder::end_path()
-{
-       if (fAttributesStorage.size() == 0) {
-               throw exception("end_path: The path was not begun");
-       }
-       path_attributes attr = cur_attr();
-       unsigned idx = fAttributesStorage[fAttributesStorage.size() - 1].index;
-       attr.index = idx;
-       fAttributesStorage[fAttributesStorage.size() - 1] = attr;
-       pop_attr();
-}
-
-// move_to
-void
-DocumentBuilder::move_to(double x, double y, bool rel)           // M, m
-{
-       if (rel)
-               fPathStorage.move_rel(x, y);
-       else
-               fPathStorage.move_to(x, y);
-}
-
-// line_to
-void
-DocumentBuilder::line_to(double x,  double y, bool rel)                 // L, l
-{
-       if (rel)
-               fPathStorage.line_rel(x, y);
-       else
-               fPathStorage.line_to(x, y);
-}
-
-// hline_to
-void
-DocumentBuilder::hline_to(double x, bool rel)                             // 
H, h
-{
-       if (rel)
-               fPathStorage.hline_rel(x);
-       else
-               fPathStorage.hline_to(x);
-}
-
-// vline_to
-void
-DocumentBuilder::vline_to(double y, bool rel)                             // 
V, v
-{
-       if (rel)
-               fPathStorage.vline_rel(y);
-       else
-               fPathStorage.vline_to(y);
-}
-
-// curve3
-void
-DocumentBuilder::curve3(double x1, double y1,                             // 
Q, q
-                                               double x,  double y, bool rel)
-{
-       if (rel)
-               fPathStorage.curve3_rel(x1, y1, x, y);
-       else
-               fPathStorage.curve3(x1, y1, x, y);
-}
-
-// curve3
-void
-DocumentBuilder::curve3(double x, double y, bool rel)             // T, t
-{
-       if (rel)
-               fPathStorage.curve3_rel(x, y);
-       else
-               fPathStorage.curve3(x, y);
-}
-
-// curve4
-void
-DocumentBuilder::curve4(double x1, double y1,                             // 
C, c
-                                               double x2, double y2,
-                                               double x,  double y, bool rel)
-{
-       if (rel) {
-               fPathStorage.curve4_rel(x1, y1, x2, y2, x, y);
-       } else {
-               fPathStorage.curve4(x1, y1, x2, y2, x, y);
-       }
-}
-
-// curve4
-void
-DocumentBuilder::curve4(double x2, double y2,                             // 
S, s
-                                               double x,  double y, bool rel)
-{
-       if (rel) {
-               fPathStorage.curve4_rel(x2, y2, x, y);
-       } else {
-               fPathStorage.curve4(x2, y2, x, y);
-       }
-}
-
-// elliptical_arc
-void
-DocumentBuilder::elliptical_arc(double rx, double ry, double angle,
-                                                           bool 
large_arc_flag, bool sweep_flag,
-                                                           double x, double y, 
bool rel)
-{
-       angle = angle / 180.0 * pi;
-       if (rel) {
-               fPathStorage.arc_rel(rx, ry, angle, large_arc_flag, sweep_flag, 
x, y);
-       } else {
-               fPathStorage.arc_to(rx, ry, angle, large_arc_flag, sweep_flag, 
x, y);
-       }
-}
-
-// close_subpath
-void
-DocumentBuilder::close_subpath()
-{
-       fPathStorage.end_poly(path_flags_close);
-}
-
 // SetTitle
 void
 DocumentBuilder::SetTitle(const char* title)
@@ -216,244 +59,6 @@
        fViewBox = viewBox;
 }

-// cur_attr
-path_attributes&
-DocumentBuilder::cur_attr()
-{
-       if (fAttributesStack.size() == 0) {
-               throw exception("cur_attr: Attribute stack is empty");
-       }
-       return fAttributesStack[fAttributesStack.size() - 1];
-}
-
-// push_attr
-void
-DocumentBuilder::push_attr()
-{
-//printf("DocumentBuilder::push_attr() (size: %d)\n", fAttributesStack.size());
-       fAttributesStack.add(fAttributesStack.size() ? 
fAttributesStack[fAttributesStack.size() - 1]
-                                                                               
                 : path_attributes());
-}
-
-// pop_attr
-void
-DocumentBuilder::pop_attr()
-{
-//printf("DocumentBuilder::pop_attr() (size: %d)\n", fAttributesStack.size());
-       if (fAttributesStack.size() == 0) {
-               throw exception("pop_attr: Attribute stack is empty");
-       }
-       fAttributesStack.remove_last();
-}
-
-// fill
-void
-DocumentBuilder::fill(const rgba8& f)
-{
-       path_attributes& attr = cur_attr();
-       attr.fill_color = f;
-       attr.fill_flag = true;
-}
-
-// stroke
-void
-DocumentBuilder::stroke(const rgba8& s)
-{
-       path_attributes& attr = cur_attr();
-       attr.stroke_color = s;
-       attr.stroke_flag = true;
-}
-
-// even_odd
-void
-DocumentBuilder::even_odd(bool flag)
-{
-       cur_attr().even_odd_flag = flag;
-}
-
-// stroke_width
-void
-DocumentBuilder::stroke_width(double w)
-{
-       path_attributes& attr = cur_attr();
-       attr.stroke_width = w;
-       attr.stroke_flag = true;
-}
-
-// fill_none
-void
-DocumentBuilder::fill_none()
-{
-       cur_attr().fill_flag = false;
-}
-
-// fill_url
-void
-DocumentBuilder::fill_url(const char* url)
-{
-       sprintf(cur_attr().fill_url, "%s", url);
-}
-
-// stroke_none
-void
-DocumentBuilder::stroke_none()
-{
-       cur_attr().stroke_flag = false;
-}
-
-// stroke_url
-void
-DocumentBuilder::stroke_url(const char* url)
-{
-       sprintf(cur_attr().stroke_url, "%s", url);
-}
-
-// opacity
-void
-DocumentBuilder::opacity(double op)
-{
-       cur_attr().opacity *= op;
-//printf("opacity: %.1f\n", cur_attr().opacity);
-}
-
-// fill_opacity
-void
-DocumentBuilder::fill_opacity(double op)
-{
-       cur_attr().fill_color.opacity(op);
-//     cur_attr().opacity *= op;
-}
-
-// stroke_opacity
-void
-DocumentBuilder::stroke_opacity(double op)
-{
-       cur_attr().stroke_color.opacity(op);
-//     cur_attr().opacity *= op;
-}
-
-// line_join
-void
-DocumentBuilder::line_join(line_join_e join)
-{
-       cur_attr().line_join = join;
-}
-
-// line_cap
-void
-DocumentBuilder::line_cap(line_cap_e cap)
-{
-       cur_attr().line_cap = cap;
-}
-
-// miter_limit
-void
-DocumentBuilder::miter_limit(double ml)
-{
-       cur_attr().miter_limit = ml;
-}
-
-// transform
-trans_affine&
-DocumentBuilder::transform()
-{
-       return cur_attr().transform;
-}
-
-// parse_path
-void
-DocumentBuilder::parse_path(PathTokenizer& tok)
-{
-       char lastCmd = 0;
-       while(tok.next()) {
-               double arg[10];
-               char cmd = tok.last_command();
-               unsigned i;
-               switch(cmd) {
-                       case 'M': case 'm':
-                               arg[0] = tok.last_number();
-                               arg[1] = tok.next(cmd);
-                               if (lastCmd != cmd)
-                                       move_to(arg[0], arg[1], cmd == 'm');
-                               else
-                                       line_to(arg[0], arg[1], lastCmd == 'm');
-                               break;
-
-                       case 'L': case 'l':
-                               arg[0] = tok.last_number();
-                               arg[1] = tok.next(cmd);
-                               line_to(arg[0], arg[1], cmd == 'l');
-                               break;
-
-                       case 'V': case 'v':
-                               vline_to(tok.last_number(), cmd == 'v');
-                               break;
-
-                       case 'H': case 'h':
-                               hline_to(tok.last_number(), cmd == 'h');
-                               break;
-
-                       case 'Q': case 'q':
-                               arg[0] = tok.last_number();
-                               for(i = 1; i < 4; i++) {
-                                       arg[i] = tok.next(cmd);
-                               }
-                               curve3(arg[0], arg[1], arg[2], arg[3], cmd == 
'q');
-                               break;
-
-                       case 'T': case 't':
-                               arg[0] = tok.last_number();
-                               arg[1] = tok.next(cmd);
-                               curve3(arg[0], arg[1], cmd == 't');
-                               break;
-
-                       case 'C': case 'c':
-                               arg[0] = tok.last_number();
-                               for(i = 1; i < 6; i++) {
-                                       arg[i] = tok.next(cmd);
-                               }
-                               curve4(arg[0], arg[1], arg[2], arg[3], arg[4], 
arg[5], cmd == 'c');
-                               break;
-
-                       case 'S': case 's':
-                               arg[0] = tok.last_number();
-                               for(i = 1; i < 4; i++) {
-                                       arg[i] = tok.next(cmd);
-                               }
-                               curve4(arg[0], arg[1], arg[2], arg[3], cmd == 
's');
-                               break;
-
-                       case 'A': case 'a': {
-                               arg[0] = tok.last_number();
-                               for(i = 1; i < 3; i++) {
-                                       arg[i] = tok.next(cmd);
-                               }
-                               bool large_arc_flag = (bool)tok.next(cmd);
-                               bool sweep_flag = (bool)tok.next(cmd);
-                               for(i = 3; i < 5; i++) {
-                                       arg[i] = tok.next(cmd);
-                               }
-                               elliptical_arc(arg[0], arg[1], arg[2],
-                                                          large_arc_flag, 
sweep_flag,
-                                                          arg[3], arg[4], cmd 
== 'a');
-                               break;
-                       }
-
-                       case 'Z': case 'z':
-                               close_subpath();
-                               break;
-
-                       default:
-                       {
-                               char buf[100];
-                               sprintf(buf, "parse_path: Invalid path command 
'%c'", cmd);
-                               throw exception(buf);
-                       }
-               }
-               lastCmd = cmd;
-       }
-}
-
 // #pragma mark -

 // GetIcon
@@ -461,22 +66,10 @@
 DocumentBuilder::GetIcon(Icon* icon, SVGImporter* importer,
                                                 const char* fallbackName)
 {
-       double xMin;
-       double yMin;
-       double xMax;
-       double yMax;
-
-       int32 pathCount = fAttributesStorage.size();
-
-       agg::conv_transform<agg::path_storage> transformedPaths(
-               fPathStorage, fTransform);
-       agg::bounding_rect(transformedPaths, *this, 0, pathCount,
-                                          &xMin, &yMin, &xMax, &yMax);
-
-       xMin = floor(xMin);
-       yMin = floor(yMin);
-       xMax = ceil(xMax);
-       yMax = ceil(yMax);
+       double xMin = 0;
+       double yMin = 0;
+       double xMax = ceil(fSource->width);
+       double yMax = ceil(fSource->height);

        BRect bounds;
        if (fViewBox.IsValid()) {
@@ -510,15 +103,11 @@
 //     else
 //             icon->SetName(fallbackName);

-       for (int32 i = 0; i < pathCount; i++) {
-
-               path_attributes& attributes = fAttributesStorage[i];
-
-               if (attributes.fill_flag)
-                       _AddShape(attributes, false, transform, icon);
-
-               if (attributes.stroke_flag)
-                       _AddShape(attributes, true, transform, icon);
+       for (NSVGshape* shape = fSource->shapes; shape != NULL; shape = 
shape->next) {
+               if (shape->fill.type != NSVG_PAINT_NONE)
+                       _AddShape(shape, false, transform, icon);
+               if (shape->stroke.type != NSVG_PAINT_NONE)
+                       _AddShape(shape, true, transform, icon);
        }

        // clean up styles and paths (remove duplicates)
@@ -543,210 +132,59 @@
        return B_OK;
 }

-// StartGradient
-void
-DocumentBuilder::StartGradient(bool radial)
-{
-       if (fCurrentGradient) {
-               fprintf(stderr, "DocumentBuilder::StartGradient() - ERROR: "
-                                               "previous gradient (%s) not 
finished!\n",
-                                               fCurrentGradient->ID());
-       }
-
-       if (radial)
-               fCurrentGradient = new SVGRadialGradient();
-       else
-               fCurrentGradient = new SVGLinearGradient();
-
-       _AddGradient(fCurrentGradient);
-}
-
-// EndGradient
-void
-DocumentBuilder::EndGradient()
-{
-       if (fCurrentGradient) {
-//             fCurrentGradient->PrintToStream();
-       } else {
-               fprintf(stderr, "DocumentBuilder::EndGradient() - "
-                               "ERROR: no gradient started!\n");
-       }
-       fCurrentGradient = NULL;
-}
-
-// #pragma mark -
-
-// _AddGradient
-void
-DocumentBuilder::_AddGradient(SVGGradient* gradient)
-{
-       if (gradient) {
-               fGradients.AddItem((void*)gradient);
-       }
-}
-
-// _GradientAt
-SVGGradient*
-DocumentBuilder::_GradientAt(int32 index) const
-{
-       return (SVGGradient*)fGradients.ItemAt(index);
-}
-
-// _FindGradient
-SVGGradient*
-DocumentBuilder::_FindGradient(const char* name) const
-{
-       for (int32 i = 0; SVGGradient* g = _GradientAt(i); i++) {
-               if (strcmp(g->ID(), name) == 0)
-                       return g;
-       }
-       return NULL;
-}
-

 // AddVertexSource
-template<class VertexSource>
 status_t
-AddPathsFromVertexSource(Icon* icon, Shape* shape,
-                                                VertexSource& source, int32 
index)
+AddPathsFromVertexSource(Icon* icon, Shape* shape, NSVGshape* svgShape)
 {
 //printf("AddPathsFromVertexSource(pathID = %ld)\n", index);

-       // start with the first path
-       VectorPath* path = new (nothrow) VectorPath();
-       if (!path || !icon->Paths()->AddPath(path)) {
-               delete path;
-               return B_NO_MEMORY;
-       }
-
-       if (!shape->Paths()->AddPath(path))
-               return B_NO_MEMORY;
-
-       source.rewind(index);
-       double x1 = 0, y1 = 0;
-       unsigned cmd = source.vertex(&x1, &y1);
-       bool keepGoing = true;
-       int32 subPath = 0;
-       while (keepGoing) {
-               if (agg::is_next_poly(cmd)) {
-//printf("next polygon\n");
-                       if (agg::is_end_poly(cmd)) {
-//printf("  end polygon\n");
-                               path->SetClosed(true);
-                               subPath++;
-                       } else {
-//printf("  not end polygon\n");
-                       }
-
-                       if (agg::is_stop(cmd)) {
-//printf("  stop = true\n");
-                               keepGoing = false;
-                       } else {
-                               if (subPath > 0) {
-//printf("  new subpath\n");
-                                       path->CleanUp();
-                                       if (path->CountPoints() == 0) {
-//printf("  path with no points!\n");
-                                               icon->Paths()->RemovePath(path);
-                                               
shape->Paths()->RemovePath(path);
-                                               path->ReleaseReference();
-                                       }
-                                       path = new (nothrow) VectorPath();
-                                       if (!path || 
!icon->Paths()->AddPath(path)) {
-                                               delete path;
-                                               return B_NO_MEMORY;
-                                       }
-                                       if (!shape->Paths()->AddPath(path))
-                                               return B_NO_MEMORY;
-                               }
-                       }
+       for (NSVGpath* svgPath = svgShape->paths; svgPath != NULL;
+               svgPath = svgPath->next) {
+               VectorPath* path = new (nothrow) VectorPath();
+               if (!path || !icon->Paths()->AddPath(path)) {
+                       delete path;
+                       return B_NO_MEMORY;
                }
-               switch (cmd) {
-                       case agg::path_cmd_move_to:
-//printf("move to (%.2f, %.2f) (subPath: %ld)\n", x1, y1, subPath);
-                               if (path->CountPoints() > 0) {
-                                       // cannot MoveTo on a path that has 
already points!
-                                       path->CleanUp();
-                                       path = new (nothrow) VectorPath();
-                                       if (!path || 
!icon->Paths()->AddPath(path)) {
-                                               delete path;
-                                               return B_NO_MEMORY;
-                                       }
-                                       if (!shape->Paths()->AddPath(path))
-                                               return B_NO_MEMORY;
-                               }
-                               if (!path->AddPoint(BPoint(x1, y1)))
-                                       return B_NO_MEMORY;
-                               path->SetInOutConnected(path->CountPoints() - 
1, false);
-                               break;

-                       case agg::path_cmd_line_to:
-//printf("line to (%.2f, %.2f) (subPath: %ld)\n", x1, y1, subPath);
-                               if (!path->AddPoint(BPoint(x1, y1)))
-                                       return B_NO_MEMORY;
-                               path->SetInOutConnected(path->CountPoints() - 
1, false);
-                               break;
+               if (!shape->Paths()->AddPath(path))
+                       return B_NO_MEMORY;

-                       case agg::path_cmd_curve3: {
-                               double x2 = 0, y2 = 0;
-                               cmd = source.vertex(&x2, &y2);
-//printf("curve3 (%.2f, %.2f)\n", x1, y1);
-//printf("        (%.2f, %.2f)\n", x2, y2);
+               path->SetClosed(svgPath->closed);

-                               // convert to curve4 for easier editing
-                               int32 start = path->CountPoints() - 1;
-                               BPoint from;
-                               path->GetPointAt(start, from);
+               int pointCount = svgPath->npts;
+               float* points = svgPath->pts;

-                               double cx2 = (1.0/3.0) * from.x + (2.0/3.0) * 
x1;
-                               double cy2 = (1.0/3.0) * from.y + (2.0/3.0) * 
y1;
-                               double cx3 = (2.0/3.0) * x1 + (1.0/3.0) * x2;
-                               double cy3 = (2.0/3.0) * y1 + (1.0/3.0) * y2;
+               // First entry in the points list is always a "move" to the path
+               // starting point
+               if (!path->AddPoint(BPoint(points[0], points[1])))
+                       return B_NO_MEMORY;
+               path->SetInOutConnected(path->CountPoints() - 1, false);

-                               path->SetPointOut(start, BPoint(cx2, cy2));
+               pointCount--;
+               points += 2;

-                               if (!path->AddPoint(BPoint(x2, y2)))
-                                       return B_NO_MEMORY;
+               while (pointCount > 0) {
+                       BPoint vector1(points[0], points[1]);
+                       BPoint vector2(points[2], points[3]);
+                       BPoint endPoint(points[4], points[5]);

-                               int32 end = path->CountPoints() - 1;
-                               path->SetInOutConnected(end, false);
-                               path->SetPointIn(end, BPoint(cx3, cy3));
-                               break;
-                       }
+                       if (!path->AddPoint(endPoint))
+                               return B_NO_MEMORY;

-                       case agg::path_cmd_curve4: {
-                               double x2 = 0, y2 = 0;
-                               double x3 = 0, y3 = 0;
-                               cmd = source.vertex(&x2, &y2);
-                               cmd = source.vertex(&x3, &y3);
+                       int32 start = path->CountPoints() - 2;
+                       int32 end = path->CountPoints() - 1;

-                               if (!path->AddPoint(BPoint(x3, y3)))
-                                       return B_NO_MEMORY;
+                       path->SetInOutConnected(end, false);
+                       path->SetPointOut(start, vector1);
+                       path->SetPointIn(end, vector2);

-                               int32 start = path->CountPoints() - 2;
-                               int32 end = path->CountPoints() - 1;
-
-//printf("curve4 [%ld] (%.2f, %.2f) -> [%ld] (%.2f, %.2f) -> (%.2f, %.2f)\n", 
start, x1, y1, end, x2, y2, x3, y3);
-
-                               path->SetInOutConnected(end, false);
-                               path->SetPointOut(start, BPoint(x1, y1));
-                               path->SetPointIn(end, BPoint(x2, y2));
-                               break;
-                       }
-                       default:
-//printf("unkown command\n");
-                               break;
+                       pointCount -= 3;
+                       points += 6;
                }
-               cmd = source.vertex(&x1, &y1);
        }
-//path->PrintToStream();
-       path->CleanUp();
-       if (path->CountPoints() == 0) {
-//printf("path with no points!\n");
-               icon->Paths()->RemovePath(path);
-               shape->Paths()->RemovePath(path);
-               path->ReleaseReference();
-       }
+
+       // FIXME handle closed vs open paths

        return B_OK;
 }
@@ -754,7 +192,7 @@

 // _AddShape
 status_t
-DocumentBuilder::_AddShape(path_attributes& attributes, bool outline,
+DocumentBuilder::_AddShape(NSVGshape* svgShape, bool outline,
                                                   const Transformable& 
transform, Icon* icon)
 {
        Shape* shape = new (nothrow) Shape(NULL);
@@ -763,20 +201,42 @@
                return B_NO_MEMORY;
        }

-       if (AddPathsFromVertexSource(icon, shape, fPathStorage, 
attributes.index) < B_OK)
+       if (AddPathsFromVertexSource(icon, shape, svgShape) < B_OK)
                printf("failed to convert from vertex source\n");

-       shape->multiply(attributes.transform);
        shape->Multiply(transform);

        StrokeTransformer* stroke = NULL;
+       NSVGpaint* paint = NULL;
        if (outline) {
                stroke = new (nothrow) StrokeTransformer(shape->VertexSource());
+               paint = &svgShape->stroke;

                if (stroke) {
-                       stroke->width(attributes.stroke_width);
-                       stroke->line_cap(attributes.line_cap);
-                       stroke->line_join(attributes.line_join);
+                       stroke->width(svgShape->strokeWidth);
+                       switch(svgShape->strokeLineCap) {
+                               case NSVG_CAP_BUTT:
+                                       stroke->line_cap(agg::butt_cap);
+                                       break;
+                               case NSVG_CAP_ROUND:
+                                       stroke->line_cap(agg::round_cap);
+                                       break;
+                               case NSVG_CAP_SQUARE:
+                                       stroke->line_cap(agg::square_cap);
+                                       break;
+                       }
+
+                       switch(svgShape->strokeLineJoin) {
+                               case NSVG_JOIN_MITER:
+                                       stroke->line_join(agg::miter_join);
+                                       break;
+                               case NSVG_JOIN_ROUND:
+                                       stroke->line_join(agg::round_join);
+                                       break;
+                               case NSVG_JOIN_BEVEL:
+                                       stroke->line_join(agg::bevel_join);
+                                       break;
+                       }
                }

                if (!shape->AddTransformer(stroke)) {
@@ -784,45 +244,61 @@
                        stroke = NULL;
                }
        } else {
-//             if (attributes.even_odd_flag)
-//                     shape->SetFillingRule(FILL_MODE_EVEN_ODD);
-//             else
-//                     shape->SetFillingRule(FILL_MODE_NON_ZERO);
+               paint = &svgShape->fill;
+#if 0 // FIXME filling rule are missing from Shape class
+               if (svgShape->fillRule == NSVG_FILLRULE_EVENODD)
+                       shape->SetFillingRule(FILL_MODE_EVEN_ODD);
+               else
+                       shape->SetFillingRule(FILL_MODE_NON_ZERO);
+#endif
        }

-
-       Gradient* gradient = NULL;
-       SVGGradient* g = NULL;
-       const char* url = outline ? attributes.stroke_url : attributes.fill_url;
-       if (url[0] != 0) {
-               g = _FindGradient(url);
-               if (g != NULL)
-                       gradient = g->GetGradient(shape->Bounds());
-       }
-
-       ObjectDeleter<Gradient> gradientDeleter(gradient);
-
+       Gradient gradient;
        rgb_color color;
+       switch(paint->type) {
+               case NSVG_PAINT_COLOR:
+                       color.red = paint->color & 0xFF;
+                       color.green = (paint->color >> 8) & 0xFF;
+                       color.blue = (paint->color >> 16) & 0xFF;
+                       color.alpha = 255;
+                       break;
+               case NSVG_PAINT_LINEAR_GRADIENT:
+                       gradient.SetType(GRADIENT_LINEAR);
+                       break;
+               case NSVG_PAINT_RADIAL_GRADIENT:
+                       gradient.SetType(GRADIENT_CIRCULAR);
+                       break;
+       }

-       BGradient::ColorStop* step;
-       if (gradient && (step = gradient->ColorAt(0))) {
-               color.red               = step->color.red;
-               color.green             = step->color.green;
-               color.blue              = step->color.blue;
-       } else {
-               if (outline) {
-                       color.red       = attributes.stroke_color.r;
-                       color.green     = attributes.stroke_color.g;
-                       color.blue      = attributes.stroke_color.b;
-                       color.alpha = (uint8)(attributes.stroke_color.a * 
attributes.opacity);
-               } else {
-                       color.red       = attributes.fill_color.r;
-                       color.green     = attributes.fill_color.g;
-                       color.blue      = attributes.fill_color.b;
-                       color.alpha = (uint8)(attributes.fill_color.a * 
attributes.opacity);
+       if (paint->type != NSVG_PAINT_COLOR) {
+               agg::trans_affine gradientTransform(
+                       paint->gradient->xform[0], paint->gradient->xform[1],
+                       paint->gradient->xform[2], paint->gradient->xform[3],
+                       paint->gradient->xform[4], paint->gradient->xform[5]
+               );
+               gradient.SetInterpolation(INTERPOLATION_LINEAR);
+               gradient.multiply(gradientTransform);
+
+               for (int i = 0; i < paint->gradient->nstops; i++) {
+                       rgb_color stopColor;
+                       stopColor.red = paint->gradient->stops[i].color & 0xFF;
+                       stopColor.green = (paint->gradient->stops[i].color >> 
8) & 0xFF;
+                       stopColor.blue = (paint->gradient->stops[i].color >> 
16) & 0xFF;
+                       stopColor.alpha = 255;
+                       gradient.AddColor(stopColor, 
paint->gradient->stops[i].offset);
+               }
+
+               BGradient::ColorStop* step = gradient.ColorAt(0);
+               if (step) {
+                       color.red               = step->color.red;
+                       color.green             = step->color.green;
+                       color.blue              = step->color.blue;
+                       color.alpha             = step->color.alpha;
                }
        }

+       color.alpha = (uint8)(color.alpha * svgShape->opacity);
+
        Style* style = new (nothrow) Style(color);
        if (!style || !icon->Styles()->AddStyle(style)) {
                delete style;
@@ -831,31 +307,24 @@

        // NOTE: quick hack to freeze all transformations (only works because
        // paths and styles are not used by multiple shapes!!)
-//     if (modifiers() & B_COMMAND_KEY) {
-               int32 pathCount = shape->Paths()->CountPaths();
-               for (int32 i = 0; i < pathCount; i++) {
-                       VectorPath* path = shape->Paths()->PathAtFast(i);
-                       path->ApplyTransform(*shape);
-               }
-               if (gradient)
-                       gradient->Multiply(*shape);
-
-               if (stroke)
-                       stroke->width(stroke->width() * shape->scale());
-
-               shape->Reset();
-//     }
-
-       if (gradient) {
-               style->SetGradient(gradient);
-               style->SetName(g->ID());
+       int32 pathCount = shape->Paths()->CountPaths();
+       for (int32 i = 0; i < pathCount; i++) {
+               VectorPath* path = shape->Paths()->PathAtFast(i);
+               path->ApplyTransform(*shape);
        }

+       gradient.Multiply(*shape);
+
+       if (stroke)
+               stroke->width(stroke->width() * shape->scale());
+
+       if (paint->type != NSVG_PAINT_COLOR)
+               style->SetGradient(&gradient);
+
+       shape->Reset();
+
        shape->SetStyle(style);

        return B_OK;
 }

-} // namespace svg
-} // namespace agg
-
diff --git a/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.h 
b/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.h
index 6874f61..55760e6 100644
--- a/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.h
+++ b/src/apps/icon-o-matic/import_export/svg/DocumentBuilder.h
@@ -6,41 +6,17 @@
  *             Stephan Aßmus <superstippi@xxxxxx>
  */

-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.2
-// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Contact: mcseem@xxxxxxxxxxxxx
-//               mcseemagg@xxxxxxxxx
-//               http://www.antigrain.com
-//----------------------------------------------------------------------------

 #ifndef DOCUMENT_BUILD_H
 #define DOCUMENT_BUILD_H

 #include <stdio.h>

-#include <List.h>
 #include <Rect.h>
 #include <String.h>

-#include <agg_array.h>
-#include <agg_color_rgba.h>
-#include <agg_conv_transform.h>
-#include <agg_conv_stroke.h>
-#include <agg_conv_contour.h>
-#include <agg_conv_curve.h>
-#include <agg_path_storage.h>
-#include <agg_rasterizer_scanline_aa.h>
-
 #include "IconBuild.h"
-#include "PathTokenizer.h"
+#include "nanosvg.h"


 class SVGImporter;
@@ -52,207 +28,33 @@

 _USING_ICON_NAMESPACE

-namespace agg {
-namespace svg {
-
-class SVGGradient;
-
-// Basic path attributes
-struct path_attributes {
-
-       unsigned                index;
-       rgba8                   fill_color;
-       rgba8                   stroke_color;
-       double                  opacity;
-       bool                    fill_flag;
-       bool                    stroke_flag;
-       bool                    even_odd_flag;
-       line_join_e             line_join;
-       line_cap_e              line_cap;
-       double                  miter_limit;
-       double                  stroke_width;
-       trans_affine    transform;
-
-       char                    stroke_url[64];
-       char                    fill_url[64];
-
-       // Empty constructor
-       path_attributes() :
-               index                   (0),
-               fill_color              (rgba(0,0,0)),
-               stroke_color    (rgba(0,0,0)),
-               opacity                 (1.0),
-               fill_flag               (true),
-               stroke_flag             (false),
-               even_odd_flag   (false),
-               line_join               (miter_join),
-               line_cap                (butt_cap),
-               miter_limit             (4.0),
-               stroke_width    (1.0),
-               transform               ()
-       {
-               stroke_url[0] = 0;
-               fill_url[0] = 0;
-       }
-
-       // Copy constructor
-       path_attributes(const path_attributes& attr) :
-               index                   (attr.index),
-               fill_color              (attr.fill_color),
-               stroke_color    (attr.stroke_color),
-               opacity                 (attr.opacity),
-               fill_flag               (attr.fill_flag),
-               stroke_flag             (attr.stroke_flag),
-               even_odd_flag   (attr.even_odd_flag),
-               line_join               (attr.line_join),
-               line_cap                (attr.line_cap),
-               miter_limit             (attr.miter_limit),
-               stroke_width    (attr.stroke_width),
-               transform               (attr.transform)
-       {
-               sprintf(stroke_url, "%s", attr.stroke_url);
-               sprintf(fill_url, "%s", attr.fill_url);
-       }
-
-       // Copy constructor with new index value
-       path_attributes(const path_attributes& attr, unsigned idx) :
-               index                   (idx),
-               fill_color              (attr.fill_color),
-               stroke_color    (attr.stroke_color),
-               fill_flag               (attr.fill_flag),
-               stroke_flag             (attr.stroke_flag),
-               even_odd_flag   (attr.even_odd_flag),
-               line_join               (attr.line_join),
-               line_cap                (attr.line_cap),
-               miter_limit             (attr.miter_limit),
-               stroke_width    (attr.stroke_width),
-               transform               (attr.transform)
-       {
-               sprintf(stroke_url, "%s", attr.stroke_url);
-               sprintf(fill_url, "%s", attr.fill_url);
-       }
-};

 class DocumentBuilder {
  public:

-       typedef pod_bvector<path_attributes>            attr_storage;
-
-                                                               
DocumentBuilder();
-
-                       void                            remove_all();
-
-       // Use these functions as follows:
-       // begin_path() when the XML tag <path> comes ("start_element" handler)
-       // parse_path() on "d=" tag attribute
-       // end_path() when parsing of the entire tag is done.
-                       void                            begin_path();
-                       void                            
parse_path(PathTokenizer& tok);
-                       void                            end_path();
-
-       // The following functions are essentially a "reflection" of
-       // the respective SVG path commands.
-                       void                            move_to(double x, 
double y, bool rel = false);  // M, m
-                       void                            line_to(double x,  
double y, bool rel = false); // L, l
-                       void                            hline_to(double x, bool 
rel = false);                   // H, h
-                       void                            vline_to(double y, bool 
rel = false);                   // V, v
-                       void                            curve3(double x1, 
double y1,                                    // Q, q
-                                                                          
double x,  double y, bool rel = false);
-                       void                            curve3(double x, double 
y, bool rel = false);   // T, t
-                       void                            curve4(double x1, 
double y1,                                    // C, c
-                                                                          
double x2, double y2,
-                                                                          
double x,  double y, bool rel = false);
-                       void                            curve4(double x2, 
double y2,                                    // S, s
-                                                                          
double x,  double y, bool rel = false);
-                       void                            elliptical_arc(double 
rx, double ry,
-                                                                               
           double angle,
-                                                                               
           bool large_arc_flag,
-                                                                               
           bool sweep_flag,
-                                                                               
           double x, double y,
-                                                                               
           bool rel = false);                           // A, a
-                       void                            close_subpath();        
                                                        // Z, z
-
-/*                     template<class VertexSource>
-                       void                            add_path(VertexSource& 
vs,
-                                                                               
 unsigned path_id = 0,
-                                                                               
 bool solid_path = true)
-                                                               {
-                                                                       
fPathStorage.add_path(vs, path_id, solid_path);
-                                                               }*/
+                                                               
DocumentBuilder(NSVGimage* image);

                        void                            SetTitle(const char* 
title);
                        void                            SetDimensions(uint32 
width, uint32 height, BRect viewBox);


-                       // Call these functions on <g> tag (start_element, 
end_element respectively)
-                       void                            push_attr();
-                       void                            pop_attr();
-
-                       // Attribute setting functions.
-                       void                            fill(const rgba8& f);
-                       void                            stroke(const rgba8& s);
-                       void                            even_odd(bool flag);
-                       void                            stroke_width(double w);
-                       void                            fill_none();
-                       void                            fill_url(const char* 
url);
-                       void                            stroke_none();
-                       void                            stroke_url(const char* 
url);
-                       void                            opacity(double op);
-                       void                            fill_opacity(double op);
-                       void                            stroke_opacity(double 
op);
-                       void                            line_join(line_join_e 
join);
-                       void                            line_cap(line_cap_e 
cap);
-                       void                            miter_limit(double ml);
-                       trans_affine&           transform();
-
-/*                     // Make all polygons CCW-oriented
-                       void                            arrange_orientations()
-                       {
-                               
fPathStorage.arrange_orientations_all_paths(path_flags_ccw);
-                       }*/
-
-                       unsigned                        operator [](unsigned 
idx)
-               {
-                   fTransform = fAttributesStorage[idx].transform;
-                   return fAttributesStorage[idx].index;
-               }
-
                        status_t                        GetIcon(Icon* icon,
                                                                                
SVGImporter* importer,
                                                                                
const char* fallbackName);

-                       void                            StartGradient(bool 
radial = false);
-                       void                            EndGradient();
-                       SVGGradient*            CurrentGradient() const
-                                                                       { 
return fCurrentGradient; }
-
  private:
-                       void                            
_AddGradient(SVGGradient* gradient);
-                       SVGGradient*            _GradientAt(int32 index) const;
-                       SVGGradient*            _FindGradient(const char* name) 
const;
-                       status_t                        
_AddShape(path_attributes& attributes,
+                       status_t                        _AddShape(NSVGshape* 
svgShape,
                                                                                
  bool outline,
                                                                                
  const Transformable& transform,
                                                                                
  Icon* icon);

-                       path_attributes&        cur_attr();
-
-                       path_storage            fPathStorage;
-                       attr_storage            fAttributesStorage;
-                       attr_storage            fAttributesStack;
-
-                       trans_affine            fTransform;
-
-                       BList                           fGradients;
-                       SVGGradient*            fCurrentGradient;

                        uint32                          fWidth;
                        uint32                          fHeight;
                        BRect                           fViewBox;
                        BString                         fTitle;
-};

-} // namespace svg
-} // namespace agg
+                       NSVGimage*                      fSource;
+};

 #endif // DOCUMENT_BUILD_H
diff --git a/src/apps/icon-o-matic/import_export/svg/PathTokenizer.cpp 
b/src/apps/icon-o-matic/import_export/svg/PathTokenizer.cpp
deleted file mode 100644
index 38999ad..0000000
--- a/src/apps/icon-o-matic/import_export/svg/PathTokenizer.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2006, Haiku. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *             Stephan Aßmus <superstippi@xxxxxx>
- */
-
-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.2
-// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Contact: mcseem@xxxxxxxxxxxxx
-//               mcseemagg@xxxxxxxxx
-//               http://www.antigrain.com
-
-#include "PathTokenizer.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-
-namespace agg {
-namespace svg {
-
-// globals
-const char PathTokenizer::sCommands[]   = "+-MmZzLlHhVvCcSsQqTtAaFfPp";
-const char PathTokenizer::sNumeric[]   = ".Ee0123456789";
-const char PathTokenizer::sSeparators[] = " ,\t\n\r";
-
-// constructor
-PathTokenizer::PathTokenizer()
-       : fPath(0),
-         fLastNumber(0.0),
-         fLastCommand(0)
-{
-       init_char_mask(fCommandsMask,   sCommands);
-       init_char_mask(fNumericMask,    sNumeric);
-       init_char_mask(fSeparatorsMask, sSeparators);
-}
-
-// set_path_str
-void
-PathTokenizer::set_path_str(const char* str)
-{
-       fPath = str;
-       fLastCommand = 0;
-       fLastNumber = 0.0;
-}
-
-// next
-bool
-PathTokenizer::next()
-{
-       if(fPath == 0) return false;
-
-       // Skip all white spaces and other garbage
-       while (*fPath && !is_command(*fPath) && !isNumeric(*fPath))  {
-               if (!is_separator(*fPath)) {
-                       char buf[100];
-                       sprintf(buf, "PathTokenizer::next : Invalid Character 
%c", *fPath);
-                       throw exception(buf);
-               }
-               fPath++;
-       }
-
-       if (*fPath == 0) return false;
-
-       if (is_command(*fPath)) {
-               // Check if the command is a numeric sign character
-               if(*fPath == '-' || *fPath == '+')
-               {
-                       return parse_number();
-               }
-               fLastCommand = *fPath++;
-               while(*fPath && is_separator(*fPath)) fPath++;
-               if(*fPath == 0) return true;
-       }
-       return parse_number();
-}
-
-// next
-double
-PathTokenizer::next(char cmd)
-{
-       if (!next()) throw exception("parse_path: Unexpected end of path");
-       if (last_command() != cmd) {
-               char buf[100];
-               sprintf(buf, "parse_path: Command %c: bad or missing 
parameters", cmd);
-               throw exception(buf);
-       }
-       return last_number();
-}
-
-// init_char_mask
-void
-PathTokenizer::init_char_mask(char* mask, const char* char_set)
-{
-       memset(mask, 0, 256/8);
-       while (*char_set) {
-               unsigned c = unsigned(*char_set++) & 0xFF;
-               mask[c >> 3] |= 1 << (c & 7);
-       }
-}
-
-// contains
-inline bool
-PathTokenizer::contains(const char* mask, unsigned c) const
-{
-       return (mask[(c >> 3) & (256 / 8 - 1)] & (1 << (c & 7))) != 0;
-}
-
-// is_command
-inline bool
-PathTokenizer::is_command(unsigned c) const
-{
-       return contains(fCommandsMask, c);
-}
-
-// isNumeric
-inline bool
-PathTokenizer::isNumeric(unsigned c) const
-{
-       return contains(fNumericMask, c);
-}
-
-// is_separator
-inline bool
-PathTokenizer::is_separator(unsigned c) const
-{
-       return contains(fSeparatorsMask, c);
-}
-
-// parse_number
-bool
-PathTokenizer::parse_number()
-{
-       char* end;
-       fLastNumber = strtod(fPath, &end);
-       fPath = end;
-       return true;
-}
-
-
-} //namespace svg
-} //namespace agg
-
-
-
-
diff --git a/src/apps/icon-o-matic/import_export/svg/PathTokenizer.h 
b/src/apps/icon-o-matic/import_export/svg/PathTokenizer.h
deleted file mode 100644
index 4cde3b8..0000000
--- a/src/apps/icon-o-matic/import_export/svg/PathTokenizer.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2006, Haiku. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *             Stephan Aßmus <superstippi@xxxxxx>
- */
-
-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.2
-// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Contact: mcseem@xxxxxxxxxxxxx
-//               mcseemagg@xxxxxxxxx
-//               http://www.antigrain.com
-//----------------------------------------------------------------------------
-
-#ifndef PATH_TOKENIZER_H
-#define PATH_TOKENIZER_H
-
-#include "SVGException.h"
-
-namespace agg {
-namespace svg {
-       // SVG path tokenizer.
-       // Example:
-       //
-       // agg::svg::PathTokenizer tok;
-       //
-       // tok.set_str("M-122.304 84.285L-122.304 84.285 122.203 86.179 ");
-       // while(tok.next())
-       // {
-       //       printf("command='%c' number=%f\n",
-       //                       tok.last_command(),
-       //                       tok.last_number());
-       // }
-       //
-       // The tokenizer does all the routine job of parsing the SVG paths.
-       // It doesn't recognize any graphical primitives, it even doesn't know
-       // anything about pairs of coordinates (X,Y). The purpose of this class
-       // is to tokenize the numeric values and commands. SVG paths can
-       // have single numeric values for Horizontal or Vertical line_to 
commands
-       // as well as more than two coordinates (4 or 6) for Bezier curves
-       // depending on the semantics of the command.
-       // The behaviour is as follows:
-       //
-       // Each call to next() returns true if there's new command or new 
numeric
-       // value or false when the path ends. How to interpret the result
-       // depends on the sematics of the command. For example, command "C"
-       // (cubic Bezier curve) implies 6 floating point numbers preceded by 
this
-       // command. If the command assumes no arguments (like z or Z) the
-       // the last_number() values won't change, that is, last_number() always
-       // returns the last recognized numeric value, so does last_command().
-
-class PathTokenizer {
- public:
-                                                               PathTokenizer();
-
-                       void                            set_path_str(const 
char* str);
-                       bool                            next();
-
-                       double                          next(char cmd);
-
-                       char                            last_command() const
-                                                                       { 
return fLastCommand; }
-                       double                          last_number() const
-                                                                       { 
return fLastNumber; }
-
-
- private:
-       static  void                            init_char_mask(char* mask,
-                                                                               
           const char* char_set);
-
-       inline  bool                            contains(const char* mask, 
unsigned c) const;
-       inline  bool                            is_command(unsigned c) const;
-       inline  bool                            isNumeric(unsigned c) const;
-       inline  bool                            is_separator(unsigned c) const;
-
-                       bool                            parse_number();
-
-                       char                            fSeparatorsMask[256 / 
8];
-                       char                            fCommandsMask[256 / 8];
-                       char                            fNumericMask[256 / 8];
-
-                       const char*                     fPath;
-                       double                          fLastNumber;
-                       char                            fLastCommand;
-
-       static  const char                      sCommands[];
-       static  const char                      sNumeric[];
-       static  const char                      sSeparators[];
-};
-
-
-
-} //namespace svg
-} //namespace agg
-
-
-#endif // PATH_TOKENIZER_H
diff --git a/src/apps/icon-o-matic/import_export/svg/SVGGradients.cpp 
b/src/apps/icon-o-matic/import_export/svg/SVGGradients.cpp
deleted file mode 100644
index 43a9509..0000000
--- a/src/apps/icon-o-matic/import_export/svg/SVGGradients.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2006, Haiku. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *             Stephan Aßmus <superstippi@xxxxxx>
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "GradientTransformable.h"
-
-#include "SVGGradients.h"
-
-namespace agg {
-namespace svg {
-
-// constructor
-SVGGradient::SVGGradient()
-       : BMessage(),
-         fGradient(NULL),
-         fID(""),
-         fGradientUnits(UNSPECIFIED)
-{
-}
-
-// destructor
-SVGGradient::~SVGGradient()
-{
-}
-
-// SetID
-void
-SVGGradient::SetID(const char* id)
-{
-       fID = id;
-}
-
-// ID
-const char*
-SVGGradient::ID() const
-{
-       return fID.String();
-}
-
-// AddStop
-void
-SVGGradient::AddStop(float offset, rgba8 color)
-{
-       if (!fGradient)
-               fGradient = MakeGradient();
-
-       rgb_color c = { color.r, color.g, color.b, color.a };
-       fGradient->AddColor(c, offset);
-}
-
-// SetTransformation
-void
-SVGGradient::SetTransformation(const trans_affine& transform)
-{
-//printf("SVGGradient::SetTransformation()\n");
-       if (!fGradient)
-               fGradient = MakeGradient();
-
-       fGradient->multiply(transform);
-}
-
-// GetGradient
-Gradient*
-SVGGradient::GetGradient(BRect objectBounds)
-{
-       if (fGradient) {
-               Gradient* gradient = new Gradient(*fGradient);
-
-               IdentifyGradientUnits();
-               if (fGradientUnits == OBJECT_BOUNDING_BOX) {
-                       gradient->FitToBounds(objectBounds);
-               }
-
-               return gradient;
-       }
-       return NULL;
-}
-
-// IdentifyGradientUnits
-void
-SVGGradient::IdentifyGradientUnits()
-{
-       if (fGradientUnits == UNSPECIFIED) {
-               const char* units;
-               if (FindString("gradientUnits", &units) >= B_OK) {
-                       if (strcmp(units, "objectBoundingBox") == 0)
-                               fGradientUnits = OBJECT_BOUNDING_BOX;
-               }
-       }
-}
-
-// constructor
-SVGLinearGradient::SVGLinearGradient()
-       : SVGGradient()
-{
-}
-
-// destructor
-SVGLinearGradient::~SVGLinearGradient()
-{
-}
-
-// MakeGradient
-Gradient*
-SVGLinearGradient::MakeGradient() const
-{
-//printf("SVGLinearGradient::MakeGradient()\n");
-//PrintToStream();
-
-       Gradient* gradient = new Gradient(true);
-       gradient->SetType(GRADIENT_LINEAR);
-       gradient->SetInterpolation(INTERPOLATION_LINEAR);
-       // setup the gradient transform
-       BPoint start(-64.0, -64.0);
-       BPoint end(64.0, -64.0);
-       BString coordinate;
-       if (FindString("x1", &coordinate) >= B_OK)
-               start.x = atof(coordinate.String());
-       if (FindString("y1", &coordinate) >= B_OK)
-               start.y = atof(coordinate.String());
-       if (FindString("x2", &coordinate) >= B_OK)
-               end.x = atof(coordinate.String());
-       if (FindString("y2", &coordinate) >= B_OK)
-               end.y = atof(coordinate.String());
-
-       // the transformed parallelogram
-       double parl[6];
-       parl[0] = start.x;
-       parl[1] = start.y;
-       parl[2] = end.x;
-       parl[3] = end.y;
-       parl[4] = end.x - (end.y - start.y);
-       parl[5] = end.y + (end.x - start.x);
-
-       trans_affine transform(-64.0, -64.0, 64.0, 64.0, parl);
-       gradient->multiply(transform);
-
-       return gradient;
-}
-
-// constructor
-SVGRadialGradient::SVGRadialGradient()
-       : SVGGradient()
-{
-}
-
-// destructor
-SVGRadialGradient::~SVGRadialGradient()
-{
-}
-
-// MakeGradient
-Gradient*
-SVGRadialGradient::MakeGradient() const
-{
-//printf("SVGRadialGradient::MakeGradient()\n");
-       // TODO: handle userSpaceOnUse/objectBoundingBox
-       Gradient* gradient = new Gradient(true);
-       gradient->SetType(GRADIENT_CIRCULAR);
-       gradient->SetInterpolation(INTERPOLATION_LINEAR);
-
-       double cx = 0.0;
-       double cy = 0.0;
-       double r = 100.0;
-
-       BString value;
-       if (FindString("cx", &value) >= B_OK)
-               cx = atof(value.String());
-       if (FindString("cy", &value) >= B_OK)
-               cy = atof(value.String());
-       if (FindString("r", &value) >= B_OK)
-               r = atof(value.String());
-
-       // the transformed parallelogram
-       double parl[6];
-       parl[0] = cx - r;
-       parl[1] = cy - r;
-       parl[2] = cx + r;
-       parl[3] = cy - r;
-       parl[4] = cx + r;
-       parl[5] = cy + r;
-
-       trans_affine transform(-64.0, -64.0, 64.0, 64.0, parl);
-       gradient->multiply(transform);
-
-       return gradient;
-}
-
-} // namespace svg
-} // namespace agg
-
diff --git a/src/apps/icon-o-matic/import_export/svg/SVGGradients.h 
b/src/apps/icon-o-matic/import_export/svg/SVGGradients.h
deleted file mode 100644
index c510ecb..0000000
--- a/src/apps/icon-o-matic/import_export/svg/SVGGradients.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2006-2007, Haiku. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *             Stephan Aßmus <superstippi@xxxxxx>
- */
-#ifndef SVG_GRADIENTS_H
-#define SVG_GRADIENTS_H
-
-
-#include <agg_color_rgba.h>
-#include <agg_trans_affine.h>
-
-#include <Message.h>
-#include <String.h>
-
-#include "IconBuild.h"
-
-
-_BEGIN_ICON_NAMESPACE
-       class Gradient;
-_END_ICON_NAMESPACE
-
-namespace agg {
-namespace svg {
-
-class SVGGradient : public BMessage {
- public:
-                                                       SVGGradient();
-       virtual                                 ~SVGGradient();
-
-                       void                    SetID(const char* id);
-                       const char*             ID() const;
-
-       virtual void                    AddStop(float offset, rgba8 color);
-                       void                    SetTransformation(const 
trans_affine& transform);
-
-                       Gradient*               GetGradient(BRect objectBounds);
-
- protected:
-       virtual Gradient*               MakeGradient() const = 0;
-                       void                    IdentifyGradientUnits();
-
- private:
-
-       enum {
-               UNSPECIFIED = 0,
-               USER_SPACE_ON_USE,
-               OBJECT_BOUNDING_BOX,
-       };
-
-                       Gradient*               fGradient;
-                       BString                 fID;
-                       uint32                  fGradientUnits;
-};
-
-class SVGLinearGradient : public SVGGradient {
- public:
-                                                       SVGLinearGradient();
-       virtual                                 ~SVGLinearGradient();
-
- protected:
-       virtual Gradient*               MakeGradient() const;
-
-};
-
-class SVGRadialGradient : public SVGGradient {
- public:
-                                                       SVGRadialGradient();
-       virtual                                 ~SVGRadialGradient();
-
- protected:
-       virtual Gradient*               MakeGradient() const;
-
-};
-
-} // namespace svg
-} // namespace agg
-
-#endif // SVG_GRADIENTS_H
diff --git a/src/apps/icon-o-matic/import_export/svg/SVGImporter.cpp 
b/src/apps/icon-o-matic/import_export/svg/SVGImporter.cpp
index 280ac80..534b36c 100644
--- a/src/apps/icon-o-matic/import_export/svg/SVGImporter.cpp
+++ b/src/apps/icon-o-matic/import_export/svg/SVGImporter.cpp
@@ -18,7 +18,7 @@
 #include <Path.h>

 #include "DocumentBuilder.h"
-#include "SVGParser.h"
+#include "nanosvg.h"


 #undef B_TRANSLATION_CONTEXT
@@ -69,23 +69,22 @@
                return B_ERROR;
        }

-       try {
-               agg::svg::DocumentBuilder builder;
-               agg::svg::Parser parser(builder);
-               parser.parse(path.Path());
-               ret = builder.GetIcon(icon, this, ref->name);
-       } catch(agg::svg::exception& e) {
+       NSVGimage* svg = nsvgParseFromFile(path.Path(), "px", 96);
+       if (svg == NULL) {
                char error[1024];
                sprintf(error, B_TRANSLATE("Failed to open the file '%s' as "
-                                          "an SVG document.\n\n"
-                                          "Error: %s"), ref->name, e.msg());
+                       "an SVG document.\n\n"), ref->name);
                BAlert* alert = new BAlert(B_TRANSLATE("load error"),
-                                                                  error, 
B_TRANSLATE("OK"), NULL, NULL,
-                                                                  
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
+                       error, B_TRANSLATE("OK"), NULL, NULL,
+                       B_WIDTH_AS_USUAL, B_WARNING_ALERT);
                alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
                alert->Go(NULL);
-               ret = B_ERROR;
+               return B_ERROR;
        }

+       DocumentBuilder builder(svg);
+       ret = builder.GetIcon(icon, this, ref->name);
+       nsvgDelete(svg);
+
        return ret;
 }
diff --git a/src/apps/icon-o-matic/import_export/svg/SVGParser.cpp 
b/src/apps/icon-o-matic/import_export/svg/SVGParser.cpp
deleted file mode 100644
index fcd182d..0000000
--- a/src/apps/icon-o-matic/import_export/svg/SVGParser.cpp
+++ /dev/null
@@ -1,1152 +0,0 @@
-/*
- * Copyright 2006, Haiku. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *             Stephan Aßmus <superstippi@xxxxxx>
- */
-
-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.2
-// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Contact: mcseem@xxxxxxxxxxxxx
-//               mcseemagg@xxxxxxxxx
-//               http://www.antigrain.com
-//----------------------------------------------------------------------------
-
-#include "SVGParser.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-#include <expat.h>
-
-#include "SVGGradients.h"
-
-namespace agg {
-namespace svg {
-
-struct named_color
-{
-       char  name[22];
-       int8u r, g, b, a;
-};
-
-named_color colors[] =
-{
-       { "aliceblue",240,248,255, 255 },
-       { "antiquewhite",250,235,215, 255 },
-       { "aqua",0,255,255, 255 },
-       { "aquamarine",127,255,212, 255 },
-       { "azure",240,255,255, 255 },
-       { "beige",245,245,220, 255 },
-       { "bisque",255,228,196, 255 },
-       { "black",0,0,0, 255 },
-       { "blanchedalmond",255,235,205, 255 },
-       { "blue",0,0,255, 255 },
-       { "blueviolet",138,43,226, 255 },
-       { "brown",165,42,42, 255 },
-       { "burlywood",222,184,135, 255 },
-       { "cadetblue",95,158,160, 255 },
-       { "chartreuse",127,255,0, 255 },
-       { "chocolate",210,105,30, 255 },
-       { "coral",255,127,80, 255 },
-       { "cornflowerblue",100,149,237, 255 },
-       { "cornsilk",255,248,220, 255 },
-       { "crimson",220,20,60, 255 },
-       { "cyan",0,255,255, 255 },
-       { "darkblue",0,0,139, 255 },
-       { "darkcyan",0,139,139, 255 },
-       { "darkgoldenrod",184,134,11, 255 },
-       { "darkgray",169,169,169, 255 },
-       { "darkgreen",0,100,0, 255 },
-       { "darkgrey",169,169,169, 255 },
-       { "darkkhaki",189,183,107, 255 },
-       { "darkmagenta",139,0,139, 255 },
-       { "darkolivegreen",85,107,47, 255 },
-       { "darkorange",255,140,0, 255 },
-       { "darkorchid",153,50,204, 255 },
-       { "darkred",139,0,0, 255 },
-       { "darksalmon",233,150,122, 255 },
-       { "darkseagreen",143,188,143, 255 },
-       { "darkslateblue",72,61,139, 255 },
-       { "darkslategray",47,79,79, 255 },
-       { "darkslategrey",47,79,79, 255 },
-       { "darkturquoise",0,206,209, 255 },
-       { "darkviolet",148,0,211, 255 },
-       { "deeppink",255,20,147, 255 },
-       { "deepskyblue",0,191,255, 255 },
-       { "dimgray",105,105,105, 255 },
-       { "dimgrey",105,105,105, 255 },
-       { "dodgerblue",30,144,255, 255 },
-       { "firebrick",178,34,34, 255 },
-       { "floralwhite",255,250,240, 255 },
-       { "forestgreen",34,139,34, 255 },
-       { "fuchsia",255,0,255, 255 },
-       { "gainsboro",220,220,220, 255 },
-       { "ghostwhite",248,248,255, 255 },
-       { "gold",255,215,0, 255 },
-       { "goldenrod",218,165,32, 255 },
-       { "gray",128,128,128, 255 },
-       { "green",0,128,0, 255 },
-       { "greenyellow",173,255,47, 255 },
-       { "grey",128,128,128, 255 },
-       { "honeydew",240,255,240, 255 },
-       { "hotpink",255,105,180, 255 },
-       { "indianred",205,92,92, 255 },
-       { "indigo",75,0,130, 255 },
-       { "ivory",255,255,240, 255 },
-       { "khaki",240,230,140, 255 },
-       { "lavender",230,230,250, 255 },
-       { "lavenderblush",255,240,245, 255 },
-       { "lawngreen",124,252,0, 255 },
-       { "lemonchiffon",255,250,205, 255 },
-       { "lightblue",173,216,230, 255 },
-       { "lightcoral",240,128,128, 255 },
-       { "lightcyan",224,255,255, 255 },
-       { "lightgoldenrodyellow",250,250,210, 255 },
-       { "lightgray",211,211,211, 255 },
-       { "lightgreen",144,238,144, 255 },
-       { "lightgrey",211,211,211, 255 },
-       { "lightpink",255,182,193, 255 },
-       { "lightsalmon",255,160,122, 255 },
-       { "lightseagreen",32,178,170, 255 },
-       { "lightskyblue",135,206,250, 255 },
-       { "lightslategray",119,136,153, 255 },
-       { "lightslategrey",119,136,153, 255 },
-       { "lightsteelblue",176,196,222, 255 },
-       { "lightyellow",255,255,224, 255 },
-       { "lime",0,255,0, 255 },
-       { "limegreen",50,205,50, 255 },
-       { "linen",250,240,230, 255 },
-       { "magenta",255,0,255, 255 },
-       { "maroon",128,0,0, 255 },
-       { "mediumaquamarine",102,205,170, 255 },
-       { "mediumblue",0,0,205, 255 },
-       { "mediumorchid",186,85,211, 255 },
-       { "mediumpurple",147,112,219, 255 },
-       { "mediumseagreen",60,179,113, 255 },
-       { "mediumslateblue",123,104,238, 255 },
-       { "mediumspringgreen",0,250,154, 255 },
-       { "mediumturquoise",72,209,204, 255 },
-       { "mediumvioletred",199,21,133, 255 },
-       { "midnightblue",25,25,112, 255 },
-       { "mintcream",245,255,250, 255 },
-       { "mistyrose",255,228,225, 255 },
-       { "moccasin",255,228,181, 255 },
-       { "navajowhite",255,222,173, 255 },
-       { "navy",0,0,128, 255 },
-       { "oldlace",253,245,230, 255 },
-       { "olive",128,128,0, 255 },
-       { "olivedrab",107,142,35, 255 },
-       { "orange",255,165,0, 255 },
-       { "orangered",255,69,0, 255 },
-       { "orchid",218,112,214, 255 },
-       { "palegoldenrod",238,232,170, 255 },
-       { "palegreen",152,251,152, 255 },
-       { "paleturquoise",175,238,238, 255 },
-       { "palevioletred",219,112,147, 255 },
-       { "papayawhip",255,239,213, 255 },
-       { "peachpuff",255,218,185, 255 },
-       { "peru",205,133,63, 255 },
-       { "pink",255,192,203, 255 },
-       { "plum",221,160,221, 255 },
-       { "powderblue",176,224,230, 255 },
-       { "purple",128,0,128, 255 },
-       { "red",255,0,0, 255 },
-       { "rosybrown",188,143,143, 255 },
-       { "royalblue",65,105,225, 255 },
-       { "saddlebrown",139,69,19, 255 },
-       { "salmon",250,128,114, 255 },
-       { "sandybrown",244,164,96, 255 },
-       { "seagreen",46,139,87, 255 },
-       { "seashell",255,245,238, 255 },
-       { "sienna",160,82,45, 255 },
-       { "silver",192,192,192, 255 },
-       { "skyblue",135,206,235, 255 },
-       { "slateblue",106,90,205, 255 },
-       { "slategray",112,128,144, 255 },
-       { "slategrey",112,128,144, 255 },
-       { "snow",255,250,250, 255 },
-       { "springgreen",0,255,127, 255 },
-       { "steelblue",70,130,180, 255 },
-       { "tan",210,180,140, 255 },
-       { "teal",0,128,128, 255 },
-       { "thistle",216,191,216, 255 },
-       { "tomato",255,99,71, 255 },
-       { "turquoise",64,224,208, 255 },
-       { "violet",238,130,238, 255 },
-       { "wheat",245,222,179, 255 },
-       { "white",255,255,255, 255 },
-       { "whitesmoke",245,245,245, 255 },
-       { "yellow",255,255,0, 255 },
-       { "yellowgreen",154,205,50, 255 },
-       { "zzzzzzzzzzz",0,0,0, 0 }
-};
-
-
-
-// cmp_color
-int
-cmp_color(const void* p1, const void* p2)
-{
-       return strcmp(((named_color*)p1)->name, ((named_color*)p2)->name);
-}
-
-// parse_color
-rgba8
-parse_color(const char* str)
-{
-       while(*str == ' ') ++str;
-       if (*str == '#') {
-               str++;
-               int32 length = strlen(str);
-               unsigned c = 0;
-               if (length == 3) {
-                       // if there are only 3 byte, than it means that we
-                       // need to expand the color (#f60 -> #ff6600)
-                       // TODO: There must be an easier way...
-                       char expanded[7];
-                       expanded[0] = *str;
-                       expanded[1] = *str++;
-                       expanded[2] = *str;
-                       expanded[3] = *str++;
-                       expanded[4] = *str;
-                       expanded[5] = *str++;
-                       expanded[6] = 0;
-                       sscanf(expanded, "%x", &c);
-               } else {
-                       sscanf(str, "%x", &c);
-               }
-               return rgb8_packed(c);
-       } else {
-               named_color c;
-               unsigned len = strlen(str);
-               if(len > sizeof(c.name) - 1)
-               {
-                       throw exception("parse_color: Invalid color name '%s'", 
str);
-               }
-               strcpy(c.name, str);
-               const void* p = bsearch(&c,
-                                                               colors,
-                                                               sizeof(colors) 
/ sizeof(colors[0]), 
-                                                               
sizeof(colors[0]),
-                                                               cmp_color);
-               if(p == 0)
-               {
-                       throw exception("parse_color: Invalid color name '%s'", 
str);
-               }
-               const named_color* pc = (const named_color*)p;
-               return rgba8(pc->r, pc->g, pc->b, pc->a);
-       }
-}
-
-// parse_double
-double
-parse_double(const char* str)
-{
-       while(*str == ' ') ++str;
-       double value = atof(str);
-       // handle percent
-       int32 length = strlen(str);
-       if (str[length - 1] == '%')
-               value /= 100.0;
-       return value;
-}
-
-// parse_url
-char*
-parse_url(const char* str)
-{
-       const char* begin = str;
-       while (*begin != '#')
-               begin++;
-
-       begin++;
-       const char* end = begin;
-       while (*end != ')')
-               end++;
-
-       end--;
-
-       int32 length = end - begin + 2;
-       char* result = new char[length];
-       memcpy(result, begin, length - 1);
-       result[length - 1] = 0;
-
-       return result;
-}
-
-
-// #pragma mark -
-
-// constructor
-Parser::Parser(DocumentBuilder& builder)
-       : fBuilder(builder),
-         fPathTokenizer(),
-         fBuffer(new char[buf_size]),
-         fTitle(new char[256]),
-         fTitleLength(0),
-
-         fTitleFlag(false),
-         fPathFlag(false),
-
-         fAttrName(new char[128]),
-         fAttrValue(new char[1024]),
-         fAttrNameLength(127),
-         fAttrValueLength(1023),
-
-         fTagsIgnored(false)
-{
-       fTitle[0] = 0;
-}
-
-// destructor
-Parser::~Parser()
-{
-       delete[] fAttrValue;
-       delete[] fAttrName;
-       delete[] fBuffer;
-       delete[] fTitle;
-}
-
-// parse
-void
-Parser::parse(const char* pathToFile)
-{
-       char msg[1024];
-       XML_Parser p = XML_ParserCreate(NULL);
-       if (p == 0) {
-               throw exception("Couldn't allocate memory for Parser");
-       }
-
-       XML_SetUserData(p, this);
-       XML_SetElementHandler(p, start_element, end_element);
-       XML_SetCharacterDataHandler(p, content);
-
-       FILE* fd = fopen(pathToFile, "r");
-       if (fd == 0) {
-               sprintf(msg, "Couldn't open file %s", pathToFile);
-               XML_ParserFree(p);
-               throw exception(msg);
-       }
-
-       bool done = false;
-       do {
-               size_t len = fread(fBuffer, 1, buf_size, fd);
-               done = len < buf_size;
-               if (!XML_Parse(p, fBuffer, len, done)) {
-                       sprintf(msg, "%s at line %ld\n",
-                                       XML_ErrorString(XML_GetErrorCode(p)),
-                                       XML_GetCurrentLineNumber(p));
-                       fclose(fd);
-                       XML_ParserFree(p);
-                       throw exception(msg);
-               }
-       } while (!done);
-
-       fclose(fd);
-       XML_ParserFree(p);
-
-       char* ts = fTitle;
-       while (*ts) {
-               if (*ts < ' ') *ts = ' ';
-               ++ts;
-       }
-}
-
-// start_element
-void
-Parser::start_element(void* data, const char* el, const char** attr)
-{
-// printf("Parser::start_element(%s)\n", el);
-       Parser& self = *(Parser*)data;
-
-       if (strcmp(el, "svg") == 0)
-       {
-               self.parse_svg(attr);
-       }
-       else
-       if (strcmp(el, "title") == 0)
-       {
-               self.fTitleFlag = true;
-       }
-       else
-       if (strcmp(el, "g") == 0)
-       {
-               self.fBuilder.push_attr();
-               self.parse_attr(attr);
-       }
-       else
-       if (strcmp(el, "path") == 0)
-       {
-               if (self.fPathFlag) {
-                       throw exception("start_element: Nested path");
-               }
-               self.fBuilder.begin_path();
-               self.parse_path(attr);
-               self.fBuilder.end_path();
-               self.fPathFlag = true;
-       }
-       else
-       if (strcmp(el, "circle") == 0)
-       {
-               self.parse_circle(attr);
-       }
-       else
-       if (strcmp(el, "ellipse") == 0)
-       {
-               self.parse_ellipse(attr);
-       }
-       else
-       if (strcmp(el, "rect") == 0)
-       {
-               self.parse_rect(attr);
-       }
-       else
-       if (strcmp(el, "line") == 0)
-       {
-               self.parse_line(attr);
-       }
-       else
-       if (strcmp(el, "polyline") == 0)
-       {
-               self.parse_poly(attr, false);
-       }
-       else
-       if (strcmp(el, "polygon") == 0)
-       {
-               self.parse_poly(attr, true);
-       }
-       else
-       if (strcmp(el, "linearGradient") == 0 || strcmp(el, "radialGradient") 
== 0)
-       {
-               self.parse_gradient(attr, strcmp(el, "radialGradient") == 0);
-       }
-       else
-       if (strcmp(el, "stop") == 0)
-       {
-               self.parse_gradient_stop(attr);
-       }
-       //else
-       //if(strcmp(el, "<OTHER_ELEMENTS>") == 0)
-       //{
-       //}
-       // . . .
-       else
-       {
-               fprintf(stderr, "SVGParser igoring tag: \"%s\"\n", el);
-               self.fTagsIgnored = true;
-       }
-}
-
-// end_element
-void
-Parser::end_element(void* data, const char* el)
-{
-       Parser& self = *(Parser*)data;
-
-       if (strcmp(el, "title") == 0)
-       {
-               self.fTitleFlag = false;
-               self.fBuilder.SetTitle(self.fTitle);
-       }
-       else
-       if (strcmp(el, "g") == 0)
-       {
-               self.fBuilder.pop_attr();
-       }
-       else
-       if (strcmp(el, "path") == 0)
-       {
-               self.fPathFlag = false;
-       }
-       else
-       if (strcmp(el, "linearGradient") == 0 || strcmp(el, "radialGradient") 
== 0)
-       {
-               self.fBuilder.EndGradient();
-       }
-       //else
-       //if(strcmp(el, "<OTHER_ELEMENTS>") == 0)
-       //{
-       //}
-       // . . .
-}
-
-// content
-void
-Parser::content(void* data, const char* s, int len)
-{
-       Parser& self = *(Parser*)data;
-
-       // fTitleFlag signals that the <title> tag is being parsed now.
-       // The following code concatenates the pieces of content of the <title> 
tag.
-       if(self.fTitleFlag)
-       {
-               if(len + self.fTitleLength > 255) len = 255 - self.fTitleLength;
-               if(len > 0)
-               {
-                       memcpy(self.fTitle + self.fTitleLength, s, len);
-                       self.fTitleLength += len;
-                       self.fTitle[self.fTitleLength] = 0;
-               }
-       }
-}
-
-// parse_svg
-void Parser::parse_svg(const char** attr)
-{
-       double width = 0.0;
-       double height = 0.0;
-       BRect viewBox(0.0, 0.0, -1.0, -1.0);
-
-       for (int i = 0; attr[i]; i += 2) {
-               if (strcmp(attr[i], "width") == 0)
-               {
-                       width = parse_double(attr[i + 1]);
-               }
-               else
-               if (strcmp(attr[i], "height") == 0)
-               {
-                       height = parse_double(attr[i + 1]);
-               }
-               else
-               if (strcmp(attr[i], "viewBox") == 0)
-               {
-                       fPathTokenizer.set_path_str(attr[i + 1]);
-                       if(!fPathTokenizer.next())
-                       {
-                               throw exception("parse_svg (viewBox): Too few 
coordinates");
-                       }
-                       viewBox.left = fPathTokenizer.last_number();
-                       if(!fPathTokenizer.next())
-                       {
-                               throw exception("parse_svg (viewBox): Too few 
coordinates");
-                       }
-                       viewBox.top = fPathTokenizer.last_number();
-                       if(!fPathTokenizer.next())
-                       {
-                               throw exception("parse_svg (viewBox): Too few 
coordinates");
-                       }
-                       viewBox.right = fPathTokenizer.last_number();
-                       if(!fPathTokenizer.next())
-                       {
-                               throw exception("parse_svg (viewBox): Too few 
coordinates");
-                       }
-                       viewBox.bottom = fPathTokenizer.last_number();
-               }
-       }
-       if (width >= 0.0 && height >= 0.0) {
-               fBuilder.SetDimensions((uint32)ceil(width), 
(uint32)ceil(height), viewBox);
-       } else {
-               throw exception("parse_svg: Invalid width or height\n");
-       }
-}
-
-// parse_attr
-void Parser::parse_attr(const char** attr)
-{
-       for (int i = 0; attr[i]; i += 2) {
-               if (strcmp(attr[i], "style") == 0) {
-                       parse_style(attr[i + 1]);
-               } else {
-                       parse_attr(attr[i], attr[i + 1]);
-               }
-       }
-}
-
-// parse_path
-void Parser::parse_path(const char** attr)
-{
-       int i;
-
-       for(i = 0; attr[i]; i += 2)
-       {
-               // The <path> tag can consist of the path itself ("d=")
-               // as well as of other parameters like "style=", "transform=", 
etc.
-               // In the last case we simply rely on the function of parsing
-               // attributes (see 'else' branch).
-               if(strcmp(attr[i], "d") == 0)
-               {
-                       fPathTokenizer.set_path_str(attr[i + 1]);
-                       fBuilder.parse_path(fPathTokenizer);
-               }
-               else
-               {
-                       // Create a temporary single pair "name-value" in order
-                       // to avoid multiple calls for the same attribute.
-                       const char* tmp[4];
-                       tmp[0] = attr[i];
-                       tmp[1] = attr[i + 1];
-                       tmp[2] = 0;
-                       tmp[3] = 0;
-                       parse_attr(tmp);
-               }
-       }
-}
-
-// parse_attr
-bool
-Parser::parse_attr(const char* name, const char* value)
-{
-       if(strcmp(name, "style") == 0) {
-               parse_style(value);
-       } else
-       if(strcmp(name, "opacity") == 0) {
-               fBuilder.opacity(parse_double(value));
-       } else
-       if(strcmp(name, "fill") == 0) {
-               if(strcmp(value, "none") == 0) {
-                       fBuilder.fill_none();
-               } else if (strncmp(value, "url", 3) == 0) {
-                       char* url = parse_url(value);
-                       fBuilder.fill_url(url);
-                       delete[] url;
-               } else {
-                       fBuilder.fill(parse_color(value));
-               }
-       } else
-       if(strcmp(name, "fill-opacity") == 0) {
-               fBuilder.fill_opacity(parse_double(value));
-       } else
-       if(strcmp(name, "fill-rule") == 0) {
-               fBuilder.even_odd(strcmp(value, "evenodd") == 0);
-       } else
-       if(strcmp(name, "stroke") == 0) {
-               if(strcmp(value, "none") == 0) {
-                       fBuilder.stroke_none();
-               } else if (strncmp(value, "url", 3) == 0) {
-                       char* url = parse_url(value);
-                       fBuilder.stroke_url(url);
-                       delete[] url;
-               } else {
-                       fBuilder.stroke(parse_color(value));
-               }
-       } else
-       if(strcmp(name, "stroke-width") == 0) {
-               fBuilder.stroke_width(parse_double(value));
-       } else
-       if(strcmp(name, "stroke-linecap") == 0) {
-               if(strcmp(value, "butt") == 0)          
fBuilder.line_cap(butt_cap);
-               else if(strcmp(value, "round") == 0)  
fBuilder.line_cap(round_cap);
-               else if(strcmp(value, "square") == 0) 
fBuilder.line_cap(square_cap);
-       } else
-       if(strcmp(name, "stroke-linejoin") == 0) {
-               if(strcmp(value, "miter") == 0)   
fBuilder.line_join(miter_join);
-               else if(strcmp(value, "round") == 0) 
fBuilder.line_join(round_join);
-               else if(strcmp(value, "bevel") == 0) 
fBuilder.line_join(bevel_join);
-       } else
-       if(strcmp(name, "stroke-miterlimit") == 0) {
-               fBuilder.miter_limit(parse_double(value));
-       } else
-       if(strcmp(name, "stroke-opacity") == 0) {
-               fBuilder.stroke_opacity(parse_double(value));
-       } else
-       if(strcmp(name, "transform") == 0) {
-               fBuilder.transform().premultiply(parse_transform(value));
-       } else
-       if (strcmp(name, "stop-color") == 0) {
-               fGradientStopColor = parse_color(value);
-       } else
-       if (strcmp(name, "stop-opacity") == 0) {
-               fGradientStopColor.opacity(parse_double(value));
-       }
-       //else
-       //if(strcmp(el, "<OTHER_ATTRIBUTES>") == 0)
-       //{
-       //}
-       // . . .
-       else
-       {
-               return false;
-       }
-       return true;
-}
-
-// copy_name
-void Parser::copy_name(const char* start, const char* end)
-{
-       unsigned len = unsigned(end - start);
-       if(fAttrNameLength == 0 || len > fAttrNameLength)
-       {
-               delete [] fAttrName;
-               fAttrName = new char[len + 1];
-               fAttrNameLength = len;
-       }
-       if(len) memcpy(fAttrName, start, len);
-       fAttrName[len] = 0;
-}
-
-// copy_value
-void Parser::copy_value(const char* start, const char* end)
-{
-       unsigned len = unsigned(end - start);
-       if(fAttrValueLength == 0 || len > fAttrValueLength)
-       {
-               delete [] fAttrValue;
-               fAttrValue = new char[len + 1];
-               fAttrValueLength = len;
-       }
-       if(len) memcpy(fAttrValue, start, len);
-       fAttrValue[len] = 0;
-}
-
-// parse_name_value
-bool Parser::parse_name_value(const char* nv_start, const char* nv_end)
-{
-       const char* str = nv_start;
-       while(str < nv_end && *str != ':') ++str;
-
-       const char* val = str;
-
-       // Right Trim
-       while(str > nv_start &&
-               (*str == ':' || isspace(*str))) --str;
-       ++str;
-
-       copy_name(nv_start, str);
-
-       while(val < nv_end && (*val == ':' || isspace(*val))) ++val;
-
-       copy_value(val, nv_end);
-       return parse_attr(fAttrName, fAttrValue);
-}
-
-// parse_style
-void Parser::parse_style(const char* str)
-{
-       while(*str)
-       {
-               // Left Trim
-               while(*str && isspace(*str)) ++str;
-               const char* nv_start = str;
-               while(*str && *str != ';') ++str;
-               const char* nv_end = str;
-
-               // Right Trim
-               while(nv_end > nv_start &&
-                       (*nv_end == ';' || isspace(*nv_end))) --nv_end;
-               ++nv_end;
-
-               parse_name_value(nv_start, nv_end);
-               if(*str) ++str;
-       }
-
-}
-
-// parse_circle
-void
-Parser::parse_circle(const char** attr)
-{
-       int i;
-       double cx = 0.0;
-       double cy = 0.0;
-       double r = 0.0;
-
-       fBuilder.begin_path();
-       for(i = 0; attr[i]; i += 2) {
-               if (!parse_attr(attr[i], attr[i + 1])) {
-                       if(strcmp(attr[i], "cx") == 0)  cx = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "cy") == 0)  cy = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "r") == 0)   r = parse_double(attr[i 
+ 1]);
-               }
-       }
-
-
-       if (r != 0.0) {
-               if (r < 0.0) throw exception("parse_circle: Invalid radius: 
%f", r);
-
-               fBuilder.move_to(cx, cy - r);
-               fBuilder.curve4(cx + r * 0.56, cy - r,
-                                               cx + r, cy - r * 0.56,
-                                               cx + r, cy);
-               fBuilder.curve4(cx + r, cy + r * 0.56,
-                                               cx + r * 0.56, cy + r,
-                                               cx, cy + r);
-               fBuilder.curve4(cx - r * 0.56, cy + r,
-                                               cx - r, cy + r * 0.56,
-                                               cx - r, cy);
-               fBuilder.curve4(cx - r, cy - r * 0.56,
-                                               cx - r * 0.56, cy - r,
-                                               cx, cy - r);
-               fBuilder.close_subpath();
-       }
-       fBuilder.end_path();
-}
-
-// parse_ellipse
-void
-Parser::parse_ellipse(const char** attr)
-{
-       int i;
-       double cx = 0.0;
-       double cy = 0.0;
-       double rx = 0.0;
-       double ry = 0.0;
-
-       fBuilder.begin_path();
-       for(i = 0; attr[i]; i += 2) {
-               if (!parse_attr(attr[i], attr[i + 1])) {
-                       if(strcmp(attr[i], "cx") == 0)  cx = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "cy") == 0)  cy = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "rx") == 0)  rx = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "ry") == 0)  ry = 
parse_double(attr[i + 1]);
-               }
-       }
-
-
-       if (rx != 0.0 && ry != 0.0) {
-               if (rx < 0.0) throw exception("parse_ellipse: Invalid x-radius: 
%f", rx);
-               if (ry < 0.0) throw exception("parse_ellipse: Invalid y-radius: 
%f", ry);
-
-               fBuilder.move_to(cx, cy - ry);
-               fBuilder.curve4(cx + rx * 0.56, cy - ry,
-                                               cx + rx, cy - ry * 0.56,
-                                               cx + rx, cy);
-               fBuilder.curve4(cx + rx, cy + ry * 0.56,
-                                               cx + rx * 0.56, cy + ry,
-                                               cx, cy + ry);
-               fBuilder.curve4(cx - rx * 0.56, cy + ry,
-                                               cx - rx, cy + ry * 0.56,
-                                               cx - rx, cy);
-               fBuilder.curve4(cx - rx, cy - ry * 0.56,
-                                               cx - rx * 0.56, cy - ry,
-                                               cx, cy - ry);
-               fBuilder.close_subpath();
-       }
-       fBuilder.end_path();
-}
-
-// parse_rect
-void
-Parser::parse_rect(const char** attr)
-{
-       int i;
-       double x = 0.0;
-       double y = 0.0;
-       double w = 0.0;
-       double h = 0.0;
-
-       fBuilder.begin_path();
-       for(i = 0; attr[i]; i += 2)
-       {
-               if(!parse_attr(attr[i], attr[i + 1]))
-               {
-                       if(strcmp(attr[i], "x") == 0)     x = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "y") == 0)     y = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "width") == 0)  w = 
parse_double(attr[i + 1]);
-                       if(strcmp(attr[i], "height") == 0) h = 
parse_double(attr[i + 1]);
-                       // rx - to be implemented
-                       // ry - to be implemented
-               }
-       }
-
-
-       if(w != 0.0 && h != 0.0)
-       {
-               if(w < 0.0) throw exception("parse_rect: Invalid width: %f", w);
-               if(h < 0.0) throw exception("parse_rect: Invalid height: %f", 
h);
-
-               fBuilder.move_to(x,      y);
-               fBuilder.line_to(x + w, y);
-               fBuilder.line_to(x + w, y + h);
-               fBuilder.line_to(x,      y + h);
-               fBuilder.close_subpath();
-       }
-       fBuilder.end_path();
-}
-
-// parse_line
-void
-Parser::parse_line(const char** attr)
-{
-       int i;
-       double x1 = 0.0;
-       double y1 = 0.0;
-       double x2 = 0.0;
-       double y2 = 0.0;
-
-       fBuilder.begin_path();
-       for(i = 0; attr[i]; i += 2)
-       {
-               if(!parse_attr(attr[i], attr[i + 1]))
-               {
-                       if(strcmp(attr[i], "x1") == 0) x1 = parse_double(attr[i 
+ 1]);
-                       if(strcmp(attr[i], "y1") == 0) y1 = parse_double(attr[i 
+ 1]);
-                       if(strcmp(attr[i], "x2") == 0) x2 = parse_double(attr[i 
+ 1]);
-                       if(strcmp(attr[i], "y2") == 0) y2 = parse_double(attr[i 
+ 1]);
-               }
-       }
-
-       fBuilder.move_to(x1, y1);
-       fBuilder.line_to(x2, y2);
-       fBuilder.end_path();
-}
-
-// parse_poly
-void
-Parser::parse_poly(const char** attr, bool close_flag)
-{
-       int i;
-       double x = 0.0;
-       double y = 0.0;
-
-       fBuilder.begin_path();
-       for (i = 0; attr[i]; i += 2) {
-               if (!parse_attr(attr[i], attr[i + 1])) {
-                       if (strcmp(attr[i], "points") == 0) {
-                               fPathTokenizer.set_path_str(attr[i + 1]);
-                               if (!fPathTokenizer.next())
-                                       throw exception("parse_poly: Too few 
coordinates");
-                               x = fPathTokenizer.last_number();
-                               if (!fPathTokenizer.next())
-                                       throw exception("parse_poly: Too few 
coordinates");
-                               y = fPathTokenizer.last_number();
-                               fBuilder.move_to(x, y);
-                               while (fPathTokenizer.next()) {
-                                       x = fPathTokenizer.last_number();
-                                       if (!fPathTokenizer.next())
-                                               throw exception("parse_poly: 
Odd number of coordinates");
-                                       y = fPathTokenizer.last_number();
-                                       fBuilder.line_to(x, y);
-                               }
-                       }
-               }
-       }
-       if (close_flag)
-               fBuilder.close_subpath();
-       fBuilder.end_path();
-}
-
-// parse_transform
-trans_affine
-Parser::parse_transform(const char* str)
-{
-       trans_affine transform;
-       while (*str) {
-               if (islower(*str)) {
-                       if (strncmp(str, "matrix", 6) == 0)             str += 
parse_matrix(str, transform);    else
-                       if (strncmp(str, "translate", 9) == 0)  str += 
parse_translate(str, transform); else
-                       if (strncmp(str, "rotate", 6) == 0)             str += 
parse_rotate(str, transform);    else
-                       if (strncmp(str, "scale", 5) == 0)              str += 
parse_scale(str, transform);             else
-                       if (strncmp(str, "skewX", 5) == 0)              str += 
parse_skew_x(str, transform);    else
-                       if (strncmp(str, "skewY", 5) == 0)              str += 
parse_skew_y(str, transform);    else
-                       {
-                               ++str;
-                       }
-               }
-               else
-               {
-                       ++str;
-               }
-       }
-       return transform;
-}
-
-// parse_gradient
-void
-Parser::parse_gradient(const char** attr, bool radial)
-{
-//     printf("Parser::parse_gradient(%s)\n", attr[0]);
-
-       fBuilder.StartGradient(radial);
-
-       for (int32 i = 0; attr[i]; i += 2)
-       {
-/*             if(!parse_attr(attr[i], attr[i + 1]))
-               {*/
-                       if (strcmp(attr[i], "id") == 0)
-                               fBuilder.CurrentGradient()->SetID(attr[i + 1]);
-                       else if(strcmp(attr[i], "gradientTransform") == 0) {
-                               
fBuilder.CurrentGradient()->SetTransformation(parse_transform(attr[i + 1]));
-                       } else
-                               fBuilder.CurrentGradient()->AddString(attr[i], 
attr[i + 1]);
-/*             }*/
-       }
-}
-
-// parse_gradient_stop
-void
-Parser::parse_gradient_stop(const char** attr)
-{
-//     printf("Parser::parse_gradient_stop(%s)\n", attr[0]);
-
-       float offset = 0.0;
-       rgba8 color;
-       for (int32 i = 0; attr[i]; i += 2) {
-               if (strcmp(attr[i], "offset") == 0) {
-                       offset = parse_double(attr[i + 1]);
-               } else
-               if (strcmp(attr[i], "style") == 0) {
-                       parse_style(attr[i + 1]);
-                       // here we get a bit hacky, in order not to change too 
much code at once...
-                       // historically, parse_style() was for parsing path 
attributes only, but
-                       // it comes in handy here as well, and I added 
"stop-color" and "stop-opacity"
-                       // to parse_name_value(). It remembers the color in 
"fGradientStopColor".
-                       // The color will of course be broken if the "style" 
attribute did not contain
-                       // any valid stuff.
-                       color = fGradientStopColor;
-               } else
-               if (strcmp(attr[i], "stop-color") == 0) {
-                       color = parse_color(attr[i + 1]);
-               } else
-               if (strcmp(attr[i], "stop-opacity") == 0) {
-                       color.opacity(parse_double(attr[i + 1]));
-               }
-       }
-
-//     printf("  offset: %f, color: %d, %d, %d, %d\n", offset, color.r, 
color.g, color.b, color.a);
-
-       if (SVGGradient* gradient = fBuilder.CurrentGradient()) {
-               gradient->AddStop(offset, color);
-       } else {
-               throw exception("parse_gradient_stop() outside of gradient 
tag!\n");
-       }
-}
-
-// is_numeric
-static bool
-is_numeric(char c)
-{
-       return strchr("0123456789+-.eE", c) != 0;
-}
-
-// parse_transform_args
-static unsigned
-parse_transform_args(const char* str,
-                                        double* args,
-                                        unsigned max_na,
-                                        unsigned* na)
-{
-       *na = 0;
-       const char* ptr = str;
-       while(*ptr && *ptr != '(') ++ptr;
-       if(*ptr == 0)
-       {
-               throw exception("parse_transform_args: Invalid syntax");
-       }
-       const char* end = ptr;
-       while(*end && *end != ')') ++end;
-       if(*end == 0)
-       {
-               throw exception("parse_transform_args: Invalid syntax");
-       }
-
-       while(ptr < end)
-       {
-               if(is_numeric(*ptr))
-               {
-                       if(*na >= max_na)
-                       {
-                               throw exception("parse_transform_args: Too many 
arguments");
-                       }
-                       args[(*na)++] = atof(ptr);
-                       while(ptr < end && is_numeric(*ptr)) ++ptr;
-               }
-               else
-               {
-                       ++ptr;
-               }
-       }
-       return unsigned(end - str);
-}
-
-// parse_matrix
-unsigned
-Parser::parse_matrix(const char* str, trans_affine& transform)
-{
-       double args[6];
-       unsigned na = 0;
-       unsigned len = parse_transform_args(str, args, 6, &na);
-       if(na != 6)
-       {
-               throw exception("parse_matrix: Invalid number of arguments");
-       }
-       transform.premultiply(trans_affine(args[0], args[1], args[2], args[3], 
args[4], args[5]));
-       return len;
-}
-
-// parse_translate
-unsigned
-Parser::parse_translate(const char* str, trans_affine& transform)
-{
-       double args[2];
-       unsigned na = 0;
-       unsigned len = parse_transform_args(str, args, 2, &na);
-       if(na == 1) args[1] = 0.0;
-       transform.premultiply(trans_affine_translation(args[0], args[1]));
-       return len;
-}
-
-// parse_rotate
-unsigned
-Parser::parse_rotate(const char* str, trans_affine& transform)
-{
-       double args[3];
-       unsigned na = 0;
-       unsigned len = parse_transform_args(str, args, 3, &na);
-       if(na == 1)
-       {
-               transform.premultiply(trans_affine_rotation(deg2rad(args[0])));
-       }
-       else if(na == 3)
-       {
-               trans_affine t = trans_affine_translation(-args[1], -args[2]);
-               t *= trans_affine_rotation(deg2rad(args[0]));
-               t *= trans_affine_translation(args[1], args[2]);
-               transform.premultiply(t);
-       }
-       else
-       {
-               throw exception("parse_rotate: Invalid number of arguments");
-       }
-       return len;
-}
-
-// parse_scale
-unsigned Parser::parse_scale(const char* str, trans_affine& transform)
-{
-       double args[2];
-       unsigned na = 0;
-       unsigned len = parse_transform_args(str, args, 2, &na);
-       if(na == 1) args[1] = args[0];
-       transform.premultiply(trans_affine_scaling(args[0], args[1]));
-       return len;
-}
-
-// parse_skew_x
-unsigned
-Parser::parse_skew_x(const char* str, trans_affine& transform)
-{
-       double arg;
-       unsigned na = 0;
-       unsigned len = parse_transform_args(str, &arg, 1, &na);
-       transform.premultiply(trans_affine_skewing(deg2rad(arg), 0.0));
-       return len;
-}
-
-// parse_skew_y
-unsigned
-Parser::parse_skew_y(const char* str, trans_affine& transform)
-{
-       double arg;
-       unsigned na = 0;
-       unsigned len = parse_transform_args(str, &arg, 1, &na);
-       transform.premultiply(trans_affine_skewing(0.0, deg2rad(arg)));
-       return len;
-}
-
-
-} // namespace svg
-} // namespace agg
-
-
-
diff --git a/src/apps/icon-o-matic/import_export/svg/SVGParser.h 
b/src/apps/icon-o-matic/import_export/svg/SVGParser.h
deleted file mode 100644
index 7ce6c81..0000000
--- a/src/apps/icon-o-matic/import_export/svg/SVGParser.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2006, Haiku. All rights reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *             Stephan Aßmus <superstippi@xxxxxx>
- */
-
-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.2
-// Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Contact: mcseem@xxxxxxxxxxxxx
-//               mcseemagg@xxxxxxxxx
-//               http://www.antigrain.com
-//----------------------------------------------------------------------------
-
-#ifndef SVG_PARSER_H
-#define SVG_PARSER_H
-
-#include "PathTokenizer.h"
-#include "DocumentBuilder.h"
-
-namespace agg {
-namespace svg {
-
-class Parser {
-       enum { buf_size = BUFSIZ };
- public:
-
-                                                               
Parser(DocumentBuilder& builder);
-       virtual                                         ~Parser();
-
-                       void                            parse(const char* 
pathToFile);
-                       const char*                     title() const
-                                                                       { 
return fTitle; }
-
-                       bool                            TagsIgnored() const
-                                                                       { 
return fTagsIgnored; }
-
- private:
-       // XML event handlers
-       static  void                            start_element(void* data, const 
char* el,
-                                                                               
          const char** attr);
-       static  void                            end_element(void* data, const 
char* el);
-       static  void                            content(void* data, const char* 
s, int len);
-
-                       void                            parse_svg(const char** 
attr);
-                       void                            parse_attr(const char** 
attr);
-                       void                            parse_path(const char** 
attr);
-                       void                            parse_poly(const char** 
attr, bool close_flag);
-                       void                            parse_circle(const 
char** attr);
-                       void                            parse_ellipse(const 
char** attr);
-                       void                            parse_rect(const char** 
attr);
-                       void                            parse_line(const char** 
attr);
-                       void                            parse_style(const char* 
str);
-                       trans_affine            parse_transform(const char* 
str);
-
-                       void                            parse_gradient(const 
char** attr, bool radial);
-                       void                            
parse_gradient_stop(const char** attr);
-
-                       unsigned                        parse_matrix(const 
char* str, trans_affine& transform);
-                       unsigned                        parse_translate(const 
char* str, trans_affine& transform);
-                       unsigned                        parse_rotate(const 
char* str, trans_affine& transform);
-                       unsigned                        parse_scale(const char* 
str, trans_affine& transform);
-                       unsigned                        parse_skew_x(const 
char* str, trans_affine& transform);
-                       unsigned                        parse_skew_y(const 
char* str, trans_affine& transform);
-
-                       bool                            parse_attr(const char* 
name,
-                                                                               
   const char* value);
-                       bool                            parse_name_value(const 
char* nv_start,
-                                                                               
                 const char* nv_end);
-                       void                            copy_name(const char* 
start, const char* end);
-                       void                            copy_value(const char* 
start, const char* end);
-
-private:
-                       DocumentBuilder&        fBuilder;
-                       PathTokenizer           fPathTokenizer;
-                       char*                           fBuffer;
-                       char*                           fTitle;
-                       unsigned                        fTitleLength;
-
-                       bool                            fTitleFlag;
-                       bool                            fPathFlag;
-
-                       char*                           fAttrName;
-                       char*                           fAttrValue;
-                       unsigned                        fAttrNameLength;
-                       unsigned                        fAttrValueLength;
-
-                       rgba8                           fGradientStopColor;
-
-                       bool                            fTagsIgnored;
-};
-
-} // namespace svg
-} // namespace agg
-
-#endif // SVG_PARSER_H
diff --git a/src/apps/icon-o-matic/import_export/svg/nanosvg.h 
b/src/apps/icon-o-matic/import_export/svg/nanosvg.h
new file mode 100644
index 0000000..e5f6900
--- /dev/null
+++ b/src/apps/icon-o-matic/import_export/svg/nanosvg.h
@@ -0,0 +1,2975 @@
+/*
+ * Copyright (c) 2013-14 Mikko Mononen memon@xxxxxxxxxx
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ *
+ * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example
+ * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) 
(http://www.antigrain.com/)
+ *
+ * Arc calculation code based on canvg (https://code.google.com/p/canvg/)
+ *
+ * Bounding box calculation based on 
http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
+ *
+ */
+
+#ifndef NANOSVG_H
+#define NANOSVG_H
+
+#ifndef NANOSVG_CPLUSPLUS
+#ifdef __cplusplus
+extern "C" {
+#endif
+#endif
+
+// NanoSVG is a simple stupid single-header-file SVG parse. The output of the 
parser is a list of cubic bezier shapes.
+//
+// The library suits well for anything from rendering scalable icons in your 
editor application to prototyping a game.
+//
+// NanoSVG supports a wide range of SVG features, but something may be 
missing, feel free to create a pull request!
+//
+// The shapes in the SVG images are transformed by the viewBox and converted 
to specified units.
+// That is, you should get the same looking data as your designed in your 
favorite app.
+//
+// NanoSVG can return the paths in few different units. For example if you 
want to render an image, you may choose
+// to get the paths in pixels, or if you are feeding the data into a 
CNC-cutter, you may want to use millimeters.
+//
+// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', 
or 'in'.
+// DPI (dots-per-inch) controls how the unit conversion is done.
+//
+// If you don't know or care about the units stuff, "px" and 96 should get you 
going.
+
+
+/* Example Usage:
+       // Load SVG
+       NSVGimage* image;
+       image = nsvgParseFromFile("test.svg", "px", 96);
+       printf("size: %f x %f\n", image->width, image->height);
+       // Use...
+       for (NSVGshape *shape = image->shapes; shape != NULL; shape = 
shape->next) {
+               for (NSVGpath *path = shape->paths; path != NULL; path = 
path->next) {
+                       for (int i = 0; i < path->npts-1; i += 3) {
+                               float* p = &path->pts[i*2];
+                               drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], 
p[6],p[7]);
+                       }
+               }
+       }
+       // Delete
+       nsvgDelete(image);
+*/
+
+enum NSVGpaintType {
+       NSVG_PAINT_NONE = 0,
+       NSVG_PAINT_COLOR = 1,
+       NSVG_PAINT_LINEAR_GRADIENT = 2,
+       NSVG_PAINT_RADIAL_GRADIENT = 3
+};
+
+enum NSVGspreadType {
+       NSVG_SPREAD_PAD = 0,
+       NSVG_SPREAD_REFLECT = 1,
+       NSVG_SPREAD_REPEAT = 2
+};
+
+enum NSVGlineJoin {
+       NSVG_JOIN_MITER = 0,
+       NSVG_JOIN_ROUND = 1,
+       NSVG_JOIN_BEVEL = 2
+};
+
+enum NSVGlineCap {
+       NSVG_CAP_BUTT = 0,
+       NSVG_CAP_ROUND = 1,
+       NSVG_CAP_SQUARE = 2
+};
+
+enum NSVGfillRule {
+       NSVG_FILLRULE_NONZERO = 0,
+       NSVG_FILLRULE_EVENODD = 1
+};
+
+enum NSVGflags {
+       NSVG_FLAGS_VISIBLE = 0x01
+};
+
+typedef struct NSVGgradientStop {
+       unsigned int color;
+       float offset;
+} NSVGgradientStop;
+
+typedef struct NSVGgradient {
+       float xform[6];
+       char spread;
+       float fx, fy;
+       int nstops;
+       NSVGgradientStop stops[1];
+} NSVGgradient;
+
+typedef struct NSVGpaint {
+       char type;
+       union {
+               unsigned int color;
+               NSVGgradient* gradient;
+       };
+} NSVGpaint;
+
+typedef struct NSVGpath
+{
+       float* pts;                                     // Cubic bezier points: 
x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
+       int npts;                                       // Total number of 
bezier points.
+       char closed;                            // Flag indicating if shapes 
should be treated as closed.
+       float bounds[4];                        // Tight bounding box of the 
shape [minx,miny,maxx,maxy].
+       struct NSVGpath* next;          // Pointer to next path, or NULL if 
last element.
+} NSVGpath;
+
+typedef struct NSVGshape
+{
+       char id[64];                            // Optional 'id' attr of the 
shape or its group
+       NSVGpaint fill;                         // Fill paint
+       NSVGpaint stroke;                       // Stroke paint
+       float opacity;                          // Opacity of the shape.
+       float strokeWidth;                      // Stroke width (scaled).
+       float strokeDashOffset;         // Stroke dash offset (scaled).
+       float strokeDashArray[8];                       // Stroke dash array 
(scaled).
+       char strokeDashCount;                           // Number of dash 
values in dash array.
+       char strokeLineJoin;            // Stroke join type.
+       char strokeLineCap;                     // Stroke cap type.
+       float miterLimit;                       // Miter limit
+       char fillRule;                          // Fill rule, see NSVGfillRule.
+       unsigned char flags;            // Logical or of NSVG_FLAGS_* flags
+       float bounds[4];                        // Tight bounding box of the 
shape [minx,miny,maxx,maxy].
+       NSVGpath* paths;                        // Linked list of paths in the 
image.
+       struct NSVGshape* next;         // Pointer to next shape, or NULL if 
last element.
+} NSVGshape;
+
+typedef struct NSVGimage
+{
+       float width;                            // Width of the image.
+       float height;                           // Height of the image.
+       NSVGshape* shapes;                      // Linked list of shapes in the 
image.
+} NSVGimage;
+
+// Parses SVG file from a file, returns SVG image as paths.
+NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float 
dpi);
+
+// Parses SVG file from a null terminated string, returns SVG image as paths.
+// Important note: changes the string.
+NSVGimage* nsvgParse(char* input, const char* units, float dpi);
+
+// Duplicates a path.
+NSVGpath* nsvgDuplicatePath(NSVGpath* p);
+
+// Deletes an image.
+void nsvgDelete(NSVGimage* image);
+
+#ifndef NANOSVG_CPLUSPLUS
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#endif // NANOSVG_H
+
+#ifdef NANOSVG_IMPLEMENTATION
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#define NSVG_PI (3.14159265358979323846264338327f)
+#define NSVG_KAPPA90 (0.5522847493f)   // Length proportional to radius of a 
cubic bezier handle for 90deg arcs.
+
+#define NSVG_ALIGN_MIN 0
+#define NSVG_ALIGN_MID 1
+#define NSVG_ALIGN_MAX 2
+#define NSVG_ALIGN_NONE 0
+#define NSVG_ALIGN_MEET 1
+#define NSVG_ALIGN_SLICE 2
+
+#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0)
+#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | 
((unsigned int)b << 16))
+
+#ifdef _MSC_VER
+       #pragma warning (disable: 4996) // Switch off security warnings
+       #pragma warning (disable: 4100) // Switch off unreferenced formal 
parameter warnings
+       #ifdef __cplusplus
+       #define NSVG_INLINE inline
+       #else
+       #define NSVG_INLINE
+       #endif
+#else
+       #define NSVG_INLINE inline
+#endif
+
+
+static int nsvg__isspace(char c)
+{
+       return strchr(" \t\n\v\f\r", c) != 0;
+}
+
+static int nsvg__isdigit(char c)
+{
+       return c >= '0' && c <= '9';
+}
+
+static int nsvg__isnum(char c)
+{
+       return strchr("0123456789+-.eE", c) != 0;
+}
+
+static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; }
+static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
+
+
+// Simple XML parser
+
+#define NSVG_XML_TAG 1
+#define NSVG_XML_CONTENT 2
+#define NSVG_XML_MAX_ATTRIBS 256
+
+static void nsvg__parseContent(char* s,
+                                                          void 
(*contentCb)(void* ud, const char* s),
+                                                          void* ud)
+{
+       // Trim start white spaces
+       while (*s && nsvg__isspace(*s)) s++;
+       if (!*s) return;
+
+       if (contentCb)
+               (*contentCb)(ud, s);
+}
+
+static void nsvg__parseElement(char* s,
+                                                          void 
(*startelCb)(void* ud, const char* el, const char** attr),
+                                                          void 
(*endelCb)(void* ud, const char* el),
+                                                          void* ud)
+{
+       const char* attr[NSVG_XML_MAX_ATTRIBS];
+       int nattr = 0;
+       char* name;
+       int start = 0;
+       int end = 0;
+       char quote;
+
+       // Skip white space after the '<'
+       while (*s && nsvg__isspace(*s)) s++;
+
+       // Check if the tag is end tag
+       if (*s == '/') {
+               s++;
+               end = 1;
+       } else {
+               start = 1;
+       }
+
+       // Skip comments, data and preprocessor stuff.
+       if (!*s || *s == '?' || *s == '!')
+               return;
+
+       // Get tag name
+       name = s;
+       while (*s && !nsvg__isspace(*s)) s++;
+       if (*s) { *s++ = '\0'; }
+
+       // Get attribs
+       while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) {
+               char* name = NULL;
+               char* value = NULL;
+
+               // Skip white space before the attrib name
+               while (*s && nsvg__isspace(*s)) s++;
+               if (!*s) break;
+               if (*s == '/') {
+                       end = 1;
+                       break;
+               }
+               name = s;
+               // Find end of the attrib name.
+               while (*s && !nsvg__isspace(*s) && *s != '=') s++;
+               if (*s) { *s++ = '\0'; }
+               // Skip until the beginning of the value.
+               while (*s && *s != '\"' && *s != '\'') s++;
+               if (!*s) break;
+               quote = *s;
+               s++;
+               // Store value and find the end of it.
+               value = s;
+               while (*s && *s != quote) s++;
+               if (*s) { *s++ = '\0'; }
+
+               // Store only well formed attributes
+               if (name && value) {
+                       attr[nattr++] = name;
+                       attr[nattr++] = value;
+               }
+       }
+
+       // List terminator
+       attr[nattr++] = 0;
+       attr[nattr++] = 0;
+
+       // Call callbacks.
+       if (start && startelCb)
+               (*startelCb)(ud, name, attr);
+       if (end && endelCb)
+               (*endelCb)(ud, name);
+}
+
+int nsvg__parseXML(char* input,
+                                  void (*startelCb)(void* ud, const char* el, 
const char** attr),
+                                  void (*endelCb)(void* ud, const char* el),
+                                  void (*contentCb)(void* ud, const char* s),
+                                  void* ud)
+{
+       char* s = input;
+       char* mark = s;
+       int state = NSVG_XML_CONTENT;
+       while (*s) {
+               if (*s == '<' && state == NSVG_XML_CONTENT) {
+                       // Start of a tag
+                       *s++ = '\0';
+                       nsvg__parseContent(mark, contentCb, ud);
+                       mark = s;
+                       state = NSVG_XML_TAG;
+               } else if (*s == '>' && state == NSVG_XML_TAG) {
+                       // Start of a content or new tag.
+                       *s++ = '\0';
+                       nsvg__parseElement(mark, startelCb, endelCb, ud);
+                       mark = s;
+                       state = NSVG_XML_CONTENT;
+               } else {
+                       s++;
+               }
+       }
+
+       return 1;
+}
+
+
+/* Simple SVG parser. */
+
+#define NSVG_MAX_ATTR 128
+
+enum NSVGgradientUnits {
+       NSVG_USER_SPACE = 0,
+       NSVG_OBJECT_SPACE = 1
+};
+
+#define NSVG_MAX_DASHES 8
+
+enum NSVGunits {
+       NSVG_UNITS_USER,
+       NSVG_UNITS_PX,
+       NSVG_UNITS_PT,
+       NSVG_UNITS_PC,
+       NSVG_UNITS_MM,
+       NSVG_UNITS_CM,
+       NSVG_UNITS_IN,
+       NSVG_UNITS_PERCENT,
+       NSVG_UNITS_EM,
+       NSVG_UNITS_EX
+};
+
+typedef struct NSVGcoordinate {
+       float value;
+       int units;
+} NSVGcoordinate;
+
+typedef struct NSVGlinearData {
+       NSVGcoordinate x1, y1, x2, y2;
+} NSVGlinearData;
+
+typedef struct NSVGradialData {
+       NSVGcoordinate cx, cy, r, fx, fy;
+} NSVGradialData;
+
+typedef struct NSVGgradientData
+{
+       char id[64];
+       char ref[64];
+       char type;
+       union {
+               NSVGlinearData linear;
+               NSVGradialData radial;
+       };
+       char spread;
+       char units;
+       float xform[6];
+       int nstops;
+       NSVGgradientStop* stops;
+       struct NSVGgradientData* next;
+} NSVGgradientData;
+
+typedef struct NSVGattrib
+{
+       char id[64];
+       float xform[6];
+       unsigned int fillColor;
+       unsigned int strokeColor;
+       float opacity;
+       float fillOpacity;
+       float strokeOpacity;
+       char fillGradient[64];
+       char strokeGradient[64];
+       float strokeWidth;
+       float strokeDashOffset;
+       float strokeDashArray[NSVG_MAX_DASHES];
+       int strokeDashCount;
+       char strokeLineJoin;
+       char strokeLineCap;
+       float miterLimit;
+       char fillRule;
+       float fontSize;
+       unsigned int stopColor;
+       float stopOpacity;
+       float stopOffset;
+       char hasFill;
+       char hasStroke;
+       char visible;
+} NSVGattrib;
+
+typedef struct NSVGparser
+{
+       NSVGattrib attr[NSVG_MAX_ATTR];
+       int attrHead;
+       float* pts;
+       int npts;
+       int cpts;
+       NSVGpath* plist;
+       NSVGimage* image;
+       NSVGgradientData* gradients;
+       NSVGshape* shapesTail;
+       float viewMinx, viewMiny, viewWidth, viewHeight;
+       int alignX, alignY, alignType;
+       float dpi;
+       char pathFlag;
+       char defsFlag;
+} NSVGparser;
+
+static void nsvg__xformIdentity(float* t)
+{
+       t[0] = 1.0f; t[1] = 0.0f;
+       t[2] = 0.0f; t[3] = 1.0f;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetTranslation(float* t, float tx, float ty)
+{
+       t[0] = 1.0f; t[1] = 0.0f;
+       t[2] = 0.0f; t[3] = 1.0f;
+       t[4] = tx; t[5] = ty;
+}
+
+static void nsvg__xformSetScale(float* t, float sx, float sy)
+{
+       t[0] = sx; t[1] = 0.0f;
+       t[2] = 0.0f; t[3] = sy;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetSkewX(float* t, float a)
+{
+       t[0] = 1.0f; t[1] = 0.0f;
+       t[2] = tanf(a); t[3] = 1.0f;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetSkewY(float* t, float a)
+{
+       t[0] = 1.0f; t[1] = tanf(a);
+       t[2] = 0.0f; t[3] = 1.0f;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformSetRotation(float* t, float a)
+{
+       float cs = cosf(a), sn = sinf(a);
+       t[0] = cs; t[1] = sn;
+       t[2] = -sn; t[3] = cs;
+       t[4] = 0.0f; t[5] = 0.0f;
+}
+
+static void nsvg__xformMultiply(float* t, float* s)
+{
+       float t0 = t[0] * s[0] + t[1] * s[2];
+       float t2 = t[2] * s[0] + t[3] * s[2];
+       float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
+       t[1] = t[0] * s[1] + t[1] * s[3];
+       t[3] = t[2] * s[1] + t[3] * s[3];
+       t[5] = t[4] * s[1] + t[5] * s[3] + s[5];
+       t[0] = t0;
+       t[2] = t2;
+       t[4] = t4;
+}
+
+static void nsvg__xformInverse(float* inv, float* t)
+{
+       double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1];
+       if (det > -1e-6 && det < 1e-6) {
+               nsvg__xformIdentity(t);
+               return;
+       }
+       invdet = 1.0 / det;
+       inv[0] = (float)(t[3] * invdet);
+       inv[2] = (float)(-t[2] * invdet);
+       inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet);
+       inv[1] = (float)(-t[1] * invdet);
+       inv[3] = (float)(t[0] * invdet);
+       inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet);
+}
+
+static void nsvg__xformPremultiply(float* t, float* s)
+{
+       float s2[6];
+       memcpy(s2, s, sizeof(float)*6);
+       nsvg__xformMultiply(s2, t);
+       memcpy(t, s2, sizeof(float)*6);
+}
+
+static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t)
+{
+       *dx = x*t[0] + y*t[2] + t[4];
+       *dy = x*t[1] + y*t[3] + t[5];
+}
+
+static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t)
+{
+       *dx = x*t[0] + y*t[2];
+       *dy = x*t[1] + y*t[3];
+}
+
+#define NSVG_EPSILON (1e-12)
+
+static int nsvg__ptInBounds(float* pt, float* bounds)
+{
+       return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] 
&& pt[1] <= bounds[3];
+}
+
+
+static double nsvg__evalBezier(double t, double p0, double p1, double p2, 
double p3)
+{
+       double it = 1.0-t;
+       return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3;
+}
+
+static void nsvg__curveBounds(float* bounds, float* curve)
+{
+       int i, j, count;
+       double roots[2], a, b, c, b2ac, t, v;
+       float* v0 = &curve[0];
+       float* v1 = &curve[2];
+       float* v2 = &curve[4];
+       float* v3 = &curve[6];
+
+       // Start the bounding box by end points
+       bounds[0] = nsvg__minf(v0[0], v3[0]);
+       bounds[1] = nsvg__minf(v0[1], v3[1]);
+       bounds[2] = nsvg__maxf(v0[0], v3[0]);
+       bounds[3] = nsvg__maxf(v0[1], v3[1]);
+
+       // Bezier curve fits inside the convex hull of it's control points.
+       // If control points are inside the bounds, we're done.
+       if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds))
+               return;
+
+       // Add bezier curve inflection points in X and Y.
+       for (i = 0; i < 2; i++) {
+               a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i];
+               b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i];
+               c = 3.0 * v1[i] - 3.0 * v0[i];
+               count = 0;
+               if (fabs(a) < NSVG_EPSILON) {
+                       if (fabs(b) > NSVG_EPSILON) {
+                               t = -c / b;
+                               if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
+                                       roots[count++] = t;
+                       }
+               } else {
+                       b2ac = b*b - 4.0*c*a;
+                       if (b2ac > NSVG_EPSILON) {
+                               t = (-b + sqrt(b2ac)) / (2.0 * a);
+                               if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
+                                       roots[count++] = t;
+                               t = (-b - sqrt(b2ac)) / (2.0 * a);
+                               if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON)
+                                       roots[count++] = t;
+                       }
+               }
+               for (j = 0; j < count; j++) {
+                       v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], 
v3[i]);
+                       bounds[0+i] = nsvg__minf(bounds[0+i], (float)v);
+                       bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v);
+               }
+       }
+}
+
+static NSVGparser* nsvg__createParser()
+{
+       NSVGparser* p;
+       p = (NSVGparser*)malloc(sizeof(NSVGparser));
+       if (p == NULL) goto error;
+       memset(p, 0, sizeof(NSVGparser));
+
+       p->image = (NSVGimage*)malloc(sizeof(NSVGimage));
+       if (p->image == NULL) goto error;
+       memset(p->image, 0, sizeof(NSVGimage));
+
+       // Init style
+       nsvg__xformIdentity(p->attr[0].xform);
+       memset(p->attr[0].id, 0, sizeof p->attr[0].id);
+       p->attr[0].fillColor = NSVG_RGB(0,0,0);
+       p->attr[0].strokeColor = NSVG_RGB(0,0,0);
+       p->attr[0].opacity = 1;
+       p->attr[0].fillOpacity = 1;
+       p->attr[0].strokeOpacity = 1;
+       p->attr[0].stopOpacity = 1;
+       p->attr[0].strokeWidth = 1;
+       p->attr[0].strokeLineJoin = NSVG_JOIN_MITER;
+       p->attr[0].strokeLineCap = NSVG_CAP_BUTT;
+       p->attr[0].miterLimit = 4;
+       p->attr[0].fillRule = NSVG_FILLRULE_NONZERO;
+       p->attr[0].hasFill = 1;
+       p->attr[0].visible = 1;
+
+       return p;
+
+error:
+       if (p) {
+               if (p->image) free(p->image);
+               free(p);
+       }
+       return NULL;
+}
+
+static void nsvg__deletePaths(NSVGpath* path)
+{
+       while (path) {
+               NSVGpath *next = path->next;
+               if (path->pts != NULL)
+                       free(path->pts);
+               free(path);
+               path = next;
+       }
+}
+
+static void nsvg__deletePaint(NSVGpaint* paint)
+{
+       if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == 
NSVG_PAINT_RADIAL_GRADIENT)
+               free(paint->gradient);
+}
+
+static void nsvg__deleteGradientData(NSVGgradientData* grad)
+{
+       NSVGgradientData* next;
+       while (grad != NULL) {
+               next = grad->next;
+               free(grad->stops);
+               free(grad);
+               grad = next;
+       }
+}
+
+static void nsvg__deleteParser(NSVGparser* p)
+{
+       if (p != NULL) {
+               nsvg__deletePaths(p->plist);
+               nsvg__deleteGradientData(p->gradients);
+               nsvgDelete(p->image);
+               free(p->pts);
+               free(p);
+       }
+}
+
+static void nsvg__resetPath(NSVGparser* p)
+{
+       p->npts = 0;
+}
+
+static void nsvg__addPoint(NSVGparser* p, float x, float y)
+{
+       if (p->npts+1 > p->cpts) {
+               p->cpts = p->cpts ? p->cpts*2 : 8;
+               p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float));
+               if (!p->pts) return;
+       }
+       p->pts[p->npts*2+0] = x;
+       p->pts[p->npts*2+1] = y;
+       p->npts++;
+}
+
+static void nsvg__moveTo(NSVGparser* p, float x, float y)
+{
+       if (p->npts > 0) {
+               p->pts[(p->npts-1)*2+0] = x;
+               p->pts[(p->npts-1)*2+1] = y;
+       } else {
+               nsvg__addPoint(p, x, y);
+       }
+}
+
+static void nsvg__lineTo(NSVGparser* p, float x, float y)
+{
+       float px,py, dx,dy;
+       if (p->npts > 0) {
+               px = p->pts[(p->npts-1)*2+0];
+               py = p->pts[(p->npts-1)*2+1];
+               dx = x - px;
+               dy = y - py;
+               nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f);
+               nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f);
+               nsvg__addPoint(p, x, y);
+       }
+}
+
+static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float 
cpx2, float cpy2, float x, float y)
+{
+       nsvg__addPoint(p, cpx1, cpy1);
+       nsvg__addPoint(p, cpx2, cpy2);
+       nsvg__addPoint(p, x, y);
+}
+
+static NSVGattrib* nsvg__getAttr(NSVGparser* p)
+{
+       return &p->attr[p->attrHead];
+}
+
+static void nsvg__pushAttr(NSVGparser* p)
+{
+       if (p->attrHead < NSVG_MAX_ATTR-1) {
+               p->attrHead++;
+               memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], 
sizeof(NSVGattrib));
+       }
+}
+
+static void nsvg__popAttr(NSVGparser* p)
+{
+       if (p->attrHead > 0)
+               p->attrHead--;
+}
+
+static float nsvg__actualOrigX(NSVGparser* p)
+{
+       return p->viewMinx;
+}
+
+static float nsvg__actualOrigY(NSVGparser* p)
+{
+       return p->viewMiny;
+}
+
+static float nsvg__actualWidth(NSVGparser* p)
+{
+       return p->viewWidth;
+}
+
+static float nsvg__actualHeight(NSVGparser* p)
+{
+       return p->viewHeight;
+}
+
+static float nsvg__actualLength(NSVGparser* p)
+{
+       float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p);
+       return sqrtf(w*w + h*h) / sqrtf(2.0f);
+}
+
+static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float 
orig, float length)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       switch (c.units) {
+               case NSVG_UNITS_USER:           return c.value;
+               case NSVG_UNITS_PX:                     return c.value;
+               case NSVG_UNITS_PT:                     return c.value / 72.0f 
* p->dpi;
+               case NSVG_UNITS_PC:                     return c.value / 6.0f * 
p->dpi;
+               case NSVG_UNITS_MM:                     return c.value / 25.4f 
* p->dpi;
+               case NSVG_UNITS_CM:                     return c.value / 2.54f 
* p->dpi;
+               case NSVG_UNITS_IN:                     return c.value * p->dpi;
+               case NSVG_UNITS_EM:                     return c.value * 
attr->fontSize;
+               case NSVG_UNITS_EX:                     return c.value * 
attr->fontSize * 0.52f; // x-height of Helvetica.
+               case NSVG_UNITS_PERCENT:        return orig + c.value / 100.0f 
* length;
+               default:                                        return c.value;
+       }
+       return c.value;
+}
+
+static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id)
+{
+       NSVGgradientData* grad = p->gradients;
+       while (grad) {
+               if (strcmp(grad->id, id) == 0)
+                       return grad;
+               grad = grad->next;
+       }
+       return NULL;
+}
+
+static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const 
float* localBounds, char* paintType)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       NSVGgradientData* data = NULL;
+       NSVGgradientData* ref = NULL;
+       NSVGgradientStop* stops = NULL;
+       NSVGgradient* grad;
+       float ox, oy, sw, sh, sl;
+       int nstops = 0;
+
+       data = nsvg__findGradientData(p, id);
+       if (data == NULL) return NULL;
+
+       // TODO: use ref to fill in all unset values too.
+       ref = data;
+       while (ref != NULL) {
+               if (stops == NULL && ref->stops != NULL) {
+                       stops = ref->stops;
+                       nstops = ref->nstops;
+                       break;
+               }
+               ref = nsvg__findGradientData(p, ref->ref);
+       }
+       if (stops == NULL) return NULL;
+
+       grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + 
sizeof(NSVGgradientStop)*(nstops-1));
+       if (grad == NULL) return NULL;
+
+       // The shape width and height.
+       if (data->units == NSVG_OBJECT_SPACE) {
+               ox = localBounds[0];
+               oy = localBounds[1];
+               sw = localBounds[2] - localBounds[0];
+               sh = localBounds[3] - localBounds[1];
+       } else {
+               ox = nsvg__actualOrigX(p);
+               oy = nsvg__actualOrigY(p);
+               sw = nsvg__actualWidth(p);
+               sh = nsvg__actualHeight(p);
+       }
+       sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f);
+
+       if (data->type == NSVG_PAINT_LINEAR_GRADIENT) {
+               float x1, y1, x2, y2, dx, dy;
+               x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw);
+               y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh);
+               x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw);
+               y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh);
+               // Calculate transform aligned to the line
+               dx = x2 - x1;
+               dy = y2 - y1;
+               grad->xform[0] = dy; grad->xform[1] = -dx;
+               grad->xform[2] = dx; grad->xform[3] = dy;
+               grad->xform[4] = x1; grad->xform[5] = y1;
+       } else {
+               float cx, cy, fx, fy, r;
+               cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw);
+               cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh);
+               fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw);
+               fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh);
+               r = nsvg__convertToPixels(p, data->radial.r, 0, sl);
+               // Calculate transform aligned to the circle
+               grad->xform[0] = r; grad->xform[1] = 0;
+               grad->xform[2] = 0; grad->xform[3] = r;
+               grad->xform[4] = cx; grad->xform[5] = cy;
+               grad->fx = fx / r;
+               grad->fy = fy / r;
+       }
+
+       nsvg__xformMultiply(grad->xform, data->xform);
+       nsvg__xformMultiply(grad->xform, attr->xform);
+
+       grad->spread = data->spread;
+       memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop));
+       grad->nstops = nstops;
+
+       *paintType = data->type;
+
+       return grad;
+}
+
+static float nsvg__getAverageScale(float* t)
+{
+       float sx = sqrtf(t[0]*t[0] + t[2]*t[2]);
+       float sy = sqrtf(t[1]*t[1] + t[3]*t[3]);
+       return (sx + sy) * 0.5f;
+}
+
+static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform)
+{
+       NSVGpath* path;
+       float curve[4*2], curveBounds[4];
+       int i, first = 1;
+       for (path = shape->paths; path != NULL; path = path->next) {
+               nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], 
path->pts[1], xform);
+               for (i = 0; i < path->npts-1; i += 3) {
+                       nsvg__xformPoint(&curve[2], &curve[3], 
path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform);
+                       nsvg__xformPoint(&curve[4], &curve[5], 
path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform);
+                       nsvg__xformPoint(&curve[6], &curve[7], 
path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform);
+                       nsvg__curveBounds(curveBounds, curve);
+                       if (first) {
+                               bounds[0] = curveBounds[0];
+                               bounds[1] = curveBounds[1];
+                               bounds[2] = curveBounds[2];
+                               bounds[3] = curveBounds[3];
+                               first = 0;
+                       } else {
+                               bounds[0] = nsvg__minf(bounds[0], 
curveBounds[0]);
+                               bounds[1] = nsvg__minf(bounds[1], 
curveBounds[1]);
+                               bounds[2] = nsvg__maxf(bounds[2], 
curveBounds[2]);
+                               bounds[3] = nsvg__maxf(bounds[3], 
curveBounds[3]);
+                       }
+                       curve[0] = curve[6];
+                       curve[1] = curve[7];
+               }
+       }
+}
+
+static void nsvg__addShape(NSVGparser* p)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       float scale = 1.0f;
+       NSVGshape* shape;
+       NSVGpath* path;
+       int i;
+
+       if (p->plist == NULL)
+               return;
+
+       shape = (NSVGshape*)malloc(sizeof(NSVGshape));
+       if (shape == NULL) goto error;
+       memset(shape, 0, sizeof(NSVGshape));
+
+       memcpy(shape->id, attr->id, sizeof shape->id);
+       scale = nsvg__getAverageScale(attr->xform);
+       shape->strokeWidth = attr->strokeWidth * scale;
+       shape->strokeDashOffset = attr->strokeDashOffset * scale;
+       shape->strokeDashCount = (char)attr->strokeDashCount;
+       for (i = 0; i < attr->strokeDashCount; i++)
+               shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale;
+       shape->strokeLineJoin = attr->strokeLineJoin;
+       shape->strokeLineCap = attr->strokeLineCap;
+       shape->miterLimit = attr->miterLimit;
+       shape->fillRule = attr->fillRule;
+       shape->opacity = attr->opacity;
+
+       shape->paths = p->plist;
+       p->plist = NULL;
+
+       // Calculate shape bounds
+       shape->bounds[0] = shape->paths->bounds[0];
+       shape->bounds[1] = shape->paths->bounds[1];
+       shape->bounds[2] = shape->paths->bounds[2];
+       shape->bounds[3] = shape->paths->bounds[3];
+       for (path = shape->paths->next; path != NULL; path = path->next) {
+               shape->bounds[0] = nsvg__minf(shape->bounds[0], 
path->bounds[0]);
+               shape->bounds[1] = nsvg__minf(shape->bounds[1], 
path->bounds[1]);
+               shape->bounds[2] = nsvg__maxf(shape->bounds[2], 
path->bounds[2]);
+               shape->bounds[3] = nsvg__maxf(shape->bounds[3], 
path->bounds[3]);
+       }
+
+       // Set fill
+       if (attr->hasFill == 0) {
+               shape->fill.type = NSVG_PAINT_NONE;
+       } else if (attr->hasFill == 1) {
+               shape->fill.type = NSVG_PAINT_COLOR;
+               shape->fill.color = attr->fillColor;
+               shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 
24;
+       } else if (attr->hasFill == 2) {
+               float inv[6], localBounds[4];
+               nsvg__xformInverse(inv, attr->xform);
+               nsvg__getLocalBounds(localBounds, shape, inv);
+               shape->fill.gradient = nsvg__createGradient(p, 
attr->fillGradient, localBounds, &shape->fill.type);
+               if (shape->fill.gradient == NULL) {
+                       shape->fill.type = NSVG_PAINT_NONE;
+               }
+       }
+
+       // Set stroke
+       if (attr->hasStroke == 0) {
+               shape->stroke.type = NSVG_PAINT_NONE;
+       } else if (attr->hasStroke == 1) {
+               shape->stroke.type = NSVG_PAINT_COLOR;
+               shape->stroke.color = attr->strokeColor;
+               shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) 
<< 24;
+       } else if (attr->hasStroke == 2) {
+               float inv[6], localBounds[4];
+               nsvg__xformInverse(inv, attr->xform);
+               nsvg__getLocalBounds(localBounds, shape, inv);
+               shape->stroke.gradient = nsvg__createGradient(p, 
attr->strokeGradient, localBounds, &shape->stroke.type);
+               if (shape->stroke.gradient == NULL)
+                       shape->stroke.type = NSVG_PAINT_NONE;
+       }
+
+       // Set flags
+       shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00);
+
+       // Add to tail
+       if (p->image->shapes == NULL)
+               p->image->shapes = shape;
+       else
+               p->shapesTail->next = shape;
+       p->shapesTail = shape;
+
+       return;
+
+error:
+       if (shape) free(shape);
+}
+
+static void nsvg__addPath(NSVGparser* p, char closed)
+{
+       NSVGattrib* attr = nsvg__getAttr(p);
+       NSVGpath* path = NULL;
+       float bounds[4];
+       float* curve;
+       int i;
+
+       if (p->npts < 4)
+               return;
+
+       if (closed)
+               nsvg__lineTo(p, p->pts[0], p->pts[1]);
+
+       path = (NSVGpath*)malloc(sizeof(NSVGpath));
+       if (path == NULL) goto error;
+       memset(path, 0, sizeof(NSVGpath));
+
+       path->pts = (float*)malloc(p->npts*2*sizeof(float));
+       if (path->pts == NULL) goto error;
+       path->closed = closed;
+       path->npts = p->npts;
+
+       // Transform path.
+       for (i = 0; i < p->npts; ++i)
+               nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], 
p->pts[i*2], p->pts[i*2+1], attr->xform);
+
+       // Find bounds
+       for (i = 0; i < path->npts-1; i += 3) {
+               curve = &path->pts[i*2];
+               nsvg__curveBounds(bounds, curve);
+               if (i == 0) {
+                       path->bounds[0] = bounds[0];
+                       path->bounds[1] = bounds[1];
+                       path->bounds[2] = bounds[2];
+                       path->bounds[3] = bounds[3];
+               } else {
+                       path->bounds[0] = nsvg__minf(path->bounds[0], 
bounds[0]);
+                       path->bounds[1] = nsvg__minf(path->bounds[1], 
bounds[1]);
+                       path->bounds[2] = nsvg__maxf(path->bounds[2], 
bounds[2]);
+                       path->bounds[3] = nsvg__maxf(path->bounds[3], 
bounds[3]);
+               }
+       }
+
+       path->next = p->plist;
+       p->plist = path;
+
+       return;
+
+error:
+       if (path != NULL) {
+               if (path->pts != NULL) free(path->pts);
+               free(path);
+       }
+}
+
+// We roll our own string to float because the std library one uses locale and 
messes things up.
+static double nsvg__atof(const char* s)
+{
+       char* cur = (char*)s;
+       char* end = NULL;
+       double res = 0.0, sign = 1.0;
+       long long intPart = 0, fracPart = 0;
+       char hasIntPart = 0, hasFracPart = 0;
+
+       // Parse optional sign
+       if (*cur == '+') {
+               cur++;
+       } else if (*cur == '-') {
+               sign = -1;
+               cur++;
+       }
+
+       // Parse integer part
+       if (nsvg__isdigit(*cur)) {
+               // Parse digit sequence
+               intPart = strtoll(cur, &end, 10);
+               if (cur != end) {
+                       res = (double)intPart;
+                       hasIntPart = 1;
+                       cur = end;
+               }
+       }
+
+       // Parse fractional part.
+       if (*cur == '.') {
+               cur++; // Skip '.'
+               if (nsvg__isdigit(*cur)) {
+                       // Parse digit sequence
+                       fracPart = strtoll(cur, &end, 10);
+                       if (cur != end) {
+                               res += (double)fracPart / pow(10.0, 
(double)(end - cur));
+                               hasFracPart = 1;
+                               cur = end;
+                       }
+               }
+       }
+
+       // A valid number should have integer or fractional part.
+       if (!hasIntPart && !hasFracPart)
+               return 0.0;
+
+       // Parse optional exponent
+       if (*cur == 'e' || *cur == 'E') {
+               long expPart = 0;
+               cur++; // skip 'E'
+               expPart = strtol(cur, &end, 10); // Parse digit sequence with 
sign
+               if (cur != end) {
+                       res *= pow(10.0, (double)expPart);
+               }
+       }
+
+       return res * sign;
+}
+
+
+static const char* nsvg__parseNumber(const char* s, char* it, const int size)
+{
+       const int last = size-1;
+       int i = 0;
+
+       // sign
+       if (*s == '-' || *s == '+') {
+               if (i < last) it[i++] = *s;
+               s++;
+       }
+       // integer part
+       while (*s && nsvg__isdigit(*s)) {
+               if (i < last) it[i++] = *s;
+               s++;
+       }
+       if (*s == '.') {
+               // decimal point
+               if (i < last) it[i++] = *s;
+               s++;
+               // fraction part
+               while (*s && nsvg__isdigit(*s)) {
+                       if (i < last) it[i++] = *s;
+                       s++;
+               }
+       }
+       // exponent
+       if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) {
+               if (i < last) it[i++] = *s;
+               s++;
+               if (*s == '-' || *s == '+') {
+                       if (i < last) it[i++] = *s;
+                       s++;
+               }
+               while (*s && nsvg__isdigit(*s)) {
+                       if (i < last) it[i++] = *s;
+                       s++;
+               }
+       }
+       it[i] = '\0';
+
+       return s;
+}
+
+static const char* nsvg__getNextPathItem(const char* s, char* it)
+{
+       it[0] = '\0';
+       // Skip white spaces and commas
+       while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
+       if (!*s) return s;
+       if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) {
+               s = nsvg__parseNumber(s, it, 64);
+       } else {
+               // Parse command
+               it[0] = *s++;
+               it[1] = '\0';
+               return s;
+       }
+
+       return s;
+}
+
+static unsigned int nsvg__parseColorHex(const char* str)
+{
+       unsigned int c = 0, r = 0, g = 0, b = 0;
+       int n = 0;
+       str++; // skip #
+       // Calculate number of characters.
+       while(str[n] && !nsvg__isspace(str[n]))
+               n++;
+       if (n == 6) {
+               sscanf(str, "%x", &c);
+       } else if (n == 3) {
+               sscanf(str, "%x", &c);
+               c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8);
+               c |= c<<4;
+       }
+       r = (c >> 16) & 0xff;
+       g = (c >> 8) & 0xff;
+       b = c & 0xff;
+       return NSVG_RGB(r,g,b);
+}
+
+static unsigned int nsvg__parseColorRGB(const char* str)
+{
+       int r = -1, g = -1, b = -1;
+       char s1[32]="", s2[32]="";
+       sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b);
+       if (strchr(s1, '%')) {
+               return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100);
+       } else {
+               return NSVG_RGB(r,g,b);
+       }
+}
+
+typedef struct NSVGNamedColor {
+       const char* name;
+       unsigned int color;
+} NSVGNamedColor;
+
+NSVGNamedColor nsvg__colors[] = {
+
+       { "red", NSVG_RGB(255, 0, 0) },
+       { "green", NSVG_RGB( 0, 128, 0) },
+       { "blue", NSVG_RGB( 0, 0, 255) },
+       { "yellow", NSVG_RGB(255, 255, 0) },
+       { "cyan", NSVG_RGB( 0, 255, 255) },
+       { "magenta", NSVG_RGB(255, 0, 255) },
+       { "black", NSVG_RGB( 0, 0, 0) },
+       { "grey", NSVG_RGB(128, 128, 128) },
+       { "gray", NSVG_RGB(128, 128, 128) },
+       { "white", NSVG_RGB(255, 255, 255) },
+
+#ifdef NANOSVG_ALL_COLOR_KEYWORDS
+       { "aliceblue", NSVG_RGB(240, 248, 255) },
+       { "antiquewhite", NSVG_RGB(250, 235, 215) },
+       { "aqua", NSVG_RGB( 0, 255, 255) },
+       { "aquamarine", NSVG_RGB(127, 255, 212) },
+       { "azure", NSVG_RGB(240, 255, 255) },
+       { "beige", NSVG_RGB(245, 245, 220) },
+       { "bisque", NSVG_RGB(255, 228, 196) },
+       { "blanchedalmond", NSVG_RGB(255, 235, 205) },
+       { "blueviolet", NSVG_RGB(138, 43, 226) },
+       { "brown", NSVG_RGB(165, 42, 42) },
+       { "burlywood", NSVG_RGB(222, 184, 135) },
+       { "cadetblue", NSVG_RGB( 95, 158, 160) },
+       { "chartreuse", NSVG_RGB(127, 255, 0) },
+       { "chocolate", NSVG_RGB(210, 105, 30) },
+       { "coral", NSVG_RGB(255, 127, 80) },
+       { "cornflowerblue", NSVG_RGB(100, 149, 237) },
+       { "cornsilk", NSVG_RGB(255, 248, 220) },
+       { "crimson", NSVG_RGB(220, 20, 60) },
+       { "darkblue", NSVG_RGB( 0, 0, 139) },
+       { "darkcyan", NSVG_RGB( 0, 139, 139) },
+       { "darkgoldenrod", NSVG_RGB(184, 134, 11) },
+       { "darkgray", NSVG_RGB(169, 169, 169) },
+       { "darkgreen", NSVG_RGB( 0, 100, 0) },
+       { "darkgrey", NSVG_RGB(169, 169, 169) },
+       { "darkkhaki", NSVG_RGB(189, 183, 107) },
+       { "darkmagenta", NSVG_RGB(139, 0, 139) },
+       { "darkolivegreen", NSVG_RGB( 85, 107, 47) },
+       { "darkorange", NSVG_RGB(255, 140, 0) },
+       { "darkorchid", NSVG_RGB(153, 50, 204) },
+       { "darkred", NSVG_RGB(139, 0, 0) },
+       { "darksalmon", NSVG_RGB(233, 150, 122) },
+       { "darkseagreen", NSVG_RGB(143, 188, 143) },
+       { "darkslateblue", NSVG_RGB( 72, 61, 139) },
+       { "darkslategray", NSVG_RGB( 47, 79, 79) },
+       { "darkslategrey", NSVG_RGB( 47, 79, 79) },
+       { "darkturquoise", NSVG_RGB( 0, 206, 209) },
+       { "darkviolet", NSVG_RGB(148, 0, 211) },
+       { "deeppink", NSVG_RGB(255, 20, 147) },
+       { "deepskyblue", NSVG_RGB( 0, 191, 255) },
+       { "dimgray", NSVG_RGB(105, 105, 105) },
+       { "dimgrey", NSVG_RGB(105, 105, 105) },
+       { "dodgerblue", NSVG_RGB( 30, 144, 255) },
+       { "firebrick", NSVG_RGB(178, 34, 34) },
+       { "floralwhite", NSVG_RGB(255, 250, 240) },
+       { "forestgreen", NSVG_RGB( 34, 139, 34) },
+       { "fuchsia", NSVG_RGB(255, 0, 255) },
+       { "gainsboro", NSVG_RGB(220, 220, 220) },
+       { "ghostwhite", NSVG_RGB(248, 248, 255) },
+       { "gold", NSVG_RGB(255, 215, 0) },
+       { "goldenrod", NSVG_RGB(218, 165, 32) },
+       { "greenyellow", NSVG_RGB(173, 255, 47) },
+       { "honeydew", NSVG_RGB(240, 255, 240) },
+       { "hotpink", NSVG_RGB(255, 105, 180) },
+       { "indianred", NSVG_RGB(205, 92, 92) },
+       { "indigo", NSVG_RGB( 75, 0, 130) },
+       { "ivory", NSVG_RGB(255, 255, 240) },
+       { "khaki", NSVG_RGB(240, 230, 140) },
+       { "lavender", NSVG_RGB(230, 230, 250) },
+       { "lavenderblush", NSVG_RGB(255, 240, 245) },
+       { "lawngreen", NSVG_RGB(124, 252, 0) },
+       { "lemonchiffon", NSVG_RGB(255, 250, 205) },
+       { "lightblue", NSVG_RGB(173, 216, 230) },
+       { "lightcoral", NSVG_RGB(240, 128, 128) },
+       { "lightcyan", NSVG_RGB(224, 255, 255) },
+       { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) },
+       { "lightgray", NSVG_RGB(211, 211, 211) },
+       { "lightgreen", NSVG_RGB(144, 238, 144) },
+       { "lightgrey", NSVG_RGB(211, 211, 211) },
+       { "lightpink", NSVG_RGB(255, 182, 193) },
+       { "lightsalmon", NSVG_RGB(255, 160, 122) },
+       { "lightseagreen", NSVG_RGB( 32, 178, 170) },
+       { "lightskyblue", NSVG_RGB(135, 206, 250) },
+       { "lightslategray", NSVG_RGB(119, 136, 153) },
+       { "lightslategrey", NSVG_RGB(119, 136, 153) },
+       { "lightsteelblue", NSVG_RGB(176, 196, 222) },
+       { "lightyellow", NSVG_RGB(255, 255, 224) },
+       { "lime", NSVG_RGB( 0, 255, 0) },
+       { "limegreen", NSVG_RGB( 50, 205, 50) },
+       { "linen", NSVG_RGB(250, 240, 230) },
+       { "maroon", NSVG_RGB(128, 0, 0) },
+       { "mediumaquamarine", NSVG_RGB(102, 205, 170) },
+       { "mediumblue", NSVG_RGB( 0, 0, 205) },
+       { "mediumorchid", NSVG_RGB(186, 85, 211) },
+       { "mediumpurple", NSVG_RGB(147, 112, 219) },
+       { "mediumseagreen", NSVG_RGB( 60, 179, 113) },
+       { "mediumslateblue", NSVG_RGB(123, 104, 238) },
+       { "mediumspringgreen", NSVG_RGB( 0, 250, 154) },
+       { "mediumturquoise", NSVG_RGB( 72, 209, 204) },
+       { "mediumvioletred", NSVG_RGB(199, 21, 133) },
+       { "midnightblue", NSVG_RGB( 25, 25, 112) },
+       { "mintcream", NSVG_RGB(245, 255, 250) },
+       { "mistyrose", NSVG_RGB(255, 228, 225) },
+       { "moccasin", NSVG_RGB(255, 228, 181) },
+       { "navajowhite", NSVG_RGB(255, 222, 173) },
+       { "navy", NSVG_RGB( 0, 0, 128) },
+       { "oldlace", NSVG_RGB(253, 245, 230) },
+       { "olive", NSVG_RGB(128, 128, 0) },
+       { "olivedrab", NSVG_RGB(107, 142, 35) },
+       { "orange", NSVG_RGB(255, 165, 0) },
+       { "orangered", NSVG_RGB(255, 69, 0) },
+       { "orchid", NSVG_RGB(218, 112, 214) },
+       { "palegoldenrod", NSVG_RGB(238, 232, 170) },
+       { "palegreen", NSVG_RGB(152, 251, 152) },
+       { "paleturquoise", NSVG_RGB(175, 238, 238) },
+       { "palevioletred", NSVG_RGB(219, 112, 147) },
+       { "papayawhip", NSVG_RGB(255, 239, 213) },
+       { "peachpuff", NSVG_RGB(255, 218, 185) },
+       { "peru", NSVG_RGB(205, 133, 63) },
+       { "pink", NSVG_RGB(255, 192, 203) },
+       { "plum", NSVG_RGB(221, 160, 221) },
+       { "powderblue", NSVG_RGB(176, 224, 230) },
+       { "purple", NSVG_RGB(128, 0, 128) },
+       { "rosybrown", NSVG_RGB(188, 143, 143) },
+       { "royalblue", NSVG_RGB( 65, 105, 225) },
+       { "saddlebrown", NSVG_RGB(139, 69, 19) },
+       { "salmon", NSVG_RGB(250, 128, 114) },
+       { "sandybrown", NSVG_RGB(244, 164, 96) },
+       { "seagreen", NSVG_RGB( 46, 139, 87) },
+       { "seashell", NSVG_RGB(255, 245, 238) },
+       { "sienna", NSVG_RGB(160, 82, 45) },
+       { "silver", NSVG_RGB(192, 192, 192) },
+       { "skyblue", NSVG_RGB(135, 206, 235) },
+       { "slateblue", NSVG_RGB(106, 90, 205) },
+       { "slategray", NSVG_RGB(112, 128, 144) },
+       { "slategrey", NSVG_RGB(112, 128, 144) },
+       { "snow", NSVG_RGB(255, 250, 250) },
+       { "springgreen", NSVG_RGB( 0, 255, 127) },
+       { "steelblue", NSVG_RGB( 70, 130, 180) },
+       { "tan", NSVG_RGB(210, 180, 140) },
+       { "teal", NSVG_RGB( 0, 128, 128) },
+       { "thistle", NSVG_RGB(216, 191, 216) },
+       { "tomato", NSVG_RGB(255, 99, 71) },
+       { "turquoise", NSVG_RGB( 64, 224, 208) },
+       { "violet", NSVG_RGB(238, 130, 238) },
+       { "wheat", NSVG_RGB(245, 222, 179) },
+       { "whitesmoke", NSVG_RGB(245, 245, 245) },
+       { "yellowgreen", NSVG_RGB(154, 205, 50) },
+#endif
+};
+
+static unsigned int nsvg__parseColorName(const char* str)
+{
+       int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor);
+
+       for (i = 0; i < ncolors; i++) {
+               if (strcmp(nsvg__colors[i].name, str) == 0) {
+                       return nsvg__colors[i].color;
+               }
+       }
+
+       return NSVG_RGB(128, 128, 128);
+}
+
+static unsigned int nsvg__parseColor(const char* str)
+{
+       size_t len = 0;
+       while(*str == ' ') ++str;
+       len = strlen(str);
+       if (len >= 1 && *str == '#')
+               return nsvg__parseColorHex(str);
+       else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && 
str[3] == '(')
+               return nsvg__parseColorRGB(str);
+       return nsvg__parseColorName(str);
+}
+
+static float nsvg__parseOpacity(const char* str)
+{
+       float val = nsvg__atof(str);
+       if (val < 0.0f) val = 0.0f;
+       if (val > 1.0f) val = 1.0f;
+       return val;
+}
+
+static float nsvg__parseMiterLimit(const char* str)
+{
+       float val = nsvg__atof(str);
+       if (val < 0.0f) val = 0.0f;
+       return val;
+}
+
+static int nsvg__parseUnits(const char* units)
+{
+       if (units[0] == 'p' && units[1] == 'x')
+               return NSVG_UNITS_PX;
+       else if (units[0] == 'p' && units[1] == 't')
+               return NSVG_UNITS_PT;
+       else if (units[0] == 'p' && units[1] == 'c')
+               return NSVG_UNITS_PC;
+       else if (units[0] == 'm' && units[1] == 'm')
+               return NSVG_UNITS_MM;
+       else if (units[0] == 'c' && units[1] == 'm')
+               return NSVG_UNITS_CM;
+       else if (units[0] == 'i' && units[1] == 'n')
+               return NSVG_UNITS_IN;
+       else if (units[0] == '%')
+               return NSVG_UNITS_PERCENT;
+       else if (units[0] == 'e' && units[1] == 'm')
+               return NSVG_UNITS_EM;
+       else if (units[0] == 'e' && units[1] == 'x')
+               return NSVG_UNITS_EX;
+       return NSVG_UNITS_USER;
+}
+
+static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
+{
+       NSVGcoordinate coord = {0, NSVG_UNITS_USER};
+       char buf[64];
+       coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64));
+       coord.value = nsvg__atof(buf);
+       return coord;
+}
+
+static NSVGcoordinate nsvg__coord(float v, int units)
+{
+       NSVGcoordinate coord = {v, units};
+       return coord;
+}
+
+static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, 
float length)
+{
+       NSVGcoordinate coord = nsvg__parseCoordinateRaw(str);
+       return nsvg__convertToPixels(p, coord, orig, length);
+}
+
+static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, 
int* na)
+{
+       const char* end;
+       const char* ptr;
+       char it[64];
+
+       *na = 0;
+       ptr = str;
+       while (*ptr && *ptr != '(') ++ptr;
+       if (*ptr == 0)
+               return 1;
+       end = ptr;
+       while (*end && *end != ')') ++end;
+       if (*end == 0)
+               return 1;
+
+       while (ptr < end) {
+               if (*ptr == '-' || *ptr == '+' || *ptr == '.' || 
nsvg__isdigit(*ptr)) {
+                       if (*na >= maxNa) return 0;
+                       ptr = nsvg__parseNumber(ptr, it, 64);
+                       args[(*na)++] = (float)nsvg__atof(it);
+               } else {
+                       ++ptr;
+               }
+       }
+       return (int)(end - str);
+}
+
+
+static int nsvg__parseMatrix(float* xform, const char* str)
+{
+       float t[6];
+       int na = 0;
+       int len = nsvg__parseTransformArgs(str, t, 6, &na);
+       if (na != 6) return len;
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseTranslate(float* xform, const char* str)
+{
+       float args[2];
+       float t[6];
+       int na = 0;
+       int len = nsvg__parseTransformArgs(str, args, 2, &na);
+       if (na == 1) args[1] = 0.0;
+
+       nsvg__xformSetTranslation(t, args[0], args[1]);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseScale(float* xform, const char* str)
+{
+       float args[2];
+       int na = 0;
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 2, &na);
+       if (na == 1) args[1] = args[0];
+       nsvg__xformSetScale(t, args[0], args[1]);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseSkewX(float* xform, const char* str)
+{
+       float args[1];
+       int na = 0;
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 1, &na);
+       nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseSkewY(float* xform, const char* str)
+{
+       float args[1];
+       int na = 0;
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 1, &na);
+       nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI);
+       memcpy(xform, t, sizeof(float)*6);
+       return len;
+}
+
+static int nsvg__parseRotate(float* xform, const char* str)
+{
+       float args[3];
+       int na = 0;
+       float m[6];
+       float t[6];
+       int len = nsvg__parseTransformArgs(str, args, 3, &na);
+       if (na == 1)
+               args[1] = args[2] = 0.0f;
+       nsvg__xformIdentity(m);
+
+       if (na > 1) {
+               nsvg__xformSetTranslation(t, -args[1], -args[2]);
+               nsvg__xformMultiply(m, t);
+       }
+
+       nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI);
+       nsvg__xformMultiply(m, t);
+
+       if (na > 1) {
+               nsvg__xformSetTranslation(t, args[1], args[2]);
+               nsvg__xformMultiply(m, t);
+       }
+
+       memcpy(xform, m, sizeof(float)*6);
+
+       return len;
+}
+
+static void nsvg__parseTransform(float* xform, const char* str)
+{
+       float t[6];
+       nsvg__xformIdentity(xform);
+       while (*str)
+       {
+               if (strncmp(str, "matrix", 6) == 0)
+                       str += nsvg__parseMatrix(t, str);
+               else if (strncmp(str, "translate", 9) == 0)
+                       str += nsvg__parseTranslate(t, str);
+               else if (strncmp(str, "scale", 5) == 0)
+                       str += nsvg__parseScale(t, str);
+               else if (strncmp(str, "rotate", 6) == 0)
+                       str += nsvg__parseRotate(t, str);
+               else if (strncmp(str, "skewX", 5) == 0)
+                       str += nsvg__parseSkewX(t, str);
+               else if (strncmp(str, "skewY", 5) == 0)
+                       str += nsvg__parseSkewY(t, str);
+               else{
+                       ++str;
+                       continue;
+               }
+
+               nsvg__xformPremultiply(xform, t);
+       }
+}
+
+static void nsvg__parseUrl(char* id, const char* str)
+{
+       int i = 0;
+       str += 4; // "url(";
+       if (*str == '#')
+               str++;
+       while (i < 63 && *str != ')') {
+               id[i] = *str++;
+               i++;
+       }
+       id[i] = '\0';
+}
+
+static char nsvg__parseLineCap(const char* str)
+{
+       if (strcmp(str, "butt") == 0)
+               return NSVG_CAP_BUTT;
+       else if (strcmp(str, "round") == 0)
+               return NSVG_CAP_ROUND;
+       else if (strcmp(str, "square") == 0)
+               return NSVG_CAP_SQUARE;
+       // TODO: handle inherit.
+       return NSVG_CAP_BUTT;
+}
+
+static char nsvg__parseLineJoin(const char* str)
+{
+       if (strcmp(str, "miter") == 0)
+               return NSVG_JOIN_MITER;
+       else if (strcmp(str, "round") == 0)
+               return NSVG_JOIN_ROUND;
+       else if (strcmp(str, "bevel") == 0)
+               return NSVG_JOIN_BEVEL;
+       // TODO: handle inherit.
+       return NSVG_JOIN_MITER;
+}
+
+static char nsvg__parseFillRule(const char* str)
+{
+       if (strcmp(str, "nonzero") == 0)
+               return NSVG_FILLRULE_NONZERO;
+       else if (strcmp(str, "evenodd") == 0)
+               return NSVG_FILLRULE_EVENODD;
+       // TODO: handle inherit.
+       return NSVG_FILLRULE_NONZERO;
+}
+
+static const char* nsvg__getNextDashItem(const char* s, char* it)
+{
+       int n = 0;
+       it[0] = '\0';
+       // Skip white spaces and commas
+       while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
+       // Advance until whitespace, comma or end.
+       while (*s && (!nsvg__isspace(*s) && *s != ',')) {
+               if (n < 63)
+                       it[n++] = *s;
+               s++;
+       }
+       it[n++] = '\0';
+       return s;
+}
+
+static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* 
strokeDashArray)
+{
+       char item[64];
+       int count = 0, i;
+       float sum = 0.0f;
+
+       // Handle "none"
+       if (str[0] == 'n')
+               return 0;
+
+       // Parse dashes
+       while (*str) {
+               str = nsvg__getNextDashItem(str, item);
+               if (!*item) break;
+               if (count < NSVG_MAX_DASHES)
+                       strokeDashArray[count++] = 
fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p)));
+       }
+
+       for (i = 0; i < count; i++)
+               sum += strokeDashArray[i];
+       if (sum <= 1e-6f)
+               count = 0;
+
+       return count;
+}
+
+static void nsvg__parseStyle(NSVGparser* p, const char* str);
+
+static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value)
+{
+       float xform[6];
+       NSVGattrib* attr = nsvg__getAttr(p);
+       if (!attr) return 0;
+
+       if (strcmp(name, "style") == 0) {
+               nsvg__parseStyle(p, value);
+       } else if (strcmp(name, "display") == 0) {
+               if (strcmp(value, "none") == 0)
+                       attr->visible = 0;
+               // Don't reset ->visible on display:inline, one display:none 
hides the whole subtree
+
+       } else if (strcmp(name, "fill") == 0) {
+               if (strcmp(value, "none") == 0) {
+                       attr->hasFill = 0;
+               } else if (strncmp(value, "url(", 4) == 0) {
+                       attr->hasFill = 2;
+                       nsvg__parseUrl(attr->fillGradient, value);
+               } else {
+                       attr->hasFill = 1;
+                       attr->fillColor = nsvg__parseColor(value);
+               }
+       } else if (strcmp(name, "opacity") == 0) {
+               attr->opacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "fill-opacity") == 0) {
+               attr->fillOpacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "stroke") == 0) {
+               if (strcmp(value, "none") == 0) {
+                       attr->hasStroke = 0;
+               } else if (strncmp(value, "url(", 4) == 0) {
+                       attr->hasStroke = 2;
+                       nsvg__parseUrl(attr->strokeGradient, value);
+               } else {
+                       attr->hasStroke = 1;
+                       attr->strokeColor = nsvg__parseColor(value);
+               }
+       } else if (strcmp(name, "stroke-width") == 0) {
+               attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, 
nsvg__actualLength(p));
+       } else if (strcmp(name, "stroke-dasharray") == 0) {
+               attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, 
attr->strokeDashArray);
+       } else if (strcmp(name, "stroke-dashoffset") == 0) {
+               attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, 
nsvg__actualLength(p));
+       } else if (strcmp(name, "stroke-opacity") == 0) {
+               attr->strokeOpacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "stroke-linecap") == 0) {
+               attr->strokeLineCap = nsvg__parseLineCap(value);
+       } else if (strcmp(name, "stroke-linejoin") == 0) {
+               attr->strokeLineJoin = nsvg__parseLineJoin(value);
+       } else if (strcmp(name, "stroke-miterlimit") == 0) {
+               attr->miterLimit = nsvg__parseMiterLimit(value);
+       } else if (strcmp(name, "fill-rule") == 0) {
+               attr->fillRule = nsvg__parseFillRule(value);
+       } else if (strcmp(name, "font-size") == 0) {
+               attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, 
nsvg__actualLength(p));
+       } else if (strcmp(name, "transform") == 0) {
+               nsvg__parseTransform(xform, value);
+               nsvg__xformPremultiply(attr->xform, xform);
+       } else if (strcmp(name, "stop-color") == 0) {
+               attr->stopColor = nsvg__parseColor(value);
+       } else if (strcmp(name, "stop-opacity") == 0) {
+               attr->stopOpacity = nsvg__parseOpacity(value);
+       } else if (strcmp(name, "offset") == 0) {
+               attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f);
+       } else if (strcmp(name, "id") == 0) {
+               strncpy(attr->id, value, 63);
+               attr->id[63] = '\0';
+       } else {
+               return 0;
+       }
+       return 1;
+}
+
+static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* 
end)
+{
+       const char* str;
+       const char* val;
+       char name[512];
+       char value[512];
+       int n;
+
+       str = start;
+       while (str < end && *str != ':') ++str;
+
+       val = str;
+
+       // Right Trim
+       while (str > start &&  (*str == ':' || nsvg__isspace(*str))) --str;
+       ++str;
+
+       n = (int)(str - start);
+       if (n > 511) n = 511;
+       if (n) memcpy(name, start, n);
+       name[n] = 0;
+
+       while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
+
+       n = (int)(end - val);
+       if (n > 511) n = 511;
+       if (n) memcpy(value, val, n);
+       value[n] = 0;
+
+       return nsvg__parseAttr(p, name, value);
+}
+
+static void nsvg__parseStyle(NSVGparser* p, const char* str)
+{
+       const char* start;
+       const char* end;
+
+       while (*str) {
+               // Left Trim
+               while(*str && nsvg__isspace(*str)) ++str;
+               start = str;
+               while(*str && *str != ';') ++str;
+               end = str;
+
+               // Right Trim
+               while (end > start &&  (*end == ';' || nsvg__isspace(*end))) 
--end;
+               ++end;
+
+               nsvg__parseNameValue(p, start, end);
+               if (*str) ++str;
+       }
+}
+
+static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
+{
+       int i;
+       for (i = 0; attr[i]; i += 2)
+       {
+               if (strcmp(attr[i], "style") == 0)
+                       nsvg__parseStyle(p, attr[i + 1]);
+               else
+                       nsvg__parseAttr(p, attr[i], attr[i + 1]);
+       }
+}
+
+static int nsvg__getArgsPerElement(char cmd)
+{
+       switch (cmd) {
+               case 'v':
+               case 'V':
+               case 'h':
+               case 'H':
+                       return 1;
+               case 'm':
+               case 'M':
+               case 'l':
+               case 'L':
+               case 't':
+               case 'T':
+                       return 2;
+               case 'q':
+               case 'Q':
+               case 's':
+               case 'S':
+                       return 4;
+               case 'c':
+               case 'C':
+                       return 6;
+               case 'a':
+               case 'A':
+                       return 7;
+       }
+       return 0;
+}
+
+static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* 
args, int rel)
+{
+       if (rel) {
+               *cpx += args[0];
+               *cpy += args[1];
+       } else {
+               *cpx = args[0];
+               *cpy = args[1];
+       }
+       nsvg__moveTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* 
args, int rel)
+{
+       if (rel) {
+               *cpx += args[0];
+               *cpy += args[1];
+       } else {
+               *cpx = args[0];
+               *cpy = args[1];
+       }
+       nsvg__lineTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* 
args, int rel)
+{
+       if (rel)
+               *cpx += args[0];
+       else
+               *cpx = args[0];
+       nsvg__lineTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* 
args, int rel)
+{
+       if (rel)
+               *cpy += args[0];
+       else
+               *cpy = args[0];
+       nsvg__lineTo(p, *cpx, *cpy);
+}
+
+static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy,
+                                                                float* cpx2, 
float* cpy2, float* args, int rel)
+{
+       float x2, y2, cx1, cy1, cx2, cy2;
+
+       if (rel) {
+               cx1 = *cpx + args[0];
+               cy1 = *cpy + args[1];
+               cx2 = *cpx + args[2];
+               cy2 = *cpy + args[3];
+               x2 = *cpx + args[4];
+               y2 = *cpy + args[5];
+       } else {
+               cx1 = args[0];
+               cy1 = args[1];
+               cx2 = args[2];
+               cy2 = args[3];
+               x2 = args[4];
+               y2 = args[5];
+       }
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx2;
+       *cpy2 = cy2;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy,
+                                                                         
float* cpx2, float* cpy2, float* args, int rel)
+{
+       float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
+
+       x1 = *cpx;
+       y1 = *cpy;
+       if (rel) {
+               cx2 = *cpx + args[0];
+               cy2 = *cpy + args[1];
+               x2 = *cpx + args[2];
+               y2 = *cpy + args[3];
+       } else {
+               cx2 = args[0];
+               cy2 = args[1];
+               x2 = args[2];
+               y2 = args[3];
+       }
+
+       cx1 = 2*x1 - *cpx2;
+       cy1 = 2*y1 - *cpy2;
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx2;
+       *cpy2 = cy2;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy,
+                                                               float* cpx2, 
float* cpy2, float* args, int rel)
+{
+       float x1, y1, x2, y2, cx, cy;
+       float cx1, cy1, cx2, cy2;
+
+       x1 = *cpx;
+       y1 = *cpy;
+       if (rel) {
+               cx = *cpx + args[0];
+               cy = *cpy + args[1];
+               x2 = *cpx + args[2];
+               y2 = *cpy + args[3];
+       } else {
+               cx = args[0];
+               cy = args[1];
+               x2 = args[2];
+               y2 = args[3];
+       }
+
+       // Convert to cubic bezier
+       cx1 = x1 + 2.0f/3.0f*(cx - x1);
+       cy1 = y1 + 2.0f/3.0f*(cy - y1);
+       cx2 = x2 + 2.0f/3.0f*(cx - x2);
+       cy2 = y2 + 2.0f/3.0f*(cy - y2);
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx;
+       *cpy2 = cy;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy,
+                                                                        float* 
cpx2, float* cpy2, float* args, int rel)
+{
+       float x1, y1, x2, y2, cx, cy;
+       float cx1, cy1, cx2, cy2;
+
+       x1 = *cpx;
+       y1 = *cpy;
+       if (rel) {
+               x2 = *cpx + args[0];
+               y2 = *cpy + args[1];
+       } else {
+               x2 = args[0];
+               y2 = args[1];
+       }
+
+       cx = 2*x1 - *cpx2;
+       cy = 2*y1 - *cpy2;
+
+       // Convert to cubix bezier
+       cx1 = x1 + 2.0f/3.0f*(cx - x1);
+       cy1 = y1 + 2.0f/3.0f*(cy - y1);
+       cx2 = x2 + 2.0f/3.0f*(cx - x2);
+       cy2 = y2 + 2.0f/3.0f*(cy - y2);
+
+       nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2);
+
+       *cpx2 = cx;
+       *cpy2 = cy;
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static float nsvg__sqr(float x) { return x*x; }
+static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); }
+
+static float nsvg__vecrat(float ux, float uy, float vx, float vy)
+{
+       return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy));
+}
+
+static float nsvg__vecang(float ux, float uy, float vx, float vy)
+{
+       float r = nsvg__vecrat(ux,uy, vx,vy);
+       if (r < -1.0f) r = -1.0f;
+       if (r > 1.0f) r = 1.0f;
+       return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r);
+}
+
+static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* 
args, int rel)
+{
+       // Ported from canvg (https://code.google.com/p/canvg/)
+       float rx, ry, rotx;
+       float x1, y1, x2, y2, cx, cy, dx, dy, d;
+       float x1p, y1p, cxp, cyp, s, sa, sb;
+       float ux, uy, vx, vy, a1, da;
+       float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6];
+       float sinrx, cosrx;
+       int fa, fs;
+       int i, ndivs;
+       float hda, kappa;
+
+       rx = fabsf(args[0]);                            // y radius
+       ry = fabsf(args[1]);                            // x radius
+       rotx = args[2] / 180.0f * NSVG_PI;              // x rotation angle
+       fa = fabsf(args[3]) > 1e-6 ? 1 : 0;     // Large arc
+       fs = fabsf(args[4]) > 1e-6 ? 1 : 0;     // Sweep direction
+       x1 = *cpx;                                                      // 
start point
+       y1 = *cpy;
+       if (rel) {                                                      // end 
point
+               x2 = *cpx + args[5];
+               y2 = *cpy + args[6];
+       } else {
+               x2 = args[5];
+               y2 = args[6];
+       }
+
+       dx = x1 - x2;
+       dy = y1 - y2;
+       d = sqrtf(dx*dx + dy*dy);
+       if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
+               // The arc degenerates to a line
+               nsvg__lineTo(p, x2, y2);
+               *cpx = x2;
+               *cpy = y2;
+               return;
+       }
+
+       sinrx = sinf(rotx);
+       cosrx = cosf(rotx);
+
+       // Convert to center point parameterization.
+       // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+       // 1) Compute x1', y1'
+       x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
+       y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
+       d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry);
+       if (d > 1) {
+               d = sqrtf(d);
+               rx *= d;
+               ry *= d;
+       }
+       // 2) Compute cx', cy'
+       s = 0.0f;
+       sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - 
nsvg__sqr(ry)*nsvg__sqr(x1p);
+       sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p);
+       if (sa < 0.0f) sa = 0.0f;
+       if (sb > 0.0f)
+               s = sqrtf(sa / sb);
+       if (fa == fs)
+               s = -s;
+       cxp = s * rx * y1p / ry;
+       cyp = s * -ry * x1p / rx;
+
+       // 3) Compute cx,cy from cx',cy'
+       cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp;
+       cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp;
+
+       // 4) Calculate theta1, and delta theta.
+       ux = (x1p - cxp) / rx;
+       uy = (y1p - cyp) / ry;
+       vx = (-x1p - cxp) / rx;
+       vy = (-y1p - cyp) / ry;
+       a1 = nsvg__vecang(1.0f,0.0f, ux,uy);    // Initial angle
+       da = nsvg__vecang(ux,uy, vx,vy);                // Delta angle
+
+//     if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
+//     if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
+
+       if (fs == 0 && da > 0)
+               da -= 2 * NSVG_PI;
+       else if (fs == 1 && da < 0)
+               da += 2 * NSVG_PI;
+
+       // Approximate the arc using cubic spline segments.
+       t[0] = cosrx; t[1] = sinrx;
+       t[2] = -sinrx; t[3] = cosrx;
+       t[4] = cx; t[5] = cy;
+
+       // Split arc into max 90 degree segments.
+       // The loop assumes an iteration per end point (including start and 
end), this +1.
+       ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f);
+       hda = (da / (float)ndivs) / 2.0f;
+       kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda));
+       if (da < 0.0f)
+               kappa = -kappa;
+
+       for (i = 0; i <= ndivs; i++) {
+               a = a1 + da * ((float)i/(float)ndivs);
+               dx = cosf(a);
+               dy = sinf(a);
+               nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position
+               nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); 
// tangent
+               if (i > 0)
+                       nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, 
x, y);
+               px = x;
+               py = y;
+               ptanx = tanx;
+               ptany = tany;
+       }
+
+       *cpx = x2;
+       *cpy = y2;
+}
+
+static void nsvg__parsePath(NSVGparser* p, const char** attr)
+{
+       const char* s = NULL;
+       char cmd = '\0';
+       float args[10];
+       int nargs;
+       int rargs = 0;
+       float cpx, cpy, cpx2, cpy2;
+       const char* tmp[4];
+       char closedFlag;
+       int i;
+       char item[64];
+
+       for (i = 0; attr[i]; i += 2) {
+               if (strcmp(attr[i], "d") == 0) {
+                       s = attr[i + 1];
+               } else {
+                       tmp[0] = attr[i];
+                       tmp[1] = attr[i + 1];
+                       tmp[2] = 0;
+                       tmp[3] = 0;
+                       nsvg__parseAttribs(p, tmp);
+               }
+       }
+
+       if (s) {
+               nsvg__resetPath(p);
+               cpx = 0; cpy = 0;
+               cpx2 = 0; cpy2 = 0;
+               closedFlag = 0;
+               nargs = 0;
+
+               while (*s) {
+                       s = nsvg__getNextPathItem(s, item);
+                       if (!*item) break;
+                       if (nsvg__isnum(item[0])) {
+                               if (nargs < 10)
+                                       args[nargs++] = (float)nsvg__atof(item);
+                               if (nargs >= rargs) {
+                                       switch (cmd) {
+                                               case 'm':
+                                               case 'M':
+                                                       nsvg__pathMoveTo(p, 
&cpx, &cpy, args, cmd == 'm' ? 1 : 0);
+                                                       // Moveto can be 
followed by multiple coordinate pairs,
+                                                       // which should be 
treated as linetos.
+                                                       cmd = (cmd == 'm') ? 
'l' : 'L';
+                                                       rargs = 
nsvg__getArgsPerElement(cmd);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'l':
+                                               case 'L':
+                                                       nsvg__pathLineTo(p, 
&cpx, &cpy, args, cmd == 'l' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'H':
+                                               case 'h':
+                                                       nsvg__pathHLineTo(p, 
&cpx, &cpy, args, cmd == 'h' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'V':
+                                               case 'v':
+                                                       nsvg__pathVLineTo(p, 
&cpx, &cpy, args, cmd == 'v' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               case 'C':
+                                               case 'c':
+                                                       nsvg__pathCubicBezTo(p, 
&cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0);
+                                                       break;
+                                               case 'S':
+                                               case 's':
+                                                       
nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 
0);
+                                                       break;
+                                               case 'Q':
+                                               case 'q':
+                                                       nsvg__pathQuadBezTo(p, 
&cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0);
+                                                       break;
+                                               case 'T':
+                                               case 't':
+                                                       
nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0);
+                                                       break;
+                                               case 'A':
+                                               case 'a':
+                                                       nsvg__pathArcTo(p, 
&cpx, &cpy, args, cmd == 'a' ? 1 : 0);
+                                                       cpx2 = cpx; cpy2 = cpy;
+                                                       break;
+                                               default:
+                                                       if (nargs >= 2) {
+                                                               cpx = 
args[nargs-2];
+                                                               cpy = 
args[nargs-1];
+                                                               cpx2 = cpx; 
cpy2 = cpy;
+                                                       }
+                                                       break;
+                                       }
+                                       nargs = 0;
+                               }
+                       } else {
+                               cmd = item[0];
+                               rargs = nsvg__getArgsPerElement(cmd);
+                               if (cmd == 'M' || cmd == 'm') {
+                                       // Commit path.
+                                       if (p->npts > 0)
+                                               nsvg__addPath(p, closedFlag);
+                                       // Start new subpath.
+                                       nsvg__resetPath(p);
+                                       closedFlag = 0;
+                                       nargs = 0;
+                               } else if (cmd == 'Z' || cmd == 'z') {
+                                       closedFlag = 1;
+                                       // Commit path.
+                                       if (p->npts > 0) {
+                                               // Move current point to first 
point
+                                               cpx = p->pts[0];
+                                               cpy = p->pts[1];
+                                               cpx2 = cpx; cpy2 = cpy;
+                                               nsvg__addPath(p, closedFlag);
+                                       }
+                                       // Start new subpath.
+                                       nsvg__resetPath(p);
+                                       nsvg__moveTo(p, cpx, cpy);
+                                       closedFlag = 0;
+                                       nargs = 0;
+                               }
+                       }
+               }
+               // Commit path.
+               if (p->npts)
+                       nsvg__addPath(p, closedFlag);
+       }
+
+       nsvg__addShape(p);
+}
+
+static void nsvg__parseRect(NSVGparser* p, const char** attr)
+{
+       float x = 0.0f;
+       float y = 0.0f;
+       float w = 0.0f;
+       float h = 0.0f;
+       float rx = -1.0f; // marks not set
+       float ry = -1.0f;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "x") == 0) x = 
nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "y") == 0) y = 
nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), 
nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "width") == 0) w = 
nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "height") == 0) h = 
nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "rx") == 0) rx = 
fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
+                       if (strcmp(attr[i], "ry") == 0) ry = 
fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
+               }
+       }
+
+       if (rx < 0.0f && ry > 0.0f) rx = ry;
+       if (ry < 0.0f && rx > 0.0f) ry = rx;
+       if (rx < 0.0f) rx = 0.0f;
+       if (ry < 0.0f) ry = 0.0f;
+       if (rx > w/2.0f) rx = w/2.0f;
+       if (ry > h/2.0f) ry = h/2.0f;
+
+       if (w != 0.0f && h != 0.0f) {
+               nsvg__resetPath(p);
+
+               if (rx < 0.00001f || ry < 0.0001f) {
+                       nsvg__moveTo(p, x, y);
+                       nsvg__lineTo(p, x+w, y);
+                       nsvg__lineTo(p, x+w, y+h);
+                       nsvg__lineTo(p, x, y+h);
+               } else {
+                       // Rounded rectangle
+                       nsvg__moveTo(p, x+rx, y);
+                       nsvg__lineTo(p, x+w-rx, y);
+                       nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, 
y+ry*(1-NSVG_KAPPA90), x+w, y+ry);
+                       nsvg__lineTo(p, x+w, y+h-ry);
+                       nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), 
x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h);
+                       nsvg__lineTo(p, x+rx, y+h);
+                       nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, 
y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry);
+                       nsvg__lineTo(p, x, y+ry);
+                       nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), 
x+rx*(1-NSVG_KAPPA90), y, x+rx, y);
+               }
+
+               nsvg__addPath(p, 1);
+
+               nsvg__addShape(p);
+       }
+}
+
+static void nsvg__parseCircle(NSVGparser* p, const char** attr)
+{
+       float cx = 0.0f;
+       float cy = 0.0f;
+       float r = 0.0f;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "cx") == 0) cx = 
nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "cy") == 0) cy = 
nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), 
nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "r") == 0) r = 
fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p)));
+               }
+       }
+
+       if (r > 0.0f) {
+               nsvg__resetPath(p);
+
+               nsvg__moveTo(p, cx+r, cy);
+               nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, 
cy+r, cx, cy+r);
+               nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, 
cy+r*NSVG_KAPPA90, cx-r, cy);
+               nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, 
cy-r, cx, cy-r);
+               nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, 
cy-r*NSVG_KAPPA90, cx+r, cy);
+
+               nsvg__addPath(p, 1);
+
+               nsvg__addShape(p);
+       }
+}
+
+static void nsvg__parseEllipse(NSVGparser* p, const char** attr)
+{
+       float cx = 0.0f;
+       float cy = 0.0f;
+       float rx = 0.0f;
+       float ry = 0.0f;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "cx") == 0) cx = 
nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "cy") == 0) cy = 
nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), 
nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "rx") == 0) rx = 
fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)));
+                       if (strcmp(attr[i], "ry") == 0) ry = 
fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)));
+               }
+       }
+
+       if (rx > 0.0f && ry > 0.0f) {
+
+               nsvg__resetPath(p);
+
+               nsvg__moveTo(p, cx+rx, cy);
+               nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, 
cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry);
+               nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, 
cy+ry*NSVG_KAPPA90, cx-rx, cy);
+               nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, 
cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry);
+               nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, 
cy-ry*NSVG_KAPPA90, cx+rx, cy);
+
+               nsvg__addPath(p, 1);
+
+               nsvg__addShape(p);
+       }
+}
+
+static void nsvg__parseLine(NSVGparser* p, const char** attr)
+{
+       float x1 = 0.0;
+       float y1 = 0.0;
+       float x2 = 0.0;
+       float y2 = 0.0;
+       int i;
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "x1") == 0) x1 = 
nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), 
nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "y1") == 0) y1 = 
nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), 
nsvg__actualHeight(p));
+                       if (strcmp(attr[i], "x2") == 0) x2 = 
nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), 
nsvg__actualWidth(p));
+                       if (strcmp(attr[i], "y2") == 0) y2 = 
nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), 
nsvg__actualHeight(p));
+               }
+       }
+
+       nsvg__resetPath(p);
+
+       nsvg__moveTo(p, x1, y1);
+       nsvg__lineTo(p, x2, y2);
+
+       nsvg__addPath(p, 0);
+
+       nsvg__addShape(p);
+}
+
+static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag)
+{
+       int i;
+       const char* s;
+       float args[2];
+       int nargs, npts = 0;
+       char item[64];
+
+       nsvg__resetPath(p);
+
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "points") == 0) {
+                               s = attr[i + 1];
+                               nargs = 0;
+                               while (*s) {
+                                       s = nsvg__getNextPathItem(s, item);
+                                       args[nargs++] = (float)nsvg__atof(item);
+                                       if (nargs >= 2) {
+                                               if (npts == 0)
+                                                       nsvg__moveTo(p, 
args[0], args[1]);
+                                               else
+                                                       nsvg__lineTo(p, 
args[0], args[1]);
+                                               nargs = 0;
+                                               npts++;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       nsvg__addPath(p, (char)closeFlag);
+
+       nsvg__addShape(p);
+}
+
+static void nsvg__parseSVG(NSVGparser* p, const char** attr)
+{
+       int i;
+       for (i = 0; attr[i]; i += 2) {
+               if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "width") == 0) {
+                               p->image->width = nsvg__parseCoordinate(p, 
attr[i + 1], 0.0f, 0.0f);
+                       } else if (strcmp(attr[i], "height") == 0) {
+                               p->image->height = nsvg__parseCoordinate(p, 
attr[i + 1], 0.0f, 0.0f);
+                       } else if (strcmp(attr[i], "viewBox") == 0) {
+                               const char *s = attr[i + 1];
+                               char buf[64];
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewMinx = nsvg__atof(buf);
+                               while (*s && (nsvg__isspace(*s) || *s == '%' || 
*s == ',')) s++;
+                               if (!*s) return;
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewMiny = nsvg__atof(buf);
+                               while (*s && (nsvg__isspace(*s) || *s == '%' || 
*s == ',')) s++;
+                               if (!*s) return;
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewWidth = nsvg__atof(buf);
+                               while (*s && (nsvg__isspace(*s) || *s == '%' || 
*s == ',')) s++;
+                               if (!*s) return;
+                               s = nsvg__parseNumber(s, buf, 64);
+                               p->viewHeight = nsvg__atof(buf);
+                       } else if (strcmp(attr[i], "preserveAspectRatio") == 0) 
{
+                               if (strstr(attr[i + 1], "none") != 0) {
+                                       // No uniform scaling
+                                       p->alignType = NSVG_ALIGN_NONE;
+                               } else {
+                                       // Parse X align
+                                       if (strstr(attr[i + 1], "xMin") != 0)
+                                               p->alignX = NSVG_ALIGN_MIN;
+                                       else if (strstr(attr[i + 1], "xMid") != 
0)
+                                               p->alignX = NSVG_ALIGN_MID;
+                                       else if (strstr(attr[i + 1], "xMax") != 
0)
+                                               p->alignX = NSVG_ALIGN_MAX;
+                                       // Parse X align
+                                       if (strstr(attr[i + 1], "yMin") != 0)
+                                               p->alignY = NSVG_ALIGN_MIN;
+                                       else if (strstr(attr[i + 1], "yMid") != 
0)
+                                               p->alignY = NSVG_ALIGN_MID;
+                                       else if (strstr(attr[i + 1], "yMax") != 
0)
+                                               p->alignY = NSVG_ALIGN_MAX;
+                                       // Parse meet/slice
+                                       p->alignType = NSVG_ALIGN_MEET;
+                                       if (strstr(attr[i + 1], "slice") != 0)
+                                               p->alignType = NSVG_ALIGN_SLICE;
+                               }
+                       }
+               }
+       }
+}
+
+static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type)
+{
+       int i;
+       NSVGgradientData* grad = 
(NSVGgradientData*)malloc(sizeof(NSVGgradientData));
+       if (grad == NULL) return;
+       memset(grad, 0, sizeof(NSVGgradientData));
+       grad->units = NSVG_OBJECT_SPACE;
+       grad->type = type;
+       if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) {
+               grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
+               grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
+               grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT);
+               grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT);
+       } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) {
+               grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
+               grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
+               grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT);
+       }
+
+       nsvg__xformIdentity(grad->xform);
+
+       for (i = 0; attr[i]; i += 2) {
+               if (strcmp(attr[i], "id") == 0) {
+                       strncpy(grad->id, attr[i+1], 63);
+                       grad->id[63] = '\0';
+               } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
+                       if (strcmp(attr[i], "gradientUnits") == 0) {
+                               if (strcmp(attr[i+1], "objectBoundingBox") == 0)
+                                       grad->units = NSVG_OBJECT_SPACE;
+                               else
+                                       grad->units = NSVG_USER_SPACE;
+                       } else if (strcmp(attr[i], "gradientTransform") == 0) {
+                               nsvg__parseTransform(grad->xform, attr[i + 1]);
+                       } else if (strcmp(attr[i], "cx") == 0) {
+                               grad->radial.cx = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "cy") == 0) {
+                               grad->radial.cy = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "r") == 0) {
+                               grad->radial.r = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "fx") == 0) {
+                               grad->radial.fx = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "fy") == 0) {
+                               grad->radial.fy = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "x1") == 0) {
+                               grad->linear.x1 = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "y1") == 0) {
+                               grad->linear.y1 = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "x2") == 0) {
+                               grad->linear.x2 = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "y2") == 0) {
+                               grad->linear.y2 = 
nsvg__parseCoordinateRaw(attr[i + 1]);
+                       } else if (strcmp(attr[i], "spreadMethod") == 0) {
+                               if (strcmp(attr[i+1], "pad") == 0)
+                                       grad->spread = NSVG_SPREAD_PAD;
+                               else if (strcmp(attr[i+1], "reflect") == 0)
+                                       grad->spread = NSVG_SPREAD_REFLECT;
+                               else if (strcmp(attr[i+1], "repeat") == 0)
+                                       grad->spread = NSVG_SPREAD_REPEAT;
+                       } else if (strcmp(attr[i], "xlink:href") == 0) {
+                               const char *href = attr[i+1];
+                               strncpy(grad->ref, href+1, 62);
+                               grad->ref[62] = '\0';
+                       }
+               }
+       }
+
+       grad->next = p->gradients;
+       p->gradients = grad;
+}
+
+static void nsvg__parseGradientStop(NSVGparser* p, const char** attr)
+{
+       NSVGattrib* curAttr = nsvg__getAttr(p);
+       NSVGgradientData* grad;
+       NSVGgradientStop* stop;
+       int i, idx;
+
+       curAttr->stopOffset = 0;
+       curAttr->stopColor = 0;
+       curAttr->stopOpacity = 1.0f;
+
+       for (i = 0; attr[i]; i += 2) {
+               nsvg__parseAttr(p, attr[i], attr[i + 1]);
+       }
+
+       // Add stop to the last gradient.
+       grad = p->gradients;
+       if (grad == NULL) return;
+
+       grad->nstops++;
+       grad->stops = (NSVGgradientStop*)realloc(grad->stops, 
sizeof(NSVGgradientStop)*grad->nstops);
+       if (grad->stops == NULL) return;
+
+       // Insert
+       idx = grad->nstops-1;
+       for (i = 0; i < grad->nstops-1; i++) {
+               if (curAttr->stopOffset < grad->stops[i].offset) {
+                       idx = i;
+                       break;
+               }
+       }
+       if (idx != grad->nstops-1) {
+               for (i = grad->nstops-1; i > idx; i--)
+                       grad->stops[i] = grad->stops[i-1];
+       }
+
+       stop = &grad->stops[idx];
+       stop->color = curAttr->stopColor;
+       stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24;
+       stop->offset = curAttr->stopOffset;
+}
+
+static void nsvg__startElement(void* ud, const char* el, const char** attr)
+{
+       NSVGparser* p = (NSVGparser*)ud;
+
+       if (p->defsFlag) {
+               // Skip everything but gradients in defs
+               if (strcmp(el, "linearGradient") == 0) {
+                       nsvg__parseGradient(p, attr, 
NSVG_PAINT_LINEAR_GRADIENT);
+               } else if (strcmp(el, "radialGradient") == 0) {
+                       nsvg__parseGradient(p, attr, 
NSVG_PAINT_RADIAL_GRADIENT);
+               } else if (strcmp(el, "stop") == 0) {
+                       nsvg__parseGradientStop(p, attr);
+               }
+               return;
+       }
+
+       if (strcmp(el, "g") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseAttribs(p, attr);
+       } else if (strcmp(el, "path") == 0) {
+               if (p->pathFlag)        // Do not allow nested paths.
+                       return;
+               nsvg__pushAttr(p);
+               nsvg__parsePath(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "rect") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseRect(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "circle") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseCircle(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "ellipse") == 0) {
+               nsvg__pushAttr(p);
+               nsvg__parseEllipse(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "line") == 0)  {
+               nsvg__pushAttr(p);
+               nsvg__parseLine(p, attr);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "polyline") == 0)  {
+               nsvg__pushAttr(p);
+               nsvg__parsePoly(p, attr, 0);
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "polygon") == 0)  {
+               nsvg__pushAttr(p);
+               nsvg__parsePoly(p, attr, 1);
+               nsvg__popAttr(p);
+       } else  if (strcmp(el, "linearGradient") == 0) {
+               nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT);
+       } else if (strcmp(el, "radialGradient") == 0) {
+               nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT);
+       } else if (strcmp(el, "stop") == 0) {
+               nsvg__parseGradientStop(p, attr);
+       } else if (strcmp(el, "defs") == 0) {
+               p->defsFlag = 1;
+       } else if (strcmp(el, "svg") == 0) {
+               nsvg__parseSVG(p, attr);
+       }
+}
+
+static void nsvg__endElement(void* ud, const char* el)
+{
+       NSVGparser* p = (NSVGparser*)ud;
+
+       if (strcmp(el, "g") == 0) {
+               nsvg__popAttr(p);
+       } else if (strcmp(el, "path") == 0) {
+               p->pathFlag = 0;
+       } else if (strcmp(el, "defs") == 0) {
+               p->defsFlag = 0;
+       }
+}
+
+static void nsvg__content(void* ud, const char* s)
+{
+       NSVG_NOTUSED(ud);
+       NSVG_NOTUSED(s);
+       // empty
+}
+
+static void nsvg__imageBounds(NSVGparser* p, float* bounds)
+{
+       NSVGshape* shape;
+       shape = p->image->shapes;
+       if (shape == NULL) {
+               bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0;
+               return;
+       }
+       bounds[0] = shape->bounds[0];
+       bounds[1] = shape->bounds[1];
+       bounds[2] = shape->bounds[2];
+       bounds[3] = shape->bounds[3];
+       for (shape = shape->next; shape != NULL; shape = shape->next) {
+               bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]);
+               bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]);
+               bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]);
+               bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]);
+       }
+}
+
+static float nsvg__viewAlign(float content, float container, int type)
+{
+       if (type == NSVG_ALIGN_MIN)
+               return 0;
+       else if (type == NSVG_ALIGN_MAX)
+               return container - content;
+       // mid
+       return (container - content) * 0.5f;
+}
+
+static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float 
sx, float sy)
+{
+       float t[6];
+       nsvg__xformSetTranslation(t, tx, ty);
+       nsvg__xformMultiply (grad->xform, t);
+
+       nsvg__xformSetScale(t, sx, sy);
+       nsvg__xformMultiply (grad->xform, t);
+}
+
+static void nsvg__scaleToViewbox(NSVGparser* p, const char* units)
+{
+       NSVGshape* shape;
+       NSVGpath* path;
+       float tx, ty, sx, sy, us, bounds[4], t[6], avgs;
+       int i;
+       float* pt;
+
+       // Guess image size if not set completely.
+       nsvg__imageBounds(p, bounds);
+
+       if (p->viewWidth == 0) {
+               if (p->image->width > 0) {
+                       p->viewWidth = p->image->width;
+               } else {
+                       p->viewMinx = bounds[0];
+                       p->viewWidth = bounds[2] - bounds[0];
+               }
+       }
+       if (p->viewHeight == 0) {
+               if (p->image->height > 0) {
+                       p->viewHeight = p->image->height;
+               } else {
+                       p->viewMiny = bounds[1];
+                       p->viewHeight = bounds[3] - bounds[1];
+               }
+       }
+       if (p->image->width == 0)
+               p->image->width = p->viewWidth;
+       if (p->image->height == 0)
+               p->image->height = p->viewHeight;
+
+       tx = -p->viewMinx;
+       ty = -p->viewMiny;
+       sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0;
+       sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0;
+       // Unit scaling
+       us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, 
nsvg__parseUnits(units)), 0.0f, 1.0f);
+
+       // Fix aspect ratio
+       if (p->alignType == NSVG_ALIGN_MEET) {
+               // fit whole image into viewbox
+               sx = sy = nsvg__minf(sx, sy);
+               tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, 
p->alignX) / sx;
+               ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, 
p->alignY) / sy;
+       } else if (p->alignType == NSVG_ALIGN_SLICE) {
+               // fill whole viewbox with image
+               sx = sy = nsvg__maxf(sx, sy);
+               tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, 
p->alignX) / sx;
+               ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, 
p->alignY) / sy;
+       }
+
+       // Transform
+       sx *= us;
+       sy *= us;
+       avgs = (sx+sy) / 2.0f;
+       for (shape = p->image->shapes; shape != NULL; shape = shape->next) {
+               shape->bounds[0] = (shape->bounds[0] + tx) * sx;
+               shape->bounds[1] = (shape->bounds[1] + ty) * sy;
+               shape->bounds[2] = (shape->bounds[2] + tx) * sx;
+               shape->bounds[3] = (shape->bounds[3] + ty) * sy;
+               for (path = shape->paths; path != NULL; path = path->next) {
+                       path->bounds[0] = (path->bounds[0] + tx) * sx;
+                       path->bounds[1] = (path->bounds[1] + ty) * sy;
+                       path->bounds[2] = (path->bounds[2] + tx) * sx;
+                       path->bounds[3] = (path->bounds[3] + ty) * sy;
+                       for (i =0; i < path->npts; i++) {
+                               pt = &path->pts[i*2];
+                               pt[0] = (pt[0] + tx) * sx;
+                               pt[1] = (pt[1] + ty) * sy;
+                       }
+               }
+
+               if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || 
shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) {
+                       nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy);
+                       memcpy(t, shape->fill.gradient->xform, sizeof(float)*6);
+                       nsvg__xformInverse(shape->fill.gradient->xform, t);
+               }
+               if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || 
shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) {
+                       nsvg__scaleGradient(shape->stroke.gradient, tx,ty, 
sx,sy);
+                       memcpy(t, shape->stroke.gradient->xform, 
sizeof(float)*6);
+                       nsvg__xformInverse(shape->stroke.gradient->xform, t);
+               }
+
+               shape->strokeWidth *= avgs;
+               shape->strokeDashOffset *= avgs;
+               for (i = 0; i < shape->strokeDashCount; i++)
+                       shape->strokeDashArray[i] *= avgs;
+       }
+}
+
+NSVGimage* nsvgParse(char* input, const char* units, float dpi)
+{
+       NSVGparser* p;
+       NSVGimage* ret = 0;
+
+       p = nsvg__createParser();
+       if (p == NULL) {
+               return NULL;
+       }
+       p->dpi = dpi;
+
+       nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, 
nsvg__content, p);
+
+       // Scale to viewBox
+       nsvg__scaleToViewbox(p, units);
+
+       ret = p->image;
+       p->image = NULL;
+
+       nsvg__deleteParser(p);
+
+       return ret;
+}
+
+NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float 
dpi)
+{
+       FILE* fp = NULL;
+       size_t size;
+       char* data = NULL;
+       NSVGimage* image = NULL;
+
+       fp = fopen(filename, "rb");
+       if (!fp) goto error;
+       fseek(fp, 0, SEEK_END);
+       size = ftell(fp);
+       fseek(fp, 0, SEEK_SET);
+       data = (char*)malloc(size+1);
+       if (data == NULL) goto error;
+       if (fread(data, 1, size, fp) != size) goto error;
+       data[size] = '\0';      // Must be null terminated.
+       fclose(fp);
+       image = nsvgParse(data, units, dpi);
+       free(data);
+
+       return image;
+
+error:
+       if (fp) fclose(fp);
+       if (data) free(data);
+       if (image) nsvgDelete(image);
+       return NULL;
+}
+
+NSVGpath* nsvgDuplicatePath(NSVGpath* p)
+{
+    NSVGpath* res = NULL;
+
+    if (p == NULL)
+        return NULL;
+
+    res = (NSVGpath*)malloc(sizeof(NSVGpath));
+    if (res == NULL) goto error;
+    memset(res, 0, sizeof(NSVGpath));
+
+    res->pts = (float*)malloc(p->npts*2*sizeof(float));
+    if (res->pts == NULL) goto error;
+    memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2);
+    res->npts = p->npts;
+
+    memcpy(res->bounds, p->bounds, sizeof(p->bounds));
+
+    res->closed = p->closed;
+
+    return res;
+
+error:
+    if (res != NULL) {
+        free(res->pts);
+        free(res);
+    }
+    return NULL;
+}
+
+void nsvgDelete(NSVGimage* image)
+{
+       NSVGshape *snext, *shape;
+       if (image == NULL) return;
+       shape = image->shapes;
+       while (shape != NULL) {
+               snext = shape->next;
+               nsvg__deletePaths(shape->paths);
+               nsvg__deletePaint(&shape->fill);
+               nsvg__deletePaint(&shape->stroke);
+               free(shape);
+               shape = snext;
+       }
+       free(image);
+}
+
+#endif

--
To view, visit https://review.haiku-os.org/c/haiku/+/2661
To unsubscribe, or for help writing mail filters, visit 
https://review.haiku-os.org/settings

Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I38ff9aa4e1d403c41979ebe42f7b45d4500a870c
Gerrit-Change-Number: 2661
Gerrit-PatchSet: 1
Gerrit-Owner: Adrien Destugues <pulkomandy@xxxxxxxxx>
Gerrit-MessageType: newchange

Other related posts:

  • » [haiku-commits] Change in haiku[master]: Icon-O-Matic: replace SVG parser with nanosvg - Gerrit