Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <string.h></string.h>
Toshihiro Shimizu 890ddd
#include <stdlib.h></stdlib.h>
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qtextstream></qtextstream>
Toshihiro Shimizu 890ddd
#include <qfile></qfile>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tiio_svg.h"
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "tstroke.h"
Toshihiro Shimizu 890ddd
#include "tstrokeoutline.h"
Toshihiro Shimizu 890ddd
#include "tregion.h"
Toshihiro Shimizu 890ddd
#include "tcurves.h"
Toshihiro Shimizu 890ddd
#include "tpalette.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace  // svg_parser
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct NSVGpath {
Shinya Kitaoka 120a6e
  float *pts;   // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
Shinya Kitaoka 120a6e
  int npts;     // Total number of bezier points.
Shinya Kitaoka 120a6e
  char closed;  // Flag indicating if shapes should be treated as closed.
Shinya Kitaoka 120a6e
  struct NSVGpath *next;  // Pointer to next path, or NULL if last element.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct NSVGshape {
Shinya Kitaoka 120a6e
  unsigned int fillColor;    // Fill color
Shinya Kitaoka 120a6e
  unsigned int strokeColor;  // Stroke color
Shinya Kitaoka 120a6e
  float strokeWidth;         // Stroke width (scaled)
Shinya Kitaoka 120a6e
  char hasFill;              // Flag indicating if fill exists.
Shinya Kitaoka 120a6e
  char hasStroke;            // Flag indicating id store exists
Shinya Kitaoka 120a6e
  struct NSVGpath *paths;    // Linked list of paths in the image.
Shinya Kitaoka 120a6e
  struct NSVGshape *next;    // Pointer to next shape, or NULL if last element.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct NSVGimage {
Shinya Kitaoka 120a6e
  float width;               // Width of the image, or -1.0f of not set.
Shinya Kitaoka 120a6e
  float height;              // Height of the image, or -1.0f of not set.
Shinya Kitaoka 120a6e
  char wunits[8];            // Units of the width attribute
Shinya Kitaoka 120a6e
  char hunits[8];            // Units of the height attribute
Shinya Kitaoka 120a6e
  struct NSVGshape *shapes;  // Linked list of shapes in the image.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define NSVG_PI 3.14159265358979323846264338327f
Shinya Kitaoka 120a6e
#define NSVG_KAPPA90                                                           \
MCCCS a0ce32
  0.5522847493f  // Length proportional to radius of a cubic bezier handle for
Shinya Kitaoka 120a6e
                 // 90deg arcs.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef _MSC_VER
Shinya Kitaoka 120a6e
#pragma warning(disable : 4996)  // Switch off security warnings
Shinya Kitaoka 120a6e
#pragma warning(                                                               \
Shinya Kitaoka 120a6e
    disable : 4100)  // Switch off unreferenced formal parameter warnings
Toshihiro Shimizu 890ddd
#ifdef __cplusplus
Toshihiro Shimizu 890ddd
#define NSVG_INLINE inline
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#define NSVG_INLINE
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#define NSVG_INLINE inline
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int nsvg__isspace(char c) { return strchr(" \t\n\v\f\r", c) != 0; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int nsvg__isdigit(char c) { return strchr("0123456789", c) != 0; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int nsvg__isnum(char c) { return strchr("0123456789+-.eE", c) != 0; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Simple XML parser
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define NSVG_XML_TAG 1
Toshihiro Shimizu 890ddd
#define NSVG_XML_CONTENT 2
Toshihiro Shimizu 890ddd
#define NSVG_XML_MAX_ATTRIBS 256
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void nsvg__parseContent(char *s, void (*contentCb)(void *ud, const char *s),
Shinya Kitaoka 120a6e
                        void *ud) {
Shinya Kitaoka 120a6e
  // Trim start white spaces
Shinya Kitaoka 120a6e
  while (*s && nsvg__isspace(*s)) s++;
Shinya Kitaoka 120a6e
  if (!*s) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (contentCb) (*contentCb)(ud, s);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseElement(char *s, void (*startelCb)(void *ud, const char *el,
Shinya Kitaoka 120a6e
                                                   const char **attr),
Shinya Kitaoka 120a6e
                        void (*endelCb)(void *ud, const char *el), void *ud) {
Shinya Kitaoka 120a6e
  const char *attr[NSVG_XML_MAX_ATTRIBS];
Shinya Kitaoka 120a6e
  int nattr = 0;
Shinya Kitaoka 120a6e
  char *name;
Shinya Kitaoka 120a6e
  int start = 0;
Shinya Kitaoka 120a6e
  int end   = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Skip white space after the '<'
Shinya Kitaoka 120a6e
  while (*s && nsvg__isspace(*s)) s++;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Check if the tag is end tag
Shinya Kitaoka 120a6e
  if (*s == '/') {
Shinya Kitaoka 120a6e
    s++;
Shinya Kitaoka 120a6e
    end = 1;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    start = 1;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Skip comments, data and preprocessor stuff.
Shinya Kitaoka 120a6e
  if (!*s || *s == '?' || *s == '!') return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Get tag name
Shinya Kitaoka 120a6e
  name = s;
Shinya Kitaoka 120a6e
  while (*s && !nsvg__isspace(*s)) s++;
Shinya Kitaoka 120a6e
  if (*s) {
Shinya Kitaoka 120a6e
    *s++ = '\0';
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Get attribs
Shinya Kitaoka 120a6e
  while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS - 3) {
Shinya Kitaoka 120a6e
    // Skip white space before the attrib name
Shinya Kitaoka 120a6e
    while (*s && nsvg__isspace(*s)) s++;
Shinya Kitaoka 120a6e
    if (!*s) break;
Shinya Kitaoka 120a6e
    if (*s == '/') {
Shinya Kitaoka 120a6e
      end = 1;
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    attr[nattr++] = s;
Shinya Kitaoka 120a6e
    // Find end of the attrib name.
Shinya Kitaoka 120a6e
    while (*s && !nsvg__isspace(*s) && *s != '=') s++;
Shinya Kitaoka 120a6e
    if (*s) {
Shinya Kitaoka 120a6e
      *s++ = '\0';
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // Skip until the beginning of the value.
Shinya Kitaoka 120a6e
    while (*s && *s != '\"') s++;
Shinya Kitaoka 120a6e
    if (!*s) break;
Shinya Kitaoka 120a6e
    s++;
Shinya Kitaoka 120a6e
    // Store value and find the end of it.
Shinya Kitaoka 120a6e
    attr[nattr++] = s;
Shinya Kitaoka 120a6e
    while (*s && *s != '\"') s++;
Shinya Kitaoka 120a6e
    if (*s) {
Shinya Kitaoka 120a6e
      *s++ = '\0';
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // List terminator
Shinya Kitaoka 120a6e
  attr[nattr++] = 0;
Shinya Kitaoka 120a6e
  attr[nattr++] = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Call callbacks.
Shinya Kitaoka 120a6e
  if (start && startelCb) (*startelCb)(ud, name, attr);
Shinya Kitaoka 120a6e
  if (end && endelCb) (*endelCb)(ud, name);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseXML(char *input, void (*startelCb)(void *ud, const char *el,
Shinya Kitaoka 120a6e
                                                  const char **attr),
Shinya Kitaoka 120a6e
                   void (*endelCb)(void *ud, const char *el),
Shinya Kitaoka 120a6e
                   void (*contentCb)(void *ud, const char *s), void *ud) {
Shinya Kitaoka 120a6e
  char *s    = input;
Shinya Kitaoka 120a6e
  char *mark = s;
Shinya Kitaoka 120a6e
  int state  = NSVG_XML_CONTENT;
Shinya Kitaoka 120a6e
  while (*s) {
Shinya Kitaoka 120a6e
    if (*s == '<' && state == NSVG_XML_CONTENT) {
Shinya Kitaoka 120a6e
      // Start of a tag
Shinya Kitaoka 120a6e
      *s++ = '\0';
Shinya Kitaoka 120a6e
      nsvg__parseContent(mark, contentCb, ud);
Shinya Kitaoka 120a6e
      mark  = s;
Shinya Kitaoka 120a6e
      state = NSVG_XML_TAG;
Shinya Kitaoka 120a6e
    } else if (*s == '>' && state == NSVG_XML_TAG) {
Shinya Kitaoka 120a6e
      // Start of a content or new tag.
Shinya Kitaoka 120a6e
      *s++ = '\0';
Shinya Kitaoka 120a6e
      nsvg__parseElement(mark, startelCb, endelCb, ud);
Shinya Kitaoka 120a6e
      mark  = s;
Shinya Kitaoka 120a6e
      state = NSVG_XML_CONTENT;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      s++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return 1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/* Simple SVG parser. */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#define NSVG_MAX_ATTR 128
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct NSVGAttrib {
Shinya Kitaoka 120a6e
  float xform[6];
Shinya Kitaoka 120a6e
  unsigned int fillColor;
Shinya Kitaoka 120a6e
  unsigned int strokeColor;
Shinya Kitaoka 120a6e
  float fillOpacity;
Shinya Kitaoka 120a6e
  float strokeOpacity;
Shinya Kitaoka 120a6e
  float strokeWidth;
Shinya Kitaoka 120a6e
  char hasFill;
Shinya Kitaoka 120a6e
  char hasStroke;
Shinya Kitaoka 120a6e
  char visible;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct NSVGParser {
Shinya Kitaoka 120a6e
  struct NSVGAttrib attr[NSVG_MAX_ATTR];
Shinya Kitaoka 120a6e
  int attrHead;
Shinya Kitaoka 120a6e
  float *pts;
Shinya Kitaoka 120a6e
  int npts;
Shinya Kitaoka 120a6e
  int cpts;
Shinya Kitaoka 120a6e
  struct NSVGpath *plist;
Shinya Kitaoka 120a6e
  struct NSVGimage *image;
Shinya Kitaoka 120a6e
  char pathFlag;
Shinya Kitaoka 120a6e
  char defsFlag;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void nsvg__xformSetIdentity(float *t) {
Shinya Kitaoka 120a6e
  t[0] = 1.0f;
Shinya Kitaoka 120a6e
  t[1] = 0.0f;
Shinya Kitaoka 120a6e
  t[2] = 0.0f;
Shinya Kitaoka 120a6e
  t[3] = 1.0f;
Shinya Kitaoka 120a6e
  t[4] = 0.0f;
Shinya Kitaoka 120a6e
  t[5] = 0.0f;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformSetTranslation(float *t, float tx, float ty) {
Shinya Kitaoka 120a6e
  t[0] = 1.0f;
Shinya Kitaoka 120a6e
  t[1] = 0.0f;
Shinya Kitaoka 120a6e
  t[2] = 0.0f;
Shinya Kitaoka 120a6e
  t[3] = 1.0f;
Shinya Kitaoka 120a6e
  t[4] = tx;
Shinya Kitaoka 120a6e
  t[5] = ty;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformSetScale(float *t, float sx, float sy) {
Shinya Kitaoka 120a6e
  t[0] = sx;
Shinya Kitaoka 120a6e
  t[1] = 0.0f;
Shinya Kitaoka 120a6e
  t[2] = 0.0f;
Shinya Kitaoka 120a6e
  t[3] = sy;
Shinya Kitaoka 120a6e
  t[4] = 0.0f;
Shinya Kitaoka 120a6e
  t[5] = 0.0f;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformSetSkewX(float *t, float a) {
Shinya Kitaoka 120a6e
  t[0] = 1.0f;
Shinya Kitaoka 120a6e
  t[1] = 0.0f;
Shinya Kitaoka 120a6e
  t[2] = tanf(a);
Shinya Kitaoka 120a6e
  t[3] = 1.0f;
Shinya Kitaoka 120a6e
  t[4] = 0.0f;
Shinya Kitaoka 120a6e
  t[5] = 0.0f;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformSetSkewY(float *t, float a) {
Shinya Kitaoka 120a6e
  t[0] = 1.0f;
Shinya Kitaoka 120a6e
  t[1] = tanf(a);
Shinya Kitaoka 120a6e
  t[2] = 0.0f;
Shinya Kitaoka 120a6e
  t[3] = 1.0f;
Shinya Kitaoka 120a6e
  t[4] = 0.0f;
Shinya Kitaoka 120a6e
  t[5] = 0.0f;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformSetRotation(float *t, float a) {
Shinya Kitaoka 120a6e
  float cs = cosf(a), sn = sinf(a);
Shinya Kitaoka 120a6e
  t[0] = cs;
Shinya Kitaoka 120a6e
  t[1] = sn;
Shinya Kitaoka 120a6e
  t[2] = -sn;
Shinya Kitaoka 120a6e
  t[3] = cs;
Shinya Kitaoka 120a6e
  t[4] = 0.0f;
Shinya Kitaoka 120a6e
  t[5] = 0.0f;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformMultiply(float *t, float *s) {
Shinya Kitaoka 120a6e
  float t0 = t[0] * s[0] + t[1] * s[2];
Shinya Kitaoka 120a6e
  float t2 = t[2] * s[0] + t[3] * s[2];
Shinya Kitaoka 120a6e
  float t4 = t[4] * s[0] + t[5] * s[2] + s[4];
Shinya Kitaoka 120a6e
  t[1]     = t[0] * s[1] + t[1] * s[3];
Shinya Kitaoka 120a6e
  t[3]     = t[2] * s[1] + t[3] * s[3];
Shinya Kitaoka 120a6e
  t[5]     = t[4] * s[1] + t[5] * s[3] + s[5];
Shinya Kitaoka 120a6e
  t[0]     = t0;
Shinya Kitaoka 120a6e
  t[2]     = t2;
Shinya Kitaoka 120a6e
  t[4]     = t4;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformPremultiply(float *t, float *s) {
Shinya Kitaoka 120a6e
  float s2[6];
Shinya Kitaoka 120a6e
  memcpy(s2, s, sizeof(float) * 6);
Shinya Kitaoka 120a6e
  nsvg__xformMultiply(s2, t);
Shinya Kitaoka 120a6e
  memcpy(t, s2, sizeof(float) * 6);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformPoint(float *dx, float *dy, float x, float y, float *t) {
Shinya Kitaoka 120a6e
  *dx = x * t[0] + y * t[2] + t[4];
Shinya Kitaoka 120a6e
  *dy = x * t[1] + y * t[3] + t[5];
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__xformVec(float *dx, float *dy, float x, float y, float *t) {
Shinya Kitaoka 120a6e
  *dx = x * t[0] + y * t[2];
Shinya Kitaoka 120a6e
  *dy = x * t[1] + y * t[3];
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
struct NSVGParser *nsvg__createParser() {
Shinya Kitaoka 120a6e
  struct NSVGParser *p;
Shinya Kitaoka 120a6e
  p = (struct NSVGParser *)malloc(sizeof(struct NSVGParser));
Shinya Kitaoka 120a6e
  if (p == NULL) goto error;
Shinya Kitaoka 120a6e
  memset(p, 0, sizeof(struct NSVGParser));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p->image = (struct NSVGimage *)malloc(sizeof(struct NSVGimage));
Shinya Kitaoka 120a6e
  if (p->image == NULL) goto error;
Shinya Kitaoka 120a6e
  memset(p->image, 0, sizeof(struct NSVGimage));
Shinya Kitaoka 120a6e
  p->image->width  = -1.0f;
Shinya Kitaoka 120a6e
  p->image->height = -1.0f;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Init style
Shinya Kitaoka 120a6e
  nsvg__xformSetIdentity(p->attr[0].xform);
Shinya Kitaoka 120a6e
  p->attr[0].fillColor     = 0;
Shinya Kitaoka 120a6e
  p->attr[0].strokeColor   = 0;
Shinya Kitaoka 120a6e
  p->attr[0].fillOpacity   = 1;
Shinya Kitaoka 120a6e
  p->attr[0].strokeOpacity = 1;
Shinya Kitaoka 120a6e
  p->attr[0].strokeWidth   = 1;
Shinya Kitaoka 120a6e
  p->attr[0].hasFill       = 0;
Shinya Kitaoka 120a6e
  p->attr[0].hasStroke     = 0;
Shinya Kitaoka 120a6e
  p->attr[0].visible       = 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return p;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
error:
Shinya Kitaoka 120a6e
  if (p) {
Shinya Kitaoka 120a6e
    if (p->image) free(p->image);
Shinya Kitaoka 120a6e
    free(p);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return NULL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void nsvg__deletePaths(struct NSVGpath *path) {
Shinya Kitaoka 120a6e
  while (path) {
Shinya Kitaoka 120a6e
    struct NSVGpath *next = path->next;
Shinya Kitaoka 120a6e
    if (path->pts != NULL) free(path->pts);
Shinya Kitaoka 120a6e
    free(path);
Shinya Kitaoka 120a6e
    path = next;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void nsvgDelete(struct NSVGimage *image) {
Shinya Kitaoka 120a6e
  struct NSVGshape *next, *shape;
Shinya Kitaoka 120a6e
  if (image == NULL) return;
Shinya Kitaoka 120a6e
  shape = image->shapes;
Shinya Kitaoka 120a6e
  while (shape != NULL) {
Shinya Kitaoka 120a6e
    next = shape->next;
Shinya Kitaoka 120a6e
    nsvg__deletePaths(shape->paths);
Shinya Kitaoka 120a6e
    free(shape);
Shinya Kitaoka 120a6e
    shape = next;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  free(image);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__deleteParser(struct NSVGParser *p) {
Shinya Kitaoka 120a6e
  if (p != NULL) {
Shinya Kitaoka 120a6e
    nsvg__deletePaths(p->plist);
Shinya Kitaoka 120a6e
    nsvgDelete(p->image);
Shinya Kitaoka 120a6e
    free(p->pts);
Shinya Kitaoka 120a6e
    free(p);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__resetPath(struct NSVGParser *p) { p->npts = 0; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__addPoint(struct NSVGParser *p, float x, float y) {
Shinya Kitaoka 120a6e
  if (p->npts + 1 > p->cpts) {
Shinya Kitaoka 120a6e
    p->cpts = p->cpts ? p->cpts * 2 : 8;
Shinya Kitaoka 120a6e
    p->pts  = (float *)realloc(p->pts, p->cpts * 2 * sizeof(float));
Shinya Kitaoka 120a6e
    if (!p->pts) return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  p->pts[p->npts * 2 + 0] = x;
Shinya Kitaoka 120a6e
  p->pts[p->npts * 2 + 1] = y;
Shinya Kitaoka 120a6e
  p->npts++;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__moveTo(struct NSVGParser *p, float x, float y) {
Shinya Kitaoka 120a6e
  nsvg__addPoint(p, x, y);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__lineTo(struct NSVGParser *p, float x, float y) {
Shinya Kitaoka 120a6e
  float px, py, dx, dy;
Shinya Kitaoka 120a6e
  if (p->npts > 0) {
Shinya Kitaoka 120a6e
    px = p->pts[(p->npts - 1) * 2 + 0];
Shinya Kitaoka 120a6e
    py = p->pts[(p->npts - 1) * 2 + 1];
Shinya Kitaoka 120a6e
    dx = x - px;
Shinya Kitaoka 120a6e
    dy = y - py;
Shinya Kitaoka 120a6e
    nsvg__addPoint(p, px + dx / 3.0f, py + dy / 3.0f);
Shinya Kitaoka 120a6e
    nsvg__addPoint(p, x - dx / 3.0f, y - dy / 3.0f);
Shinya Kitaoka 120a6e
    nsvg__addPoint(p, x, y);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__cubicBezTo(struct NSVGParser *p, float cpx1, float cpy1, float cpx2,
Shinya Kitaoka 120a6e
                      float cpy2, float x, float y) {
Shinya Kitaoka 120a6e
  nsvg__addPoint(p, cpx1, cpy1);
Shinya Kitaoka 120a6e
  nsvg__addPoint(p, cpx2, cpy2);
Shinya Kitaoka 120a6e
  nsvg__addPoint(p, x, y);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
struct NSVGAttrib *nsvg__getAttr(struct NSVGParser *p) {
Shinya Kitaoka 120a6e
  return &p->attr[p->attrHead];
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__pushAttr(struct NSVGParser *p) {
Shinya Kitaoka 120a6e
  if (p->attrHead < NSVG_MAX_ATTR - 1) {
Shinya Kitaoka 120a6e
    p->attrHead++;
Shinya Kitaoka 120a6e
    memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead - 1],
Shinya Kitaoka 120a6e
           sizeof(struct NSVGAttrib));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__popAttr(struct NSVGParser *p) {
Shinya Kitaoka 120a6e
  if (p->attrHead > 0) p->attrHead--;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__addShape(struct NSVGParser *p) {
Shinya Kitaoka 120a6e
  struct NSVGAttrib *attr = nsvg__getAttr(p);
Shinya Kitaoka 120a6e
  float scale             = 1.0f;
Shinya Kitaoka 120a6e
  struct NSVGshape *shape, *cur, *prev;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (p->plist == NULL) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  shape = (struct NSVGshape *)malloc(sizeof(struct NSVGshape));
Shinya Kitaoka 120a6e
  if (shape == NULL) goto error;
Shinya Kitaoka 120a6e
  memset(shape, 0, sizeof(struct NSVGshape));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  scale              = nsvg__maxf(fabsf(attr->xform[0]), fabsf(attr->xform[3]));
Shinya Kitaoka 120a6e
  shape->hasFill     = attr->hasFill;
Shinya Kitaoka 120a6e
  shape->hasStroke   = attr->hasStroke;
Shinya Kitaoka 120a6e
  shape->strokeWidth = attr->strokeWidth * scale;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  shape->fillColor = attr->fillColor;
Shinya Kitaoka 120a6e
  if (shape->hasFill)
Shinya Kitaoka 120a6e
    shape->fillColor |= (unsigned int)(attr->fillOpacity * 255) << 24;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  shape->strokeColor = attr->strokeColor;
Shinya Kitaoka 120a6e
  if (shape->hasStroke)
Shinya Kitaoka 120a6e
    shape->strokeColor |= (unsigned int)(attr->strokeOpacity * 255) << 24;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  shape->paths = p->plist;
Shinya Kitaoka 120a6e
  p->plist     = NULL;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Add to tail
Shinya Kitaoka 120a6e
  prev = NULL;
Shinya Kitaoka 120a6e
  cur  = p->image->shapes;
Shinya Kitaoka 120a6e
  while (cur != NULL) {
Shinya Kitaoka 120a6e
    prev = cur;
Shinya Kitaoka 120a6e
    cur  = cur->next;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (prev == NULL)
Shinya Kitaoka 120a6e
    p->image->shapes = shape;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    prev->next = shape;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
error:
Shinya Kitaoka 120a6e
  if (shape) free(shape);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void nsvg__addPath(struct NSVGParser *p, char closed) {
Shinya Kitaoka 120a6e
  struct NSVGAttrib *attr = nsvg__getAttr(p);
Shinya Kitaoka 120a6e
  struct NSVGpath *path   = NULL;
Shinya Kitaoka 120a6e
  int i;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (p->npts == 0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (closed) nsvg__lineTo(p, p->pts[0], p->pts[1]);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  path = (struct NSVGpath *)malloc(sizeof(struct NSVGpath));
Shinya Kitaoka 120a6e
  if (path == NULL) goto error;
Shinya Kitaoka 120a6e
  memset(path, 0, sizeof(struct NSVGpath));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  path->pts = (float *)malloc(p->npts * 2 * sizeof(float));
Shinya Kitaoka 120a6e
  if (path->pts == NULL) goto error;
Shinya Kitaoka 120a6e
  path->closed = closed;
Shinya Kitaoka 120a6e
  path->npts   = p->npts;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Transform path.
Shinya Kitaoka 120a6e
  for (i = 0; i < p->npts; ++i)
Shinya Kitaoka 120a6e
    nsvg__xformPoint(&path->pts[i * 2], &path->pts[i * 2 + 1], p->pts[i * 2],
Shinya Kitaoka 120a6e
                     p->pts[i * 2 + 1], attr->xform);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  path->next = p->plist;
Shinya Kitaoka 120a6e
  p->plist   = path;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
error:
Shinya Kitaoka 120a6e
  if (path != NULL) {
Shinya Kitaoka 120a6e
    if (path->pts != NULL) free(path->pts);
Shinya Kitaoka 120a6e
    free(path);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
const char *nsvg__getNextPathItem(const char *s, char *it) {
Shinya Kitaoka 120a6e
  int i = 0;
Shinya Kitaoka 120a6e
  it[0] = '\0';
Shinya Kitaoka 120a6e
  // Skip white spaces and commas
Shinya Kitaoka 120a6e
  while (*s && (nsvg__isspace(*s) || *s == ',')) s++;
Shinya Kitaoka 120a6e
  if (!*s) return s;
Shinya Kitaoka 120a6e
  if (*s == '-' || *s == '+' || nsvg__isdigit(*s)) {
Shinya Kitaoka 120a6e
    // sign
Shinya Kitaoka 120a6e
    if (*s == '-' || *s == '+') {
Shinya Kitaoka 120a6e
      if (i < 63) it[i++] = *s;
Shinya Kitaoka 120a6e
      s++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // integer part
Shinya Kitaoka 120a6e
    while (*s && nsvg__isdigit(*s)) {
Shinya Kitaoka 120a6e
      if (i < 63) it[i++] = *s;
Shinya Kitaoka 120a6e
      s++;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (*s == '.') {
Shinya Kitaoka 120a6e
      // decimal point
Shinya Kitaoka 120a6e
      if (i < 63) it[i++] = *s;
Shinya Kitaoka 120a6e
      s++;
Shinya Kitaoka 120a6e
      // fraction part
Shinya Kitaoka 120a6e
      while (*s && nsvg__isdigit(*s)) {
Shinya Kitaoka 120a6e
        if (i < 63) it[i++] = *s;
Shinya Kitaoka 120a6e
        s++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    // exponent
Shinya Kitaoka 120a6e
    if (*s == 'e' || *s == 'E') {
Shinya Kitaoka 120a6e
      if (i < 63) it[i++] = *s;
Shinya Kitaoka 120a6e
      s++;
Shinya Kitaoka 120a6e
      if (*s == '-' || *s == '+') {
Shinya Kitaoka 120a6e
        if (i < 63) it[i++] = *s;
Shinya Kitaoka 120a6e
        s++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      while (*s && nsvg__isdigit(*s)) {
Shinya Kitaoka 120a6e
        if (i < 63) it[i++] = *s;
Shinya Kitaoka 120a6e
        s++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    it[i] = '\0';
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Parse command
Shinya Kitaoka 120a6e
    it[0] = *s++;
Shinya Kitaoka 120a6e
    it[1] = '\0';
Shinya Kitaoka 120a6e
    return s;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return s;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
#define NSVG_RGB(r, g, b)                                                      \
Shinya Kitaoka 120a6e
  (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16))
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
unsigned int nsvg__parseColorHex(const char *str) {
Shinya Kitaoka 120a6e
  unsigned int c = 0, r = 0, g = 0, b = 0;
Shinya Kitaoka 120a6e
  int n = 0;
Shinya Kitaoka 120a6e
  str++;  // skip #
Shinya Kitaoka 120a6e
  // Calculate number of characters.
Shinya Kitaoka 120a6e
  while (str[n] && !nsvg__isspace(str[n])) n++;
Shinya Kitaoka 120a6e
  if (n == 6) {
Shinya Kitaoka 120a6e
    sscanf(str, "%x", &c);
Shinya Kitaoka 120a6e
  } else if (n == 3) {
Shinya Kitaoka 120a6e
    sscanf(str, "%x", &c);
Shinya Kitaoka 120a6e
    c = (c & 0xf) | ((c & 0xf0) << 4) | ((c & 0xf00) << 8);
Shinya Kitaoka 120a6e
    c |= c << 4;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  r = (c >> 16) & 0xff;
Shinya Kitaoka 120a6e
  g = (c >> 8) & 0xff;
Shinya Kitaoka 120a6e
  b = c & 0xff;
Shinya Kitaoka 120a6e
  return NSVG_RGB(r, g, b);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
unsigned int nsvg__parseColorRGB(const char *str) {
Shinya Kitaoka 120a6e
  int r = -1, g = -1, b = -1;
Shinya Kitaoka 120a6e
  char s1[32] = "", s2[32] = "";
Shinya Kitaoka 120a6e
  sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b);
Shinya Kitaoka 120a6e
  if (strchr(s1, '%')) {
Shinya Kitaoka 120a6e
    return NSVG_RGB((r * 255) / 100, (g * 255) / 100, (b * 255) / 100);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    return NSVG_RGB(r, g, b);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct NSVGNamedColor {
Shinya Kitaoka 120a6e
  const char *name;
Shinya Kitaoka 120a6e
  unsigned int color;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct NSVGNamedColor nsvg__colors[] = {
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    {"red", NSVG_RGB(255, 0, 0)},
Shinya Kitaoka 120a6e
    {"green", NSVG_RGB(0, 128, 0)},
Shinya Kitaoka 120a6e
    {"blue", NSVG_RGB(0, 0, 255)},
Shinya Kitaoka 120a6e
    {"yellow", NSVG_RGB(255, 255, 0)},
Shinya Kitaoka 120a6e
    {"cyan", NSVG_RGB(0, 255, 255)},
Shinya Kitaoka 120a6e
    {"magenta", NSVG_RGB(255, 0, 255)},
Shinya Kitaoka 120a6e
    {"black", NSVG_RGB(0, 0, 0)},
Shinya Kitaoka 120a6e
    {"grey", NSVG_RGB(128, 128, 128)},
Shinya Kitaoka 120a6e
    {"gray", NSVG_RGB(128, 128, 128)},
Shinya Kitaoka 120a6e
    {"white", NSVG_RGB(255, 255, 255)},
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    {"aliceblue", NSVG_RGB(240, 248, 255)},
Shinya Kitaoka 120a6e
    {"antiquewhite", NSVG_RGB(250, 235, 215)},
Shinya Kitaoka 120a6e
    {"aqua", NSVG_RGB(0, 255, 255)},
Shinya Kitaoka 120a6e
    {"aquamarine", NSVG_RGB(127, 255, 212)},
Shinya Kitaoka 120a6e
    {"azure", NSVG_RGB(240, 255, 255)},
Shinya Kitaoka 120a6e
    {"beige", NSVG_RGB(245, 245, 220)},
Shinya Kitaoka 120a6e
    {"bisque", NSVG_RGB(255, 228, 196)},
Shinya Kitaoka 120a6e
    {"blanchedalmond", NSVG_RGB(255, 235, 205)},
Shinya Kitaoka 120a6e
    {"blueviolet", NSVG_RGB(138, 43, 226)},
Shinya Kitaoka 120a6e
    {"brown", NSVG_RGB(165, 42, 42)},
Shinya Kitaoka 120a6e
    {"burlywood", NSVG_RGB(222, 184, 135)},
Shinya Kitaoka 120a6e
    {"cadetblue", NSVG_RGB(95, 158, 160)},
Shinya Kitaoka 120a6e
    {"chartreuse", NSVG_RGB(127, 255, 0)},
Shinya Kitaoka 120a6e
    {"chocolate", NSVG_RGB(210, 105, 30)},
Shinya Kitaoka 120a6e
    {"coral", NSVG_RGB(255, 127, 80)},
Shinya Kitaoka 120a6e
    {"cornflowerblue", NSVG_RGB(100, 149, 237)},
Shinya Kitaoka 120a6e
    {"cornsilk", NSVG_RGB(255, 248, 220)},
Shinya Kitaoka 120a6e
    {"crimson", NSVG_RGB(220, 20, 60)},
Shinya Kitaoka 120a6e
    {"darkblue", NSVG_RGB(0, 0, 139)},
Shinya Kitaoka 120a6e
    {"darkcyan", NSVG_RGB(0, 139, 139)},
Shinya Kitaoka 120a6e
    {"darkgoldenrod", NSVG_RGB(184, 134, 11)},
Shinya Kitaoka 120a6e
    {"darkgray", NSVG_RGB(169, 169, 169)},
Shinya Kitaoka 120a6e
    {"darkgreen", NSVG_RGB(0, 100, 0)},
Shinya Kitaoka 120a6e
    {"darkgrey", NSVG_RGB(169, 169, 169)},
Shinya Kitaoka 120a6e
    {"darkkhaki", NSVG_RGB(189, 183, 107)},
Shinya Kitaoka 120a6e
    {"darkmagenta", NSVG_RGB(139, 0, 139)},
Shinya Kitaoka 120a6e
    {"darkolivegreen", NSVG_RGB(85, 107, 47)},
Shinya Kitaoka 120a6e
    {"darkorange", NSVG_RGB(255, 140, 0)},
Shinya Kitaoka 120a6e
    {"darkorchid", NSVG_RGB(153, 50, 204)},
Shinya Kitaoka 120a6e
    {"darkred", NSVG_RGB(139, 0, 0)},
Shinya Kitaoka 120a6e
    {"darksalmon", NSVG_RGB(233, 150, 122)},
Shinya Kitaoka 120a6e
    {"darkseagreen", NSVG_RGB(143, 188, 143)},
Shinya Kitaoka 120a6e
    {"darkslateblue", NSVG_RGB(72, 61, 139)},
Shinya Kitaoka 120a6e
    {"darkslategray", NSVG_RGB(47, 79, 79)},
Shinya Kitaoka 120a6e
    {"darkslategrey", NSVG_RGB(47, 79, 79)},
Shinya Kitaoka 120a6e
    {"darkturquoise", NSVG_RGB(0, 206, 209)},
Shinya Kitaoka 120a6e
    {"darkviolet", NSVG_RGB(148, 0, 211)},
Shinya Kitaoka 120a6e
    {"deeppink", NSVG_RGB(255, 20, 147)},
Shinya Kitaoka 120a6e
    {"deepskyblue", NSVG_RGB(0, 191, 255)},
Shinya Kitaoka 120a6e
    {"dimgray", NSVG_RGB(105, 105, 105)},
Shinya Kitaoka 120a6e
    {"dimgrey", NSVG_RGB(105, 105, 105)},
Shinya Kitaoka 120a6e
    {"dodgerblue", NSVG_RGB(30, 144, 255)},
Shinya Kitaoka 120a6e
    {"firebrick", NSVG_RGB(178, 34, 34)},
Shinya Kitaoka 120a6e
    {"floralwhite", NSVG_RGB(255, 250, 240)},
Shinya Kitaoka 120a6e
    {"forestgreen", NSVG_RGB(34, 139, 34)},
Shinya Kitaoka 120a6e
    {"fuchsia", NSVG_RGB(255, 0, 255)},
Shinya Kitaoka 120a6e
    {"gainsboro", NSVG_RGB(220, 220, 220)},
Shinya Kitaoka 120a6e
    {"ghostwhite", NSVG_RGB(248, 248, 255)},
Shinya Kitaoka 120a6e
    {"gold", NSVG_RGB(255, 215, 0)},
Shinya Kitaoka 120a6e
    {"goldenrod", NSVG_RGB(218, 165, 32)},
Shinya Kitaoka 120a6e
    {"greenyellow", NSVG_RGB(173, 255, 47)},
Shinya Kitaoka 120a6e
    {"honeydew", NSVG_RGB(240, 255, 240)},
Shinya Kitaoka 120a6e
    {"hotpink", NSVG_RGB(255, 105, 180)},
Shinya Kitaoka 120a6e
    {"indianred", NSVG_RGB(205, 92, 92)},
Shinya Kitaoka 120a6e
    {"indigo", NSVG_RGB(75, 0, 130)},
Shinya Kitaoka 120a6e
    {"ivory", NSVG_RGB(255, 255, 240)},
Shinya Kitaoka 120a6e
    {"khaki", NSVG_RGB(240, 230, 140)},
Shinya Kitaoka 120a6e
    {"lavender", NSVG_RGB(230, 230, 250)},
Shinya Kitaoka 120a6e
    {"lavenderblush", NSVG_RGB(255, 240, 245)},
Shinya Kitaoka 120a6e
    {"lawngreen", NSVG_RGB(124, 252, 0)},
Shinya Kitaoka 120a6e
    {"lemonchiffon", NSVG_RGB(255, 250, 205)},
Shinya Kitaoka 120a6e
    {"lightblue", NSVG_RGB(173, 216, 230)},
Shinya Kitaoka 120a6e
    {"lightcoral", NSVG_RGB(240, 128, 128)},
Shinya Kitaoka 120a6e
    {"lightcyan", NSVG_RGB(224, 255, 255)},
Shinya Kitaoka 120a6e
    {"lightgoldenrodyellow", NSVG_RGB(250, 250, 210)},
Shinya Kitaoka 120a6e
    {"lightgray", NSVG_RGB(211, 211, 211)},
Shinya Kitaoka 120a6e
    {"lightgreen", NSVG_RGB(144, 238, 144)},
Shinya Kitaoka 120a6e
    {"lightgrey", NSVG_RGB(211, 211, 211)},
Shinya Kitaoka 120a6e
    {"lightpink", NSVG_RGB(255, 182, 193)},
Shinya Kitaoka 120a6e
    {"lightsalmon", NSVG_RGB(255, 160, 122)},
Shinya Kitaoka 120a6e
    {"lightseagreen", NSVG_RGB(32, 178, 170)},
Shinya Kitaoka 120a6e
    {"lightskyblue", NSVG_RGB(135, 206, 250)},
Shinya Kitaoka 120a6e
    {"lightslategray", NSVG_RGB(119, 136, 153)},
Shinya Kitaoka 120a6e
    {"lightslategrey", NSVG_RGB(119, 136, 153)},
Shinya Kitaoka 120a6e
    {"lightsteelblue", NSVG_RGB(176, 196, 222)},
Shinya Kitaoka 120a6e
    {"lightyellow", NSVG_RGB(255, 255, 224)},
Shinya Kitaoka 120a6e
    {"lime", NSVG_RGB(0, 255, 0)},
Shinya Kitaoka 120a6e
    {"limegreen", NSVG_RGB(50, 205, 50)},
Shinya Kitaoka 120a6e
    {"linen", NSVG_RGB(250, 240, 230)},
Shinya Kitaoka 120a6e
    {"maroon", NSVG_RGB(128, 0, 0)},
Shinya Kitaoka 120a6e
    {"mediumaquamarine", NSVG_RGB(102, 205, 170)},
Shinya Kitaoka 120a6e
    {"mediumblue", NSVG_RGB(0, 0, 205)},
Shinya Kitaoka 120a6e
    {"mediumorchid", NSVG_RGB(186, 85, 211)},
Shinya Kitaoka 120a6e
    {"mediumpurple", NSVG_RGB(147, 112, 219)},
Shinya Kitaoka 120a6e
    {"mediumseagreen", NSVG_RGB(60, 179, 113)},
Shinya Kitaoka 120a6e
    {"mediumslateblue", NSVG_RGB(123, 104, 238)},
Shinya Kitaoka 120a6e
    {"mediumspringgreen", NSVG_RGB(0, 250, 154)},
Shinya Kitaoka 120a6e
    {"mediumturquoise", NSVG_RGB(72, 209, 204)},
Shinya Kitaoka 120a6e
    {"mediumvioletred", NSVG_RGB(199, 21, 133)},
Shinya Kitaoka 120a6e
    {"midnightblue", NSVG_RGB(25, 25, 112)},
Shinya Kitaoka 120a6e
    {"mintcream", NSVG_RGB(245, 255, 250)},
Shinya Kitaoka 120a6e
    {"mistyrose", NSVG_RGB(255, 228, 225)},
Shinya Kitaoka 120a6e
    {"moccasin", NSVG_RGB(255, 228, 181)},
Shinya Kitaoka 120a6e
    {"navajowhite", NSVG_RGB(255, 222, 173)},
Shinya Kitaoka 120a6e
    {"navy", NSVG_RGB(0, 0, 128)},
Shinya Kitaoka 120a6e
    {"oldlace", NSVG_RGB(253, 245, 230)},
Shinya Kitaoka 120a6e
    {"olive", NSVG_RGB(128, 128, 0)},
Shinya Kitaoka 120a6e
    {"olivedrab", NSVG_RGB(107, 142, 35)},
Shinya Kitaoka 120a6e
    {"orange", NSVG_RGB(255, 165, 0)},
Shinya Kitaoka 120a6e
    {"orangered", NSVG_RGB(255, 69, 0)},
Shinya Kitaoka 120a6e
    {"orchid", NSVG_RGB(218, 112, 214)},
Shinya Kitaoka 120a6e
    {"palegoldenrod", NSVG_RGB(238, 232, 170)},
Shinya Kitaoka 120a6e
    {"palegreen", NSVG_RGB(152, 251, 152)},
Shinya Kitaoka 120a6e
    {"paleturquoise", NSVG_RGB(175, 238, 238)},
Shinya Kitaoka 120a6e
    {"palevioletred", NSVG_RGB(219, 112, 147)},
Shinya Kitaoka 120a6e
    {"papayawhip", NSVG_RGB(255, 239, 213)},
Shinya Kitaoka 120a6e
    {"peachpuff", NSVG_RGB(255, 218, 185)},
Shinya Kitaoka 120a6e
    {"peru", NSVG_RGB(205, 133, 63)},
Shinya Kitaoka 120a6e
    {"pink", NSVG_RGB(255, 192, 203)},
Shinya Kitaoka 120a6e
    {"plum", NSVG_RGB(221, 160, 221)},
Shinya Kitaoka 120a6e
    {"powderblue", NSVG_RGB(176, 224, 230)},
Shinya Kitaoka 120a6e
    {"purple", NSVG_RGB(128, 0, 128)},
Shinya Kitaoka 120a6e
    {"rosybrown", NSVG_RGB(188, 143, 143)},
Shinya Kitaoka 120a6e
    {"royalblue", NSVG_RGB(65, 105, 225)},
Shinya Kitaoka 120a6e
    {"saddlebrown", NSVG_RGB(139, 69, 19)},
Shinya Kitaoka 120a6e
    {"salmon", NSVG_RGB(250, 128, 114)},
Shinya Kitaoka 120a6e
    {"sandybrown", NSVG_RGB(244, 164, 96)},
Shinya Kitaoka 120a6e
    {"seagreen", NSVG_RGB(46, 139, 87)},
Shinya Kitaoka 120a6e
    {"seashell", NSVG_RGB(255, 245, 238)},
Shinya Kitaoka 120a6e
    {"sienna", NSVG_RGB(160, 82, 45)},
Shinya Kitaoka 120a6e
    {"silver", NSVG_RGB(192, 192, 192)},
Shinya Kitaoka 120a6e
    {"skyblue", NSVG_RGB(135, 206, 235)},
Shinya Kitaoka 120a6e
    {"slateblue", NSVG_RGB(106, 90, 205)},
Shinya Kitaoka 120a6e
    {"slategray", NSVG_RGB(112, 128, 144)},
Shinya Kitaoka 120a6e
    {"slategrey", NSVG_RGB(112, 128, 144)},
Shinya Kitaoka 120a6e
    {"snow", NSVG_RGB(255, 250, 250)},
Shinya Kitaoka 120a6e
    {"springgreen", NSVG_RGB(0, 255, 127)},
Shinya Kitaoka 120a6e
    {"steelblue", NSVG_RGB(70, 130, 180)},
Shinya Kitaoka 120a6e
    {"tan", NSVG_RGB(210, 180, 140)},
Shinya Kitaoka 120a6e
    {"teal", NSVG_RGB(0, 128, 128)},
Shinya Kitaoka 120a6e
    {"thistle", NSVG_RGB(216, 191, 216)},
Shinya Kitaoka 120a6e
    {"tomato", NSVG_RGB(255, 99, 71)},
Shinya Kitaoka 120a6e
    {"turquoise", NSVG_RGB(64, 224, 208)},
Shinya Kitaoka 120a6e
    {"violet", NSVG_RGB(238, 130, 238)},
Shinya Kitaoka 120a6e
    {"wheat", NSVG_RGB(245, 222, 179)},
Shinya Kitaoka 120a6e
    {"whitesmoke", NSVG_RGB(245, 245, 245)},
Shinya Kitaoka 120a6e
    {"yellowgreen", NSVG_RGB(154, 205, 50)},
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
unsigned int nsvg__parseColorName(const char *str) {
Shinya Kitaoka 120a6e
  int i, ncolors = sizeof(nsvg__colors) / sizeof(struct NSVGNamedColor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < ncolors; i++) {
Shinya Kitaoka 120a6e
    if (strcmp(nsvg__colors[i].name, str) == 0) {
Shinya Kitaoka 120a6e
      return nsvg__colors[i].color;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return NSVG_RGB(128, 128, 128);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
unsigned int nsvg__parseColor(const char *str) {
Shinya Kitaoka 120a6e
  int len = 0;
Shinya Kitaoka 120a6e
  while (*str == ' ') ++str;
Shinya Kitaoka 120a6e
  len = (int)strlen(str);
Shinya Kitaoka 120a6e
  if (len >= 1 && *str == '#')
Shinya Kitaoka 120a6e
    return nsvg__parseColorHex(str);
Shinya Kitaoka 120a6e
  else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' &&
Shinya Kitaoka 120a6e
           str[3] == '(')
Shinya Kitaoka 120a6e
    return nsvg__parseColorRGB(str);
Shinya Kitaoka 120a6e
  return nsvg__parseColorName(str);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
float nsvg__parseFloat(const char *str) {
Shinya Kitaoka 120a6e
  while (*str == ' ') ++str;
Shinya Kitaoka 120a6e
  return (float)atof(str);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseTransformArgs(const char *str, float *args, int maxNa, int *na) {
Shinya Kitaoka 120a6e
  const char *end;
Shinya Kitaoka 120a6e
  const char *ptr;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *na = 0;
Shinya Kitaoka 120a6e
  ptr = str;
Shinya Kitaoka 120a6e
  while (*ptr && *ptr != '(') ++ptr;
Shinya Kitaoka 120a6e
  if (*ptr == 0) return 1;
Shinya Kitaoka 120a6e
  end = ptr;
Shinya Kitaoka 120a6e
  while (*end && *end != ')') ++end;
Shinya Kitaoka 120a6e
  if (*end == 0) return 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (ptr < end) {
Shinya Kitaoka 120a6e
    if (nsvg__isnum(*ptr)) {
Shinya Kitaoka 120a6e
      if (*na >= maxNa) return 0;
Shinya Kitaoka 120a6e
      args[(*na)++] = (float)atof(ptr);
Shinya Kitaoka 120a6e
      while (ptr < end && nsvg__isnum(*ptr)) ++ptr;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      ++ptr;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return (int)(end - str);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseMatrix(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  float t[6];
Shinya Kitaoka 120a6e
  int na  = 0;
Shinya Kitaoka 120a6e
  int len = nsvg__parseTransformArgs(str, t, 6, &na);
Shinya Kitaoka 120a6e
  if (na != 6) return len;
Shinya Kitaoka 120a6e
  nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
  return len;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseTranslate(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  float args[2];
Shinya Kitaoka 120a6e
  float t[6];
Shinya Kitaoka 120a6e
  int na               = 0;
Shinya Kitaoka 120a6e
  int len              = nsvg__parseTransformArgs(str, args, 2, &na);
Shinya Kitaoka 120a6e
  if (na == 1) args[1] = 0.0;
Shinya Kitaoka 120a6e
  nsvg__xformSetTranslation(t, args[0], args[1]);
Shinya Kitaoka 120a6e
  nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
  return len;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseScale(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  float args[2];
Shinya Kitaoka 120a6e
  int na = 0;
Shinya Kitaoka 120a6e
  float t[6];
Shinya Kitaoka 120a6e
  int len              = nsvg__parseTransformArgs(str, args, 2, &na);
Shinya Kitaoka 120a6e
  if (na == 1) args[1] = args[0];
Shinya Kitaoka 120a6e
  nsvg__xformSetScale(t, args[0], args[1]);
Shinya Kitaoka 120a6e
  nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
  return len;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseSkewX(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  float args[1];
Shinya Kitaoka 120a6e
  int na = 0;
Shinya Kitaoka 120a6e
  float t[6];
Shinya Kitaoka 120a6e
  int len = nsvg__parseTransformArgs(str, args, 1, &na);
Shinya Kitaoka 120a6e
  nsvg__xformSetSkewX(t, args[0] / 180.0f * NSVG_PI);
Shinya Kitaoka 120a6e
  nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
  return len;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseSkewY(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  float args[1];
Shinya Kitaoka 120a6e
  int na = 0;
Shinya Kitaoka 120a6e
  float t[6];
Shinya Kitaoka 120a6e
  int len = nsvg__parseTransformArgs(str, args, 1, &na);
Shinya Kitaoka 120a6e
  nsvg__xformSetSkewY(t, args[0] / 180.0f * NSVG_PI);
Shinya Kitaoka 120a6e
  nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
  return len;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseRotate(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  float args[3];
Shinya Kitaoka 120a6e
  int na = 0;
Shinya Kitaoka 120a6e
  float t[6];
Shinya Kitaoka 120a6e
  int len              = nsvg__parseTransformArgs(str, args, 3, &na);
Shinya Kitaoka 120a6e
  if (na == 1) args[1] = args[2] = 0.0f;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (na > 1) {
Shinya Kitaoka 120a6e
    nsvg__xformSetTranslation(t, -args[1], -args[2]);
Shinya Kitaoka 120a6e
    nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__xformSetRotation(t, args[0] / 180.0f * NSVG_PI);
Shinya Kitaoka 120a6e
  nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (na > 1) {
Shinya Kitaoka 120a6e
    nsvg__xformSetTranslation(t, args[1], args[2]);
Shinya Kitaoka 120a6e
    nsvg__xformPremultiply(nsvg__getAttr(p)->xform, t);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return len;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseTransform(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  while (*str) {
Shinya Kitaoka 120a6e
    if (strncmp(str, "matrix", 6) == 0)
Shinya Kitaoka 120a6e
      str += nsvg__parseMatrix(p, str);
Shinya Kitaoka 120a6e
    else if (strncmp(str, "translate", 9) == 0)
Shinya Kitaoka 120a6e
      str += nsvg__parseTranslate(p, str);
Shinya Kitaoka 120a6e
    else if (strncmp(str, "scale", 5) == 0)
Shinya Kitaoka 120a6e
      str += nsvg__parseScale(p, str);
Shinya Kitaoka 120a6e
    else if (strncmp(str, "rotate", 6) == 0)
Shinya Kitaoka 120a6e
      str += nsvg__parseRotate(p, str);
Shinya Kitaoka 120a6e
    else if (strncmp(str, "skewX", 5) == 0)
Shinya Kitaoka 120a6e
      str += nsvg__parseSkewX(p, str);
Shinya Kitaoka 120a6e
    else if (strncmp(str, "skewY", 5) == 0)
Shinya Kitaoka 120a6e
      str += nsvg__parseSkewY(p, str);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      ++str;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void nsvg__parseStyle(struct NSVGParser *p, const char *str);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int nsvg__parseAttr(struct NSVGParser *p, const char *name, const char *value) {
Shinya Kitaoka 120a6e
  struct NSVGAttrib *attr = nsvg__getAttr(p);
Shinya Kitaoka 120a6e
  if (!attr) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (strcmp(name, "style") == 0) {
Shinya Kitaoka 120a6e
    nsvg__parseStyle(p, value);
Shinya Kitaoka 120a6e
  } else if (strcmp(name, "display") == 0) {
Shinya Kitaoka 120a6e
    if (strcmp(value, "none") == 0)
Shinya Kitaoka 120a6e
      attr->visible = 0;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      attr->visible = 1;
Shinya Kitaoka 120a6e
  } else if (strcmp(name, "fill") == 0) {
Shinya Kitaoka 120a6e
    if (strcmp(value, "none") == 0) {
Shinya Kitaoka 120a6e
      attr->hasFill = 0;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      attr->hasFill   = 1;
Shinya Kitaoka 120a6e
      attr->fillColor = nsvg__parseColor(value);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (strcmp(name, "fill-opacity") == 0) {
Shinya Kitaoka 120a6e
    attr->fillOpacity = nsvg__parseFloat(value);
Shinya Kitaoka 120a6e
  } else if (strcmp(name, "stroke") == 0) {
Shinya Kitaoka 120a6e
    if (strcmp(value, "none") == 0) {
Shinya Kitaoka 120a6e
      attr->hasStroke = 0;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      attr->hasStroke   = 1;
Shinya Kitaoka 120a6e
      attr->strokeColor = nsvg__parseColor(value);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else if (strcmp(name, "stroke-width") == 0) {
Shinya Kitaoka 120a6e
    attr->strokeWidth = nsvg__parseFloat(value);
Shinya Kitaoka 120a6e
  } else if (strcmp(name, "stroke-opacity") == 0) {
Shinya Kitaoka 120a6e
    attr->strokeOpacity = nsvg__parseFloat(value);
Shinya Kitaoka 120a6e
  } else if (strcmp(name, "transform") == 0) {
Shinya Kitaoka 120a6e
    nsvg__parseTransform(p, value);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    return 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return 1;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__parseNameValue(struct NSVGParser *p, const char *start,
Shinya Kitaoka 120a6e
                         const char *end) {
Shinya Kitaoka 120a6e
  const char *str;
Shinya Kitaoka 120a6e
  const char *val;
Shinya Kitaoka 120a6e
  char name[512];
Shinya Kitaoka 120a6e
  char value[512];
Shinya Kitaoka 120a6e
  int n;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  str = start;
Shinya Kitaoka 120a6e
  while (str < end && *str != ':') ++str;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  val = str;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Right Trim
Shinya Kitaoka 120a6e
  while (str > start && (*str == ':' || nsvg__isspace(*str))) --str;
Shinya Kitaoka 120a6e
  ++str;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  n              = (int)(str - start);
Shinya Kitaoka 120a6e
  if (n > 511) n = 511;
Shinya Kitaoka 120a6e
  if (n) memcpy(name, start, n);
Shinya Kitaoka 120a6e
  name[n] = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  n              = (int)(end - val);
Shinya Kitaoka 120a6e
  if (n > 511) n = 511;
Shinya Kitaoka 120a6e
  if (n) memcpy(value, val, n);
Shinya Kitaoka 120a6e
  value[n] = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return nsvg__parseAttr(p, name, value);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseStyle(struct NSVGParser *p, const char *str) {
Shinya Kitaoka 120a6e
  const char *start;
Shinya Kitaoka 120a6e
  const char *end;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  while (*str) {
Shinya Kitaoka 120a6e
    // Left Trim
Shinya Kitaoka 120a6e
    while (*str && nsvg__isspace(*str)) ++str;
Shinya Kitaoka 120a6e
    start = str;
Shinya Kitaoka 120a6e
    while (*str && *str != ';') ++str;
Shinya Kitaoka 120a6e
    end = str;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Right Trim
Shinya Kitaoka 120a6e
    while (end > start && (*end == ';' || nsvg__isspace(*end))) --end;
Shinya Kitaoka 120a6e
    ++end;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__parseNameValue(p, start, end);
Shinya Kitaoka 120a6e
    if (*str) ++str;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseAttribs(struct NSVGParser *p, const char **attr) {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (strcmp(attr[i], "style") == 0)
Shinya Kitaoka 120a6e
      nsvg__parseStyle(p, attr[i + 1]);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      nsvg__parseAttr(p, attr[i], attr[i + 1]);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int nsvg__getArgsPerElement(char cmd) {
Shinya Kitaoka 120a6e
  switch (cmd) {
Shinya Kitaoka 120a6e
  case 'v':
Shinya Kitaoka 120a6e
  case 'V':
Shinya Kitaoka 120a6e
  case 'h':
Shinya Kitaoka 120a6e
  case 'H':
Shinya Kitaoka 120a6e
    return 1;
Shinya Kitaoka 120a6e
  case 'm':
Shinya Kitaoka 120a6e
  case 'M':
Shinya Kitaoka 120a6e
  case 'l':
Shinya Kitaoka 120a6e
  case 'L':
Shinya Kitaoka 120a6e
  case 't':
Shinya Kitaoka 120a6e
  case 'T':
Shinya Kitaoka 120a6e
    return 2;
Shinya Kitaoka 120a6e
  case 'q':
Shinya Kitaoka 120a6e
  case 'Q':
Shinya Kitaoka 120a6e
  case 's':
Shinya Kitaoka 120a6e
  case 'S':
Shinya Kitaoka 120a6e
    return 4;
Shinya Kitaoka 120a6e
  case 'c':
Shinya Kitaoka 120a6e
  case 'C':
Shinya Kitaoka 120a6e
    return 6;
Shinya Kitaoka 120a6e
  case 'a':
Shinya Kitaoka 120a6e
  case 'A':
Shinya Kitaoka 120a6e
    return 7;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return 0;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__pathMoveTo(struct NSVGParser *p, float *cpx, float *cpy, float *args,
Shinya Kitaoka 120a6e
                      int rel) {
Shinya Kitaoka 120a6e
  if (rel) {
Shinya Kitaoka 120a6e
    *cpx += args[0];
Shinya Kitaoka 120a6e
    *cpy += args[1];
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    *cpx = args[0];
Shinya Kitaoka 120a6e
    *cpy = args[1];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  nsvg__moveTo(p, *cpx, *cpy);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__pathLineTo(struct NSVGParser *p, float *cpx, float *cpy, float *args,
Shinya Kitaoka 120a6e
                      int rel) {
Shinya Kitaoka 120a6e
  if (rel) {
Shinya Kitaoka 120a6e
    *cpx += args[0];
Shinya Kitaoka 120a6e
    *cpy += args[1];
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    *cpx = args[0];
Shinya Kitaoka 120a6e
    *cpy = args[1];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  nsvg__lineTo(p, *cpx, *cpy);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__pathHLineTo(struct NSVGParser *p, float *cpx, float *cpy,
Shinya Kitaoka 120a6e
                       float *args, int rel) {
Shinya Kitaoka 120a6e
  if (rel)
Shinya Kitaoka 120a6e
    *cpx += args[0];
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    *cpx = args[0];
Shinya Kitaoka 120a6e
  nsvg__lineTo(p, *cpx, *cpy);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__pathVLineTo(struct NSVGParser *p, float *cpx, float *cpy,
Shinya Kitaoka 120a6e
                       float *args, int rel) {
Shinya Kitaoka 120a6e
  if (rel)
Shinya Kitaoka 120a6e
    *cpy += args[0];
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    *cpy = args[0];
Shinya Kitaoka 120a6e
  nsvg__lineTo(p, *cpx, *cpy);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void nsvg__pathCubicBezTo(struct NSVGParser *p, float *cpx, float *cpy,
Shinya Kitaoka 120a6e
                          float *cpx2, float *cpy2, float *args, int rel) {
Shinya Kitaoka 120a6e
  float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  x1 = *cpx;
Shinya Kitaoka 120a6e
  y1 = *cpy;
Shinya Kitaoka 120a6e
  if (rel) {
Shinya Kitaoka 120a6e
    cx1 = *cpx + args[0];
Shinya Kitaoka 120a6e
    cy1 = *cpy + args[1];
Shinya Kitaoka 120a6e
    cx2 = *cpx + args[2];
Shinya Kitaoka 120a6e
    cy2 = *cpy + args[3];
Shinya Kitaoka 120a6e
    x2  = *cpx + args[4];
Shinya Kitaoka 120a6e
    y2  = *cpy + args[5];
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    cx1 = args[0];
Shinya Kitaoka 120a6e
    cy1 = args[1];
Shinya Kitaoka 120a6e
    cx2 = args[2];
Shinya Kitaoka 120a6e
    cy2 = args[3];
Shinya Kitaoka 120a6e
    x2  = args[4];
Shinya Kitaoka 120a6e
    y2  = args[5];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *cpx2 = cx2;
Shinya Kitaoka 120a6e
  *cpy2 = cy2;
Shinya Kitaoka 120a6e
  *cpx  = x2;
Shinya Kitaoka 120a6e
  *cpy  = y2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void nsvg__pathCubicBezShortTo(struct NSVGParser *p, float *cpx, float *cpy,
Shinya Kitaoka 120a6e
                               float *cpx2, float *cpy2, float *args, int rel) {
Shinya Kitaoka 120a6e
  float x1, y1, x2, y2, cx1, cy1, cx2, cy2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  x1 = *cpx;
Shinya Kitaoka 120a6e
  y1 = *cpy;
Shinya Kitaoka 120a6e
  if (rel) {
Shinya Kitaoka 120a6e
    cx2 = *cpx + args[0];
Shinya Kitaoka 120a6e
    cy2 = *cpy + args[1];
Shinya Kitaoka 120a6e
    x2  = *cpx + args[2];
Shinya Kitaoka 120a6e
    y2  = *cpy + args[3];
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    cx2 = args[0];
Shinya Kitaoka 120a6e
    cy2 = args[1];
Shinya Kitaoka 120a6e
    x2  = args[2];
Shinya Kitaoka 120a6e
    y2  = args[3];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  cx1 = 2 * x1 - *cpx2;
Shinya Kitaoka 120a6e
  cy1 = 2 * y1 - *cpy2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *cpx2 = cx2;
Shinya Kitaoka 120a6e
  *cpy2 = cy2;
Shinya Kitaoka 120a6e
  *cpx  = x2;
Shinya Kitaoka 120a6e
  *cpy  = y2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void nsvg__pathQuadBezTo(struct NSVGParser *p, float *cpx, float *cpy,
Shinya Kitaoka 120a6e
                         float *cpx2, float *cpy2, float *args, int rel) {
Shinya Kitaoka 120a6e
  float x1, y1, x2, y2, cx, cy;
Shinya Kitaoka 120a6e
  float cx1, cy1, cx2, cy2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  x1 = *cpx;
Shinya Kitaoka 120a6e
  y1 = *cpy;
Shinya Kitaoka 120a6e
  if (rel) {
Shinya Kitaoka 120a6e
    cx = *cpx + args[0];
Shinya Kitaoka 120a6e
    cy = *cpy + args[1];
Shinya Kitaoka 120a6e
    x2 = *cpx + args[2];
Shinya Kitaoka 120a6e
    y2 = *cpy + args[3];
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    cx = args[0];
Shinya Kitaoka 120a6e
    cy = args[1];
Shinya Kitaoka 120a6e
    x2 = args[2];
Shinya Kitaoka 120a6e
    y2 = args[3];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Convert to cubix bezier
Shinya Kitaoka 120a6e
  cx1 = x1 + 2.0f / 3.0f * (cx - x1);
Shinya Kitaoka 120a6e
  cy1 = y1 + 2.0f / 3.0f * (cy - y1);
Shinya Kitaoka 120a6e
  cx2 = x2 + 2.0f / 3.0f * (cx - x2);
Shinya Kitaoka 120a6e
  cy2 = y2 + 2.0f / 3.0f * (cy - y2);
Shinya Kitaoka 120a6e
  nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *cpx2 = cx;
Shinya Kitaoka 120a6e
  *cpy2 = cy;
Shinya Kitaoka 120a6e
  *cpx  = x2;
Shinya Kitaoka 120a6e
  *cpy  = y2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void nsvg__pathQuadBezShortTo(struct NSVGParser *p, float *cpx, float *cpy,
Shinya Kitaoka 120a6e
                              float *cpx2, float *cpy2, float *args, int rel) {
Shinya Kitaoka 120a6e
  float x1, y1, x2, y2, cx, cy;
Shinya Kitaoka 120a6e
  float cx1, cy1, cx2, cy2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  x1 = *cpx;
Shinya Kitaoka 120a6e
  y1 = *cpy;
Shinya Kitaoka 120a6e
  if (rel) {
Shinya Kitaoka 120a6e
    x2 = *cpx + args[0];
Shinya Kitaoka 120a6e
    y2 = *cpy + args[1];
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    x2 = args[0];
Shinya Kitaoka 120a6e
    y2 = args[1];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  cx = 2 * x1 - *cpx2;
Shinya Kitaoka 120a6e
  cy = 2 * y1 - *cpy2;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Convert to cubix bezier
Shinya Kitaoka 120a6e
  cx1 = x1 + 2.0f / 3.0f * (cx - x1);
Shinya Kitaoka 120a6e
  cy1 = y1 + 2.0f / 3.0f * (cy - y1);
Shinya Kitaoka 120a6e
  cx2 = x2 + 2.0f / 3.0f * (cx - x2);
Shinya Kitaoka 120a6e
  cy2 = y2 + 2.0f / 3.0f * (cy - y2);
Shinya Kitaoka 120a6e
  nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *cpx2 = cx;
Shinya Kitaoka 120a6e
  *cpy2 = cy;
Shinya Kitaoka 120a6e
  *cpx  = x2;
Shinya Kitaoka 120a6e
  *cpy  = y2;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
float nsvg__sqr(float x) { return x * x; }
Toshihiro Shimizu 890ddd
float nsvg__vmag(float x, float y) { return sqrtf(x * x + y * y); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
float nsvg__vecrat(float ux, float uy, float vx, float vy) {
Shinya Kitaoka 120a6e
  return (ux * vx + uy * vy) / (nsvg__vmag(ux, uy) * nsvg__vmag(vx, vy));
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
float nsvg__vecang(float ux, float uy, float vx, float vy) {
Shinya Kitaoka 120a6e
  float r          = nsvg__vecrat(ux, uy, vx, vy);
Shinya Kitaoka 120a6e
  if (r < -1.0f) r = -1.0f;
Shinya Kitaoka 120a6e
  if (r > 1.0f) r  = 1.0f;
Shinya Kitaoka 120a6e
  return ((ux * vy < uy * vx) ? -1.0f : 1.0f) * acosf(r);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__pathArcTo(struct NSVGParser *p, float *cpx, float *cpy, float *args,
Shinya Kitaoka 120a6e
                     int rel) {
Shinya Kitaoka 120a6e
  // Ported from canvg (https://code.google.com/p/canvg/)
Shinya Kitaoka 120a6e
  float rx, ry, rotx;
Shinya Kitaoka 120a6e
  float x1, y1, x2, y2, cx, cy, dx, dy, d;
Shinya Kitaoka 120a6e
  float x1p, y1p, cxp, cyp, s, sa, sb;
Shinya Kitaoka 120a6e
  float ux, uy, vx, vy, a1, da;
Shinya Kitaoka 120a6e
  float x, y, tanx, tany, a, px, py, ptanx, ptany, t[6];
Shinya Kitaoka 120a6e
  float sinrx, cosrx;
Shinya Kitaoka 120a6e
  int fa, fs;
Shinya Kitaoka 120a6e
  int i, ndivs;
Shinya Kitaoka 120a6e
  float hda, kappa;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rx   = fabsf(args[0]);                 // y radius
Shinya Kitaoka 120a6e
  ry   = fabsf(args[1]);                 // x radius
Shinya Kitaoka 120a6e
  rotx = args[2] / 180.0f * NSVG_PI;     // x rotation engle
Shinya Kitaoka 120a6e
  fa   = fabsf(args[3]) > 1e-6 ? 1 : 0;  // Large arc
Shinya Kitaoka 120a6e
  fs   = fabsf(args[4]) > 1e-6 ? 1 : 0;  // Sweep direction
Shinya Kitaoka 120a6e
  x1   = *cpx;                           // start point
Shinya Kitaoka 120a6e
  y1   = *cpy;
Shinya Kitaoka 120a6e
  if (rel) {  // end point
Shinya Kitaoka 120a6e
    x2 = *cpx + args[5];
Shinya Kitaoka 120a6e
    y2 = *cpy + args[6];
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    x2 = args[5];
Shinya Kitaoka 120a6e
    y2 = args[6];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  dx = x1 - x2;
Shinya Kitaoka 120a6e
  dy = y1 - y2;
Shinya Kitaoka 120a6e
  d  = sqrtf(dx * dx + dy * dy);
Shinya Kitaoka 120a6e
  if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) {
Shinya Kitaoka 120a6e
    // The arc degenerates to a line
Shinya Kitaoka 120a6e
    nsvg__lineTo(p, x2, y2);
Shinya Kitaoka 120a6e
    *cpx = x2;
Shinya Kitaoka 120a6e
    *cpy = y2;
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  sinrx = sinf(rotx);
Shinya Kitaoka 120a6e
  cosrx = cosf(rotx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Convert to center point parameterization.
Shinya Kitaoka 120a6e
  // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
Shinya Kitaoka 120a6e
  // 1) Compute x1', y1'
Shinya Kitaoka 120a6e
  x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f;
Shinya Kitaoka 120a6e
  y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f;
Shinya Kitaoka 120a6e
  d   = nsvg__sqr(x1p) / nsvg__sqr(rx) + nsvg__sqr(y1p) / nsvg__sqr(ry);
Shinya Kitaoka 120a6e
  if (d > 1) {
Shinya Kitaoka 120a6e
    d = sqrtf(d);
Shinya Kitaoka 120a6e
    rx *= d;
Shinya Kitaoka 120a6e
    ry *= d;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  // 2) Compute cx', cy'
Shinya Kitaoka 120a6e
  s  = 0.0f;
Shinya Kitaoka 120a6e
  sa = nsvg__sqr(rx) * nsvg__sqr(ry) - nsvg__sqr(rx) * nsvg__sqr(y1p) -
Shinya Kitaoka 120a6e
       nsvg__sqr(ry) * nsvg__sqr(x1p);
Shinya Kitaoka 120a6e
  sb = nsvg__sqr(rx) * nsvg__sqr(y1p) + nsvg__sqr(ry) * nsvg__sqr(x1p);
Shinya Kitaoka 120a6e
  if (sa < 0.0f) sa = 0.0f;
Shinya Kitaoka 120a6e
  if (sb > 0.0f) s  = sqrtf(sa / sb);
Shinya Kitaoka 120a6e
  if (fa == fs) s   = -s;
Shinya Kitaoka 120a6e
  cxp               = s * rx * y1p / ry;
Shinya Kitaoka 120a6e
  cyp               = s * -ry * x1p / rx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // 3) Compute cx,cy from cx',cy'
Shinya Kitaoka 120a6e
  cx = (x1 + x2) / 2.0f + cosrx * cxp - sinrx * cyp;
Shinya Kitaoka 120a6e
  cy = (y1 + y2) / 2.0f + sinrx * cxp + cosrx * cyp;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // 4) Calculate theta1, and delta theta.
Shinya Kitaoka 120a6e
  ux = (x1p - cxp) / rx;
Shinya Kitaoka 120a6e
  uy = (y1p - cyp) / ry;
Shinya Kitaoka 120a6e
  vx = (-x1p - cxp) / rx;
Shinya Kitaoka 120a6e
  vy = (-y1p - cyp) / ry;
Shinya Kitaoka 120a6e
  a1 = nsvg__vecang(1.0f, 0.0f, ux, uy);  // Initial angle
Shinya Kitaoka 120a6e
  da = nsvg__vecang(ux, uy, vx, vy);      // Delta angle
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //        if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI;
Shinya Kitaoka 120a6e
  //        if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (fa) {
Shinya Kitaoka 120a6e
    // Choose large arc
Shinya Kitaoka 120a6e
    if (da > 0.0f)
Shinya Kitaoka 120a6e
      da = da - 2 * NSVG_PI;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      da = 2 * NSVG_PI + da;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Approximate the arc using cubic spline segments.
Shinya Kitaoka 120a6e
  t[0] = cosrx;
Shinya Kitaoka 120a6e
  t[1] = sinrx;
Shinya Kitaoka 120a6e
  t[2] = -sinrx;
Shinya Kitaoka 120a6e
  t[3] = cosrx;
Shinya Kitaoka 120a6e
  t[4] = cx;
Shinya Kitaoka 120a6e
  t[5] = cy;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Split arc into max 90 degree segments.
Calabaraburus 676b4b
  ndivs                = (int)(ceil(fabsf(da)) / (NSVG_PI * 0.5f) + 0.5f);
Shinya Kitaoka 120a6e
  hda                  = (da / (float)ndivs) / 2.0f;
Shinya Kitaoka 120a6e
  kappa                = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda));
Shinya Kitaoka 120a6e
  if (da < 0.0f) kappa = -kappa;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i <= ndivs; i++) {
Shinya Kitaoka 120a6e
    a  = a1 + da * (i / (float)ndivs);
Shinya Kitaoka 120a6e
    dx = cosf(a);
Shinya Kitaoka 120a6e
    dy = sinf(a);
Shinya Kitaoka 120a6e
    nsvg__xformPoint(&x, &y, dx * rx, dy * ry, t);  // position
Shinya Kitaoka 120a6e
    nsvg__xformVec(&tanx, &tany, -dy * rx * kappa, dx * ry * kappa,
Shinya Kitaoka 120a6e
                   t);  // tangent
Shinya Kitaoka 120a6e
    if (i > 0)
Shinya Kitaoka 120a6e
      nsvg__cubicBezTo(p, px + ptanx, py + ptany, x - tanx, y - tany, x, y);
Shinya Kitaoka 120a6e
    px    = x;
Shinya Kitaoka 120a6e
    py    = y;
Shinya Kitaoka 120a6e
    ptanx = tanx;
Shinya Kitaoka 120a6e
    ptany = tany;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  *cpx = x2;
Shinya Kitaoka 120a6e
  *cpy = y2;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parsePath(struct NSVGParser *p, const char **attr) {
Shinya Kitaoka 120a6e
  const char *s;
Shinya Kitaoka 120a6e
  char cmd;
Shinya Kitaoka 120a6e
  float args[10];
Shinya Kitaoka 120a6e
  int nargs;
Shinya Kitaoka 120a6e
  int rargs;
Shinya Kitaoka 120a6e
  float cpx, cpy, cpx2, cpy2;
Shinya Kitaoka 120a6e
  const char *tmp[4];
Shinya Kitaoka 120a6e
  char closedFlag;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  char item[64];
Calabaraburus 7e96bc
  float prev_m_cpx, prev_m_cpy;
Calabaraburus 7e96bc
  bool prev_m_exists;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (strcmp(attr[i], "d") == 0) {
Shinya Kitaoka 120a6e
      s = attr[i + 1];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      nsvg__resetPath(p);
Shinya Kitaoka 120a6e
      cpx        = 0;
Shinya Kitaoka 120a6e
      cpy        = 0;
Shinya Kitaoka 120a6e
      closedFlag = 0;
Shinya Kitaoka 120a6e
      nargs      = 0;
Calabaraburus 7e96bc
      prev_m_exists = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      while (*s) {
Shinya Kitaoka 120a6e
        s = nsvg__getNextPathItem(s, item);
Shinya Kitaoka 120a6e
        if (!*item) break;
Shinya Kitaoka 120a6e
        if (nsvg__isnum(item[0])) {
Shinya Kitaoka 120a6e
          if (nargs < 10) args[nargs++] = (float)atof(item);
Shinya Kitaoka 120a6e
          if (nargs >= rargs) {
Shinya Kitaoka 120a6e
            switch (cmd) {
Shinya Kitaoka 120a6e
            case 'm':
Shinya Kitaoka 120a6e
            case 'M':
Calabaraburus 7e96bc
			 
Calabaraburus 7e96bc
              // If moveto is relative it relative to previous moveto point
Calabaraburus 7e96bc
              if (cmd == 'm' && prev_m_exists) {
Calabaraburus 7e96bc
                cpx = prev_m_cpx;
Calabaraburus 7e96bc
                cpy = prev_m_cpy;
Calabaraburus 7e96bc
              }
Calabaraburus 7e96bc
              
Shinya Kitaoka 120a6e
              nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0);
Calabaraburus 7e96bc
              
Calabaraburus 7e96bc
              prev_m_cpx = cpx;
Calabaraburus 7e96bc
              prev_m_cpy = cpy;
Calabaraburus 7e96bc
              prev_m_exists = true;
Calabaraburus 7e96bc
Shinya Kitaoka 120a6e
              // Moveto can be followed by multiple coordinate pairs,
Shinya Kitaoka 120a6e
              // which should be treated as linetos.
Shinya Kitaoka 120a6e
              cmd   = (cmd == 'm') ? 'l' : 'L';
Shinya Kitaoka 120a6e
              rargs = nsvg__getArgsPerElement(cmd);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'l':
Shinya Kitaoka 120a6e
            case 'L':
Shinya Kitaoka 120a6e
              nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'H':
Shinya Kitaoka 120a6e
            case 'h':
Shinya Kitaoka 120a6e
              nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'V':
Shinya Kitaoka 120a6e
            case 'v':
Shinya Kitaoka 120a6e
              nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'C':
Shinya Kitaoka 120a6e
            case 'c':
Shinya Kitaoka 120a6e
              nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args,
Shinya Kitaoka 120a6e
                                   cmd == 'c' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'S':
Shinya Kitaoka 120a6e
            case 's':
Shinya Kitaoka 120a6e
              nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args,
Shinya Kitaoka 120a6e
                                        cmd == 's' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'Q':
Shinya Kitaoka 120a6e
            case 'q':
Shinya Kitaoka 120a6e
              nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args,
Shinya Kitaoka 120a6e
                                  cmd == 'q' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'T':
Shinya Kitaoka 120a6e
            case 't':
Shinya Kitaoka 120a6e
              nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args,
Shinya Kitaoka 120a6e
                                       cmd == 's' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            case 'A':
Shinya Kitaoka 120a6e
            case 'a':
Shinya Kitaoka 120a6e
              nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0);
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            default:
Shinya Kitaoka 120a6e
              if (nargs >= 2) {
Shinya Kitaoka 120a6e
                cpx = args[nargs - 2];
Shinya Kitaoka 120a6e
                cpy = args[nargs - 1];
Shinya Kitaoka 120a6e
              }
Shinya Kitaoka 120a6e
              break;
Shinya Kitaoka 120a6e
            }
Shinya Kitaoka 120a6e
            nargs = 0;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          cmd   = item[0];
Shinya Kitaoka 120a6e
          rargs = nsvg__getArgsPerElement(cmd);
Shinya Kitaoka 120a6e
          if (cmd == 'M' || cmd == 'm') {
Shinya Kitaoka 120a6e
            // Commit path.
Shinya Kitaoka 120a6e
            if (p->npts > 0) nsvg__addPath(p, closedFlag);
Shinya Kitaoka 120a6e
            // Start new subpath.
Shinya Kitaoka 120a6e
            nsvg__resetPath(p);
Shinya Kitaoka 120a6e
            closedFlag = 0;
Shinya Kitaoka 120a6e
            nargs      = 0;
Shinya Kitaoka 120a6e
          } else if (cmd == 'Z' || cmd == 'z') {
Shinya Kitaoka 120a6e
            closedFlag = 1;
Shinya Kitaoka 120a6e
            // Commit path.
Shinya Kitaoka 120a6e
            if (p->npts > 0) nsvg__addPath(p, closedFlag);
Shinya Kitaoka 120a6e
            // Start new subpath.
Shinya Kitaoka 120a6e
            nsvg__resetPath(p);
Shinya Kitaoka 120a6e
            closedFlag = 0;
Shinya Kitaoka 120a6e
            nargs      = 0;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      // Commit path.
Shinya Kitaoka 120a6e
      if (p->npts) nsvg__addPath(p, closedFlag);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      tmp[0] = attr[i];
Shinya Kitaoka 120a6e
      tmp[1] = attr[i + 1];
Shinya Kitaoka 120a6e
      tmp[2] = 0;
Shinya Kitaoka 120a6e
      tmp[3] = 0;
Shinya Kitaoka 120a6e
      nsvg__parseAttribs(p, tmp);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__addShape(p);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseRect(struct NSVGParser *p, const char **attr) {
Shinya Kitaoka 120a6e
  float x  = 0.0f;
Shinya Kitaoka 120a6e
  float y  = 0.0f;
Shinya Kitaoka 120a6e
  float w  = 0.0f;
Shinya Kitaoka 120a6e
  float h  = 0.0f;
Shinya Kitaoka 120a6e
  float rx = -1.0f;  // marks not set
Shinya Kitaoka 120a6e
  float ry = -1.0f;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "x") == 0) x      = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "y") == 0) y      = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "width") == 0) w  = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "height") == 0) h = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseFloat(attr[i + 1]));
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseFloat(attr[i + 1]));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (rx < 0.0f && ry > 0.0f) rx = ry;
Shinya Kitaoka 120a6e
  if (ry < 0.0f && rx > 0.0f) ry = rx;
Shinya Kitaoka 120a6e
  if (rx < 0.0f) rx              = 0.0f;
Shinya Kitaoka 120a6e
  if (ry < 0.0f) ry              = 0.0f;
Shinya Kitaoka 120a6e
  if (rx > w / 2.0f) rx          = w / 2.0f;
Shinya Kitaoka 120a6e
  if (ry > h / 2.0f) ry          = h / 2.0f;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (w != 0.0f && h != 0.0f) {
Shinya Kitaoka 120a6e
    nsvg__resetPath(p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (rx < 0.00001f || ry < 0.0001f) {
Shinya Kitaoka 120a6e
      nsvg__moveTo(p, x, y);
Shinya Kitaoka 120a6e
      nsvg__lineTo(p, x + w, y);
Shinya Kitaoka 120a6e
      nsvg__lineTo(p, x + w, y + h);
Shinya Kitaoka 120a6e
      nsvg__lineTo(p, x, y + h);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // Rounded rectangle
Shinya Kitaoka 120a6e
      nsvg__moveTo(p, x + rx, y);
Shinya Kitaoka 120a6e
      nsvg__lineTo(p, x + w - rx, y);
Shinya Kitaoka 120a6e
      nsvg__cubicBezTo(p, x + w - rx * (1 - NSVG_KAPPA90), y, x + w,
Shinya Kitaoka 120a6e
                       y + ry * (1 - NSVG_KAPPA90), x + w, y + ry);
Shinya Kitaoka 120a6e
      nsvg__lineTo(p, x + w, y + h - ry);
Shinya Kitaoka 120a6e
      nsvg__cubicBezTo(p, x + w, y + h - ry * (1 - NSVG_KAPPA90),
Shinya Kitaoka 120a6e
                       x + w - rx * (1 - NSVG_KAPPA90), y + h, x + w - rx,
Shinya Kitaoka 120a6e
                       y + h);
Shinya Kitaoka 120a6e
      nsvg__lineTo(p, x + rx, y + h);
Shinya Kitaoka 120a6e
      nsvg__cubicBezTo(p, x + rx * (1 - NSVG_KAPPA90), y + h, x,
Shinya Kitaoka 120a6e
                       y + h - ry * (1 - NSVG_KAPPA90), x, y + h - ry);
Shinya Kitaoka 120a6e
      nsvg__lineTo(p, x, y + ry);
Shinya Kitaoka 120a6e
      nsvg__cubicBezTo(p, x, y + ry * (1 - NSVG_KAPPA90),
Shinya Kitaoka 120a6e
                       x + rx * (1 - NSVG_KAPPA90), y, x + rx, y);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__addPath(p, 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__addShape(p);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseCircle(struct NSVGParser *p, const char **attr) {
Shinya Kitaoka 120a6e
  float cx = 0.0f;
Shinya Kitaoka 120a6e
  float cy = 0.0f;
Shinya Kitaoka 120a6e
  float r  = 0.0f;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "r") == 0) r   = fabsf(nsvg__parseFloat(attr[i + 1]));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (r > 0.0f) {
Shinya Kitaoka 120a6e
    nsvg__resetPath(p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__moveTo(p, cx + r, cy);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx + r, cy + r * NSVG_KAPPA90, cx + r * NSVG_KAPPA90,
Shinya Kitaoka 120a6e
                     cy + r, cx, cy + r);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx - r * NSVG_KAPPA90, cy + r, cx - r,
Shinya Kitaoka 120a6e
                     cy + r * NSVG_KAPPA90, cx - r, cy);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx - r, cy - r * NSVG_KAPPA90, cx - r * NSVG_KAPPA90,
Shinya Kitaoka 120a6e
                     cy - r, cx, cy - r);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx + r * NSVG_KAPPA90, cy - r, cx + r,
Shinya Kitaoka 120a6e
                     cy - r * NSVG_KAPPA90, cx + r, cy);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__addPath(p, 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__addShape(p);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseEllipse(struct NSVGParser *p, const char **attr) {
Shinya Kitaoka 120a6e
  float cx = 0.0f;
Shinya Kitaoka 120a6e
  float cy = 0.0f;
Shinya Kitaoka 120a6e
  float rx = 0.0f;
Shinya Kitaoka 120a6e
  float ry = 0.0f;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseFloat(attr[i + 1]));
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseFloat(attr[i + 1]));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (rx > 0.0f && ry > 0.0f) {
Shinya Kitaoka 120a6e
    nsvg__resetPath(p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__moveTo(p, cx + rx, cy);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx + rx, cy + ry * NSVG_KAPPA90, cx + rx * NSVG_KAPPA90,
Shinya Kitaoka 120a6e
                     cy + ry, cx, cy + ry);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx - rx * NSVG_KAPPA90, cy + ry, cx - rx,
Shinya Kitaoka 120a6e
                     cy + ry * NSVG_KAPPA90, cx - rx, cy);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx - rx, cy - ry * NSVG_KAPPA90, cx - rx * NSVG_KAPPA90,
Shinya Kitaoka 120a6e
                     cy - ry, cx, cy - ry);
Shinya Kitaoka 120a6e
    nsvg__cubicBezTo(p, cx + rx * NSVG_KAPPA90, cy - ry, cx + rx,
Shinya Kitaoka 120a6e
                     cy - ry * NSVG_KAPPA90, cx + rx, cy);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__addPath(p, 1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    nsvg__addShape(p);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseLine(struct NSVGParser *p, const char **attr) {
Shinya Kitaoka 120a6e
  float x1 = 0.0;
Shinya Kitaoka 120a6e
  float y1 = 0.0;
Shinya Kitaoka 120a6e
  float x2 = 0.0;
Shinya Kitaoka 120a6e
  float y2 = 0.0;
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseFloat(attr[i + 1]);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__resetPath(p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__moveTo(p, x1, y1);
Shinya Kitaoka 120a6e
  nsvg__lineTo(p, x2, y2);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__addPath(p, 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__addShape(p);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parsePoly(struct NSVGParser *p, const char **attr, int closeFlag) {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  const char *s;
Shinya Kitaoka 120a6e
  float args[2];
Shinya Kitaoka 120a6e
  int nargs, npts = 0;
Shinya Kitaoka 120a6e
  char item[64];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__resetPath(p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "points") == 0) {
Shinya Kitaoka 120a6e
        s     = attr[i + 1];
Shinya Kitaoka 120a6e
        nargs = 0;
Shinya Kitaoka 120a6e
        while (*s) {
Shinya Kitaoka 120a6e
          s             = nsvg__getNextPathItem(s, item);
Shinya Kitaoka 120a6e
          args[nargs++] = (float)atof(item);
Shinya Kitaoka 120a6e
          if (nargs >= 2) {
Shinya Kitaoka 120a6e
            if (npts == 0)
Shinya Kitaoka 120a6e
              nsvg__moveTo(p, args[0], args[1]);
Shinya Kitaoka 120a6e
            else
Shinya Kitaoka 120a6e
              nsvg__lineTo(p, args[0], args[1]);
Shinya Kitaoka 120a6e
            nargs = 0;
Shinya Kitaoka 120a6e
            npts++;
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__addPath(p, (char)closeFlag);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__addShape(p);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__parseSVG(struct NSVGParser *p, const char **attr) {
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  for (i = 0; attr[i]; i += 2) {
Shinya Kitaoka 120a6e
    if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) {
Shinya Kitaoka 120a6e
      if (strcmp(attr[i], "width") == 0) {
Shinya Kitaoka 120a6e
        p->image->wunits[0] = '\0';
Shinya Kitaoka 120a6e
        sscanf(attr[i + 1], "%f%s", &p->image->width, p->image->wunits);
Shinya Kitaoka 120a6e
      } else if (strcmp(attr[i], "height") == 0) {
Shinya Kitaoka 120a6e
        p->image->hunits[0] = '\0';
Shinya Kitaoka 120a6e
        sscanf(attr[i + 1], "%f%s", &p->image->height, p->image->hunits);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__startElement(void *ud, const char *el, const char **attr) {
Shinya Kitaoka 120a6e
  struct NSVGParser *p = (struct NSVGParser *)ud;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Skip everything in defs
Shinya Kitaoka 120a6e
  if (p->defsFlag) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (strcmp(el, "g") == 0) {
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parseAttribs(p, attr);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "path") == 0) {
Shinya Kitaoka 120a6e
    if (p->pathFlag)  // Do not allow nested paths.
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parsePath(p, attr);
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "rect") == 0) {
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parseRect(p, attr);
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "circle") == 0) {
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parseCircle(p, attr);
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "ellipse") == 0) {
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parseEllipse(p, attr);
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "line") == 0) {
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parseLine(p, attr);
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "polyline") == 0) {
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parsePoly(p, attr, 0);
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "polygon") == 0) {
Shinya Kitaoka 120a6e
    nsvg__pushAttr(p);
Shinya Kitaoka 120a6e
    nsvg__parsePoly(p, attr, 1);
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "defs") == 0) {
Shinya Kitaoka 120a6e
    p->defsFlag = 1;
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "svg") == 0) {
Shinya Kitaoka 120a6e
    nsvg__parseSVG(p, attr);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__endElement(void *ud, const char *el) {
Shinya Kitaoka 120a6e
  struct NSVGParser *p = (struct NSVGParser *)ud;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (strcmp(el, "g") == 0) {
Shinya Kitaoka 120a6e
    nsvg__popAttr(p);
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "path") == 0) {
Shinya Kitaoka 120a6e
    p->pathFlag = 0;
Shinya Kitaoka 120a6e
  } else if (strcmp(el, "defs") == 0) {
Shinya Kitaoka 120a6e
    p->defsFlag = 0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void nsvg__content(void *ud, const char *s) {
Shinya Kitaoka 120a6e
  // empty
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void dump(struct NSVGimage *image) {
Shinya Kitaoka 120a6e
  struct NSVGshape *shape;
Shinya Kitaoka 120a6e
  if (image == NULL) return;
Shinya Kitaoka 120a6e
  shape = image->shapes;
Shinya Kitaoka 120a6e
  while (shape != NULL) {
Shinya Kitaoka 120a6e
    struct NSVGpath *path;
Shinya Kitaoka 120a6e
    path              = shape->paths;
Shinya Kitaoka 120a6e
    while (path) path = path->next;
Shinya Kitaoka 120a6e
    shape             = shape->next;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
struct NSVGimage *nsvgParse(char *input) {
Shinya Kitaoka 120a6e
  struct NSVGParser *p;
Shinya Kitaoka 120a6e
  struct NSVGimage *ret = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  p = nsvg__createParser();
Shinya Kitaoka 120a6e
  if (p == NULL) {
Shinya Kitaoka 120a6e
    return NULL;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  ret      = p->image;
Shinya Kitaoka 120a6e
  p->image = NULL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  dump(ret);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvg__deleteParser(p);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return ret;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
struct NSVGimage *nsvgParseFromFile(const char *filename) {
Shinya Kitaoka 120a6e
  FILE *fp = NULL;
Shinya Kitaoka 120a6e
  int size;
Shinya Kitaoka 120a6e
  char *data              = NULL;
Shinya Kitaoka 120a6e
  struct NSVGimage *image = NULL;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  fp = fopen(filename, "rb");
Shinya Kitaoka 120a6e
  if (!fp) goto error;
Shinya Kitaoka 120a6e
  fseek(fp, 0, SEEK_END);
Shinya Kitaoka 120a6e
  size = ftell(fp);
Shinya Kitaoka 120a6e
  fseek(fp, 0, SEEK_SET);
Shinya Kitaoka 120a6e
  data = (char *)malloc(size + 1);
Shinya Kitaoka 120a6e
  if (data == NULL) goto error;
Shinya Kitaoka 120a6e
  fread(data, size, 1, fp);
Shinya Kitaoka 120a6e
  data[size] = '\0';  // Must be null terminated.
Shinya Kitaoka 120a6e
  fclose(fp);
Shinya Kitaoka 120a6e
  image = nsvgParse(data);
Shinya Kitaoka 120a6e
  free(data);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return image;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
error:
Shinya Kitaoka 120a6e
  if (fp) fclose(fp);
Shinya Kitaoka 120a6e
  if (data) free(data);
Shinya Kitaoka 120a6e
  if (image) nsvgDelete(image);
Shinya Kitaoka 120a6e
  return NULL;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace svg_parser
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
//=------------------------------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class TImageWriterSvg final : public TImageWriter {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TImageWriterSvg(const TFilePath &, TPropertyGroup *);
Shinya Kitaoka 120a6e
  ~TImageWriterSvg() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  // double m_maxThickness;
Shinya Kitaoka 120a6e
  // not implemented
Shinya Kitaoka 120a6e
  TImageWriterSvg(const TImageWriterSvg &);
Shinya Kitaoka 120a6e
  TImageWriterSvg &operator=(const TImageWriterSvg &src);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 473e70
  void save(const TImageP &) override;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Shinya Kitaoka d1f6c4
class TImageReaderSvg final : public TImageReader {
Shinya Kitaoka 120a6e
  TLevelP m_level;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  TImageReaderSvg(const TFilePath &path, TLevelP &level)
Shinya Kitaoka 120a6e
      : TImageReader(path), m_level(level) {}
Shinya Kitaoka 473e70
Shinya Kitaoka 473e70
  TImageP load() override;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageWriterP TLevelWriterSvg::getFrameWriter(TFrameId fid) {
Shinya Kitaoka 120a6e
  TImageWriterSvg *iwm =
Shinya Kitaoka 120a6e
      new TImageWriterSvg(m_path.withFrame(fid), getProperties());
Shinya Kitaoka 120a6e
  return TImageWriterP(iwm);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
TImageWriterSvg::TImageWriterSvg(const TFilePath &f, TPropertyGroup *prop)
Shinya Kitaoka 120a6e
    : TImageWriter(f)
Toshihiro Shimizu 890ddd
//, m_maxThickness(0)
Toshihiro Shimizu 890ddd
{
Shinya Kitaoka 120a6e
  setProperties(prop);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TLevelWriterSvg::TLevelWriterSvg(const TFilePath &path, TPropertyGroup *winfo)
Shinya Kitaoka 120a6e
    : TLevelWriter(path, winfo)
Toshihiro Shimizu 890ddd
//, m_pli         (0)
Toshihiro Shimizu 890ddd
//, m_frameNumber (0)
Shinya Kitaoka 120a6e
{}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 27b0cf
static void writeRegion(TRegion *r, TPalette *plt, QTextStream &out,
shun-iwasawa 27b0cf
                        double ly) {
Shinya Kitaoka 120a6e
  if (r->getEdgeCount() == 0) return;
Shinya Kitaoka 120a6e
  std::vector<const *="" tquadratic=""> quadsOutline;</const>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)r->getEdgeCount(); i++) {
Shinya Kitaoka 120a6e
    TEdge *e   = r->getEdge(i);
Shinya Kitaoka 120a6e
    TStroke *s = e->m_s;
Shinya Kitaoka 120a6e
    int index0, index1;
Shinya Kitaoka 120a6e
    double t0, t1;
Shinya Kitaoka 120a6e
    double w0 = e->m_w0, w1 = e->m_w1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (w0 > w1) {
Shinya Kitaoka 120a6e
      TStroke *s1 = new TStroke(*s);
Shinya Kitaoka 120a6e
      s1->changeDirection();
Shinya Kitaoka 120a6e
      double totalLength = s->getLength();
Shinya Kitaoka 120a6e
      w0 = s1->getParameterAtLength(totalLength - s->getLength(w0));
Shinya Kitaoka 120a6e
      w1 = s1->getParameterAtLength(totalLength - s->getLength(w1));
Shinya Kitaoka 120a6e
      s  = s1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      assert(w0 <= w1);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    s->getChunkAndT(w0, index0, t0);
Shinya Kitaoka 120a6e
    s->getChunkAndT(w1, index1, t1);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (int j = index0; j <= index1; j++) {
Shinya Kitaoka 120a6e
      const TQuadratic *q = s->getChunk(j);
Shinya Kitaoka 120a6e
      if (j == index0 && t0 != 0) {
Shinya Kitaoka 120a6e
        TQuadratic q1, *q2 = new TQuadratic();
Shinya Kitaoka 120a6e
        q->split(t0, q1, *q2);
Shinya Kitaoka 120a6e
        q = q2;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      if (j == index1 && t1 != 1) {
Shinya Kitaoka 120a6e
        TQuadratic *q1 = new TQuadratic(), q2;
Shinya Kitaoka 120a6e
        q->split(t1, *q1, q2);
Shinya Kitaoka 120a6e
        q = q1;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
      quadsOutline.push_back(q);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (quadsOutline.empty()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  out << "
Shinya Kitaoka 120a6e
  TPixel32 col = plt->getStyle(r->getStyle())->getMainColor();
Shinya Kitaoka 120a6e
  if (col == TPixel::Transparent) col == TPixel::White;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  out << "style=\"fill:rgb(" << col.r << "," << col.g << "," << col.b
Shinya Kitaoka 120a6e
      << ")\" \n";
Shinya Kitaoka 120a6e
  out << "d=\"M " << quadsOutline[0]->getP0().x << " "
Shinya Kitaoka 120a6e
      << ly - quadsOutline[0]->getP0().y << "\n";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int i = 0; i < quadsOutline.size(); i++)
Shinya Kitaoka 120a6e
    out << "Q " << quadsOutline[i]->getP1().x << ","
Shinya Kitaoka 120a6e
        << ly - quadsOutline[i]->getP1().y << "," << quadsOutline[i]->getP2().x
Shinya Kitaoka 120a6e
        << "," << ly - quadsOutline[i]->getP2().y << "\n";
Shinya Kitaoka 120a6e
  out << " \" /> \n";
Shinya Kitaoka 120a6e
  for (int i = 0; i < (int)r->getSubregionCount(); i++)
Shinya Kitaoka 120a6e
    writeRegion(r->getSubregion(i), plt, out, ly);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
shun-iwasawa 27b0cf
static void writeOutlineStroke(TStroke *s, TPalette *plt, QTextStream &out,
shun-iwasawa 27b0cf
                               double ly, double quality) {
Shinya Kitaoka 120a6e
  if (s->getChunkCount() == 0) return;
Shinya Kitaoka 120a6e
  if (s->getMaxThickness() == 0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::vector<tquadratic *=""> quadsOutline;</tquadratic>
Shinya Kitaoka 120a6e
  computeOutlines(s, 0, s->getChunkCount() - 1, quadsOutline, quality);
Shinya Kitaoka 120a6e
  if (quadsOutline.empty()) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  out << "
Shinya Kitaoka 120a6e
  TPixel32 col = plt->getStyle(s->getStyle())->getMainColor();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  out << "style=\"fill:rgb(" << col.r << "," << col.g << "," << col.b
Shinya Kitaoka 120a6e
      << ")\" \n";
Shinya Kitaoka 120a6e
  out << "d=\"M " << quadsOutline[0]->getP0().x << " "
Shinya Kitaoka 120a6e
      << ly - quadsOutline[0]->getP0().y << "\n";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 0; i < quadsOutline.size(); i++)
Shinya Kitaoka 120a6e
    out << "Q " << quadsOutline[i]->getP1().x << ","
Shinya Kitaoka 120a6e
        << ly - quadsOutline[i]->getP1().y << "," << quadsOutline[i]->getP2().x
Shinya Kitaoka 120a6e
        << "," << ly - quadsOutline[i]->getP2().y << "\n";
Shinya Kitaoka 120a6e
  out << " \" /> \n";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------
Toshihiro Shimizu 890ddd
Campbell Barton 8c6c57
static double computeAverageThickness(const TStroke *s) {
Shinya Kitaoka 120a6e
  int count = s->getControlPointCount();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double resThick = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 0; i < s->getControlPointCount(); i++) {
Shinya Kitaoka 120a6e
    double thick = s->getControlPoint(i).thick;
Shinya Kitaoka 120a6e
    if (i >= 2 && i < s->getControlPointCount() - 2) resThick += thick;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (count < 6) return s->getControlPoint(count / 2 + 1).thick;
Shinya Kitaoka 120a6e
  return resThick / (s->getControlPointCount() - 4);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------
Toshihiro Shimizu 890ddd
Campbell Barton 8c6c57
static void writeCenterlineStroke(TStroke *s, TPalette *plt, QTextStream &out,
Campbell Barton 8c6c57
                                  double ly) {
Shinya Kitaoka 120a6e
  if (s->getChunkCount() == 0) return;
Shinya Kitaoka 120a6e
  if (s->getMaxThickness() == 0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double thick = 2 * computeAverageThickness(s);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  out << "
Shinya Kitaoka 120a6e
  TPixel32 col = plt->getStyle(s->getStyle())->getMainColor();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  out << "style=\"stroke:rgb(" << col.r << "," << col.g << "," << col.b
Shinya Kitaoka 120a6e
      << ")\" stroke-width=\"" << thick << " \"  \n";
Shinya Kitaoka 120a6e
  out << "d=\"M " << s->getChunk(0)->getP0().x << " "
Shinya Kitaoka 120a6e
      << ly - s->getChunk(0)->getP0().y << "\n";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 0; i < s->getChunkCount(); i++)
Shinya Kitaoka 120a6e
    out << "Q " << s->getChunk(i)->getP1().x << ","
Shinya Kitaoka 120a6e
        << ly - s->getChunk(i)->getP1().y << "," << s->getChunk(i)->getP2().x
Shinya Kitaoka 120a6e
        << "," << ly - s->getChunk(i)->getP2().y << "\n";
Shinya Kitaoka 120a6e
  out << " \" /> \n";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Tiio::SvgWriterProperties::SvgWriterProperties()
Shinya Kitaoka 120a6e
    : m_strokeMode("Stroke Mode"), m_outlineQuality("Outline Quality") {
Shinya Kitaoka 120a6e
  m_strokeMode.addValue(L"Centerline");
Shinya Kitaoka 120a6e
  m_strokeMode.addValue(L"Outline");
Shinya Kitaoka 120a6e
  m_outlineQuality.addValue(L"High");
Shinya Kitaoka 120a6e
  m_outlineQuality.addValue(L"Medium");
Shinya Kitaoka 120a6e
  m_outlineQuality.addValue(L"Low");
Shinya Kitaoka 120a6e
  bind(m_strokeMode);
Shinya Kitaoka 120a6e
  bind(m_outlineQuality);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun-iwasawa 86dc52
void Tiio::SvgWriterProperties::updateTranslation() {
shun-iwasawa 86dc52
  m_strokeMode.setQStringName(tr("Stroke Mode"));
shun-iwasawa 86dc52
  m_outlineQuality.setQStringName(tr("Outline Quality"));
shun-iwasawa 86dc52
  m_strokeMode.setItemUIName(L"Centerline", tr("Centerline"));
shun-iwasawa 86dc52
  m_strokeMode.setItemUIName(L"Outline", tr("Outline"));
shun-iwasawa 86dc52
  m_outlineQuality.setItemUIName(L"High", tr("High"));
shun-iwasawa 86dc52
  m_outlineQuality.setItemUIName(L"Medium", tr("Medium"));
shun-iwasawa 86dc52
  m_outlineQuality.setItemUIName(L"Low", tr("Low"));
shun-iwasawa 86dc52
}
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// void writeSvg(QString path, TVectorImageP v)
Shinya Kitaoka 120a6e
void TImageWriterSvg::save(const TImageP &img) {
Shinya Kitaoka 120a6e
  const TVectorImageP v = (const TVectorImageP)img;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (v->getStrokeCount() == 0) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TPalette *plt = v->getPalette();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TRectD r  = v->getBBox();
Shinya Kitaoka 120a6e
  double ly = r.getP00().y + r.getP11().y;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QFile file(this->getFilePath().getQString());
Shinya Kitaoka 120a6e
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QTextStream out(&file);
Shinya Kitaoka 120a6e
  out.setRealNumberPrecision(1);
Shinya Kitaoka 120a6e
  out.setRealNumberNotation(QTextStream::FixedNotation);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  out << "\n";
Shinya Kitaoka 120a6e
  out << "
Shinya Kitaoka 120a6e
         "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
Shinya Kitaoka 120a6e
  out << "<svg version="\"1.1\"" xmlns:xmlns="\"http://www.w3.org/2000/svg\"">\n";</svg>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  out << "
Shinya Kitaoka 120a6e
      << ")\" stroke-width=\"0\" fill=\"none\" >\n";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  bool isCenterline =
Shinya Kitaoka 120a6e
      ((TEnumProperty *)(m_properties->getProperty("Stroke Mode")))
Shinya Kitaoka 120a6e
          ->getValue() == L"Centerline";
Shinya Kitaoka 120a6e
  double quality = 1;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!isCenterline) {
Shinya Kitaoka 120a6e
    if (((TEnumProperty *)(m_properties->getProperty("Outline Quality")))
Shinya Kitaoka 120a6e
            ->getValue() == L"Low")
Shinya Kitaoka 120a6e
      quality = 200;
Shinya Kitaoka 120a6e
    else if (((TEnumProperty *)(m_properties->getProperty("Outline Quality")))
Shinya Kitaoka 120a6e
                 ->getValue() == L"Medium")
Shinya Kitaoka 120a6e
      quality = 10;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int j = 0; j < (int)v->getRegionCount(); j++)
Shinya Kitaoka 120a6e
    writeRegion(v->getRegion(j), plt, out, ly);
Shinya Kitaoka 120a6e
  for (int j = 0; j < (int)v->getStrokeCount(); j++)
Shinya Kitaoka 120a6e
    if (isCenterline)
Shinya Kitaoka 120a6e
      writeCenterlineStroke(v->getStroke(j), plt, out, ly);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      writeOutlineStroke(v->getStroke(j), plt, out, ly, quality);
Shinya Kitaoka 120a6e
  out << " \n";
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  out << " \n";
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Shinya Kitaoka 120a6e
int addColorToPalette(TPalette *plt, unsigned int _color) {
Shinya Kitaoka 120a6e
  TPixel color(_color & 0xFF, (_color >> 8) & 0xFF, _color >> 16);
Shinya Kitaoka 120a6e
  for (int i = 0; i < plt->getStyleCount(); i++)
Shinya Kitaoka 120a6e
    if (plt->getStyle(i)->getMainColor() == color) return i;
Shinya Kitaoka 120a6e
  TPalette::Page *page = plt->getPage(0);
Shinya Kitaoka 120a6e
  int index            = page->addStyle(color);
Shinya Kitaoka 120a6e
  return index;  // plt->addStyle(color);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int findColor(TPalette *plt, unsigned int _color) {
Shinya Kitaoka 120a6e
  TPixel color(_color & 0xFF, (_color >> 8) & 0xFF, _color >> 16);
Shinya Kitaoka 120a6e
  for (int i = 0; i < plt->getStyleCount(); i++)
Shinya Kitaoka 120a6e
    if (plt->getStyle(i)->getMainColor() == color) return i;
Shinya Kitaoka 120a6e
  assert(false);
Shinya Kitaoka 120a6e
  return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TStroke *buildStroke(NSVGpath *path, float width) {
Shinya Kitaoka 120a6e
  assert((path->npts - 1) % 3 == 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TThickPoint p0 = TThickPoint(path->pts[0], -path->pts[1], width);
Shinya Kitaoka 120a6e
  std::vector<tthickpoint> points;</tthickpoint>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  points.push_back(p0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (int i = 1; i < path->npts; i += 3) {
Shinya Kitaoka 120a6e
    std::vector<tthickquadratic *=""> chunkArray;</tthickquadratic>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    computeQuadraticsFromCubic(
Shinya Kitaoka 120a6e
        p0, TThickPoint(path->pts[2 * i], -path->pts[2 * i + 1], width),
Shinya Kitaoka 120a6e
        TThickPoint(path->pts[2 * i + 2], -path->pts[2 * i + 3], width),
Shinya Kitaoka 120a6e
        TThickPoint(path->pts[2 * i + 4], -path->pts[2 * i + 5], width), 0.01,
Shinya Kitaoka 120a6e
        chunkArray);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (int j = 0; j < chunkArray.size(); j++) {
Shinya Kitaoka 120a6e
      points.push_back(chunkArray[j]->getP1());
Shinya Kitaoka 120a6e
      points.push_back(chunkArray[j]->getP2());
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    p0 = chunkArray.back()->getP2();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (points.empty()) return 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (path->closed) {
Shinya Kitaoka 120a6e
    if (points.back() != points.front()) {
Shinya Kitaoka 120a6e
      points.push_back(0.5 * (points.back() + points.front()));
Shinya Kitaoka 120a6e
      points.push_back(points.front());
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      int gasp = 0;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  TStroke *s = new TStroke(points);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  s->setSelfLoop(path->closed);
Toshihiro Shimizu 890ddd
Calabaraburus 7e96bc
  std::vector<tthickpoint> tpoints;</tthickpoint>
Calabaraburus 7e96bc
  s->getControlPoints(tpoints);
Calabaraburus 7e96bc
Calabaraburus 7e96bc
  for (int j = 0; j < tpoints.size(); j++) {
Calabaraburus 7e96bc
	  tpoints[j].thick = width;
Calabaraburus 7e96bc
  }
Calabaraburus 7e96bc
Calabaraburus 7e96bc
  s->reshape(&tpoints[0], tpoints.size());
Calabaraburus 7e96bc
Shinya Kitaoka 120a6e
  return s;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageP TImageReaderSvg::load() {
Shinya Kitaoka 120a6e
  NSVGimage *svgImg =
Shinya Kitaoka 120a6e
      nsvgParseFromFile(m_path.getQString().toStdString().c_str());
Shinya Kitaoka 120a6e
  if (!svgImg) return TImageP();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TPalette *plt = m_level->getPalette();
Shinya Kitaoka 120a6e
  assert(plt);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TVectorImage *vimage = new TVectorImage();
Shinya Kitaoka 120a6e
  vimage->setPalette(plt);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (NSVGshape *shape = svgImg->shapes; shape; shape = shape->next) {
Shinya Kitaoka 120a6e
    int inkIndex, paintIndex;
Shinya Kitaoka 120a6e
    NSVGpath *path = shape->paths;
Shinya Kitaoka 120a6e
    if (!path) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // TVectorImageP vapp = new TVectorImage();
Shinya Kitaoka 120a6e
    // TPalette* appPlt = new TPalette();
Shinya Kitaoka 120a6e
    // vapp->setPalette(appPlt);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    TPixel color(shape->fillColor & 0xFF, (shape->fillColor >> 8) & 0xFF,
Shinya Kitaoka 120a6e
                 shape->fillColor >> 16);
Shinya Kitaoka 120a6e
    if (!shape->hasFill) {
Shinya Kitaoka 120a6e
      assert(color == TPixel::Black);
Shinya Kitaoka 120a6e
      shape->hasFill = true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (shape->hasStroke) inkIndex = findColor(plt, shape->strokeColor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (shape->hasFill) paintIndex = findColor(plt, shape->fillColor);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // vapp->setPalette(plt.getPointer());
Shinya Kitaoka 120a6e
    int startStrokeIndex = vimage->getStrokeCount();
Shinya Kitaoka 120a6e
    for (; path; path = path->next) {
Shinya Kitaoka 120a6e
      TStroke *s = buildStroke(path, shape->hasStroke ? shape->strokeWidth : 0);
Shinya Kitaoka 120a6e
      if (!s) continue;
Shinya Kitaoka 120a6e
      s->setStyle(shape->hasStroke ? inkIndex : 0);
Shinya Kitaoka 120a6e
      vimage->addStroke(s);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    if (startStrokeIndex == vimage->getStrokeCount()) continue;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    vimage->group(startStrokeIndex,
Shinya Kitaoka 120a6e
                  vimage->getStrokeCount() - startStrokeIndex);
Shinya Kitaoka 120a6e
    if (shape->hasFill) {
Shinya Kitaoka 120a6e
      vimage->enterGroup(startStrokeIndex);
Shinya Kitaoka 120a6e
      vimage->selectFill(TRectD(-9999999, -9999999, 9999999, 9999999), 0,
Shinya Kitaoka 120a6e
                         paintIndex, true, true, false);
Shinya Kitaoka 120a6e
      vimage->exitGroup();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    /* vapp->findRegions();
Shinya Kitaoka 120a6e
if (paintIndex!=-1)
Shinya Kitaoka 120a6e
for (int i=0; i<(int)vapp->getRegionCount(); i++)
Shinya Kitaoka 120a6e
vapp->getRegion(i)->setStyle(paintIndex);
Shinya Kitaoka 120a6e
std::vector<int> indexes(vapp->getStrokeCount());</int>
Shinya Kitaoka 120a6e
for (int i=0; i<(int)vapp->getStrokeCount() ;i++)
Shinya Kitaoka 120a6e
indexes[i] = vimage->getStrokeCount()+i;
Shinya Kitaoka 120a6e
vimage->insertImage(vapp, indexes);*/
Shinya Kitaoka 120a6e
    // delete appPlt;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nsvgDelete(svgImg);
Shinya Kitaoka 120a6e
  // if (m_level)
Shinya Kitaoka 120a6e
  // m_level->setPalette(plt);
Shinya Kitaoka 120a6e
  return TImageP(vimage);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelReaderSvg::TLevelReaderSvg(const TFilePath &path) : TLevelReader(path) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TImageReaderP TLevelReaderSvg::getFrameReader(TFrameId fid) {
Shinya Kitaoka 120a6e
  return new TImageReaderSvg(getFilePath().withFrame(fid), m_level);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
TLevelP TLevelReaderSvg::loadInfo() {
Shinya Kitaoka 120a6e
  m_level             = TLevelReader::loadInfo();
Shinya Kitaoka 120a6e
  TPalette *plt       = new TPalette();
Shinya Kitaoka 120a6e
  TLevel::Iterator it = m_level->begin();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (; it != m_level->end(); ++it) {
Shinya Kitaoka 120a6e
    NSVGimage *svgImg = nsvgParseFromFile(
Shinya Kitaoka 120a6e
        m_path.withFrame(it->first).getQString().toStdString().c_str());
Shinya Kitaoka 120a6e
    if (!svgImg) continue;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (NSVGshape *shape = svgImg->shapes; shape; shape = shape->next) {
Shinya Kitaoka 120a6e
      if (shape->hasStroke) addColorToPalette(plt, shape->strokeColor);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (shape->hasFill) addColorToPalette(plt, shape->fillColor);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    nsvgDelete(svgImg);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_level->setPalette(plt);
Shinya Kitaoka 120a6e
  return m_level;
Toshihiro Shimizu 890ddd
}