/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    module for conversion SVG files into LaTeX		      *
 * modul:       pass1svg.cc                                                   *
 * description: This module contains parser for SVG documents. It could   *
 *		be optionally compiled with WP2LaTeX package.		      *
 * licency:     GPL		                                              *
 ******************************************************************************/
// https://www.w3schools.com/graphics/svg_intro.asp
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>

#include "stringa.h"
#include "lists.h"
#include "dbllist.h"
#include "matrix.h"

#include "images/raster.h"
#include "images/vecimage.h"
#include "images.h"

#include"wp2latex.h"
#include"pass1xml.h"
#include "cp_lib/cptran.h"

#include "wmfsupp.h"


#ifndef M_PI
 #define M_PI        3.14159265358979323846
#endif


extern list HTMLChars;
int SavePictureEPS(const char *Name, const Image &Img);


/// Read float value from in memory string.
/// @param[in,out] pstr	Pointerto a stringto be read.
/// @param[out] f	Value read.
/// @return	true on success, false on failure.
bool ReadFloat(const char **pstr, float &f)
{
  if(pstr==NULL) {f=0;return false;}
  const char *str = *pstr;
  if(str==NULL) {f=0;return false;}

  while(isspace(*str)) str++;

  if(!isdigit(*str) && *str!='.' && *str!='-')
  {
    *pstr = str;
    f = 0;
    return false;
  }
  f = atof(str);

  if(*str=='-') str++;
  while(isdigit(*str) || *str=='.') str++;

  while(isspace(*str)) str++;

  *pstr = str;
return true;
}


inline float DEG2RAD(const float x) {return((x)*(float)M_PI/180.0f);}


/** Functor class for SVG transform. */
class TransformSVG: public AbstractTransformXY
{
public:
  float_matrix CTM;

  TransformSVG(void): CTM(4,4,(float)0) {CTM(0,0)=CTM(1,1)=CTM(2,2)=CTM(3,3)=1;}

  virtual void ApplyTransform(float &x, float &y) const;

  float TopPBottom;
};


void TransformSVG::ApplyTransform(float &x, float &y) const
{
  const float xNew = CTM(0,0)*x + CTM(1,0)*y + CTM(3,0);
  y = CTM(0,1)*x + CTM(1,1)*y + CTM(3,1);
  x = xNew;
}

////////////////////////////////////////////////////


const char LINE_COLOR[] = "stroke";
const char FILL_COLOR[] = "fill";

class VectDictionaryItem
{
public:
    string Id;
    VectorList VectList;
};


class DefinedObject
{
public:
    string id;
    VectorList VectList;
};


/*Register translator object here*/
class TconvertedPass1_SVG: virtual public TconvertedPass1_XML, virtual public TconvertedPass1_Image
     {
protected:
     VectorList VectList;
     PS_State PSS;
     float PositionX, PositionY;

     DefinedObject **objs;
     int DObjectCount;

     bool GetProp(const char *PropName, float &f);
     bool GetColor(RGB_Record &LineColor, const char *ClrType=LINE_COLOR);
     void GetLineCap(unsigned char &LineCap);
     void GetLineJoin(unsigned char &LineJoin);
     void GetStyle(vecPen *pPen, vecBrush *pBrush);
     float *LoadPoints(int &n);
     AbstractTransformXY *getTransform(void);
     void ClosePathLine(float **pPoints, int & n, bool Close=false, AbstractTransformXY *Tx=NULL);
     void ClosePathCurve(float **pPoints, int & n, bool Close=false, AbstractTransformXY *Tx=NULL);

public:
     TconvertedPass1_SVG(void)	{DObjectCount=0;objs=NULL;}
     virtual ~TconvertedPass1_SVG(void);
     void AddDefine(DefinedObject *pObj);
     DefinedObject *GetDefine(const char *DefId);

     virtual int Convert_first_pass(void);
     void ProcessKeySVG(void);

     void Circle(void);
     void Defs(void);
     void Ellipse(void);
     void Group(void);
     void Line(void);
     void Path(void);
     void Polygon(void);
     void PolyLine(void);
     void Rectangle(void);
     void Text(void);
     void Use(void);
     };
TconvertedPass1 *Factory_SVG(void) {return new TconvertedPass1_SVG;}
FFormatTranslator FormatSVG("SVG",Factory_SVG);

#define SVGVersion "0.4"


TconvertedPass1_SVG::~TconvertedPass1_SVG()
{
  if(objs)
  {
    while(DObjectCount>0)
    {
      DObjectCount--;
      if(objs[DObjectCount] != NULL)
      {
        delete objs[DObjectCount];
        objs[DObjectCount] = NULL;
      }
    }
    free(objs);
    objs = NULL;
  }
}


void TconvertedPass1_SVG::AddDefine(DefinedObject *pObj)
{
  if(objs==NULL)
  {
    objs = (DefinedObject**)malloc(sizeof(DefinedObject*));
    if(objs==NULL)
    {
      delete pObj;
      return;
    }
    DObjectCount = 1;
  }
  else
  {
    DObjectCount++;
    void *NewObjs = realloc(objs, DObjectCount*sizeof(DefinedObject*));
    if(NewObjs==NULL)
    {
      DObjectCount--;
      delete pObj;
      return;
    }
    objs = (DefinedObject**)NewObjs;
  }
  objs[DObjectCount-1] = pObj;
}


DefinedObject *TconvertedPass1_SVG::GetDefine(const char *DefId)
{
  if(objs==NULL) return NULL;
  for(int i=0; i<DObjectCount; i++)
  {
    if(objs[i]==NULL) continue;
    if(objs[i]->id==DefId) return objs[i];
  }
  return NULL;
}


bool TconvertedPass1_SVG::GetProp(const char *PropName, float &f)
{
int i;

  if((i=TAG_Args IN PropName)<0) return false;
  const char * const Payload = TAG_Args.Member(i,1);
  if(Payload==NULL) return false;
  f = atof(Payload);
return true;
}

typedef struct
{
  const char *desc;
  RGB_Record color;
} SVG_color;

// https://www.w3.org/TR/css-color-3/#html4
static SVG_color SVG_colors[] =
{
 "black", {0,0,0},
 "silver", {192,192,192},
 "gray", {128,128,128},
 "white", {255,255,255},
 "maroon", {128,0,0},
 "red", {255,0,0},
 "purple", {128,0,128},
 "fuchsia", {255,0,255},
 "green", {0,128,0},
 "lime", {0,255,0},
 "olive" , {128,128,0},
 "yellow", {255,255,0},
 "navy", {0,0,128},
 "blue", {0,0,255},
 "teal", {0,128,128},
 "aqua", {0,255,255}
};


bool TconvertedPass1_SVG::GetColor(RGB_Record &LineColor, const char *ClrType)
{
int i;

  if(ClrType==NULL || *ClrType==0) return false;
  if((i=TAG_Args IN ClrType)<0) return false;
  const char * const Payload = TAG_Args.Member(i,1);
  if(Payload==NULL) return false;

  if(Payload[0]=='#' && isxdigit(Payload[1]))
  {
    const uint32_t val = strtoul(Payload+1, NULL, 16);
    LineColor.Blue = val & 0xFF;
    LineColor.Green = (val>>8) & 0xFF;
    LineColor.Red = (val>>16) & 0xFF;
    return true;
  }
  for(i=0; i<sizeof(SVG_colors)/sizeof(SVG_color);i++)
    if(!strcmp(Payload, SVG_colors[i].desc))
    {
      LineColor = SVG_colors[i].color;
      return true;
    }

return false;
}


/// Extract a color from style string item.
bool GetStyleColor(RGB_Record *pColor, const char *ClrText)
{
  if(ClrText==NULL) return false;

  while(isspace(*ClrText)) ClrText++;
  if(!strncmp(ClrText,"rgb",3))
  {
    ClrText += 3;
    while(isspace(*ClrText)) ClrText++;
    if(*ClrText=='(')
    {
      ClrText++;
      pColor->Red = atoi(ClrText);
      while(*ClrText!=',' && *ClrText!=0) ClrText++;
      if(*ClrText==',')
      {
        ClrText++;
        pColor->Green = atoi(ClrText);
        while(*ClrText!=',' && *ClrText!=0) ClrText++;
        if(*ClrText==',')
        {
          ClrText++;
          pColor->Blue = atoi(ClrText);
          return true;
        }
      }
    }
    return false;
  }

  string Color;
  while(isalpha(*ClrText))
  {
    Color += *ClrText++;
    if(Color.length()>16) return false;		// maximal color string length
  }
  if(Color.length() > 0)
  {
    for(int i=0; i<sizeof(SVG_colors)/sizeof(SVG_color);i++)
      if(!strcmp(Color(), SVG_colors[i].desc))
      {
        *pColor = SVG_colors[i].color;
        return true;
      }
  }

  return false;
}


void TconvertedPass1_SVG::GetLineCap(unsigned char &LineCap)
{
int i;

  if((i=TAG_Args IN "stroke-linecap")<0) return;
  const char * const Payload = TAG_Args.Member(i,1);
  if(Payload==NULL) return;

  if(!strcmp(Payload, "butt")) {LineCap=0; return;}
  if(!strcmp(Payload, "round")) {LineCap=1; return;}
  if(!strcmp(Payload, "square")) {LineCap=2;}
}


void TconvertedPass1_SVG::GetLineJoin(unsigned char &LineJoin)
{
int i;

  if((i=TAG_Args IN "stroke-linejoin")<0) return;
  const char * const Payload = TAG_Args.Member(i,1);
  if(Payload==NULL) return;

  if(!strcmp(Payload, "miter")) {LineJoin=0; return;}
  if(!strcmp(Payload, "miter-clip")) {LineJoin=0; return;} //!!!!
  if(!strcmp(Payload, "round")) {LineJoin=1; return;}
  if(!strcmp(Payload, "bevel")) {LineJoin=2;}
  //if(!strcmp(Payload, "arcs")) {LineJoin=;}
}


void TconvertedPass1_SVG::GetStyle(vecPen *pPen, vecBrush *pBrush)
{
int i;
const char *str;
  if((i=TAG_Args IN "style")<0) return;
  const char * const Payload = TAG_Args.Member(i,1);
  if(Payload==NULL) return;
  if(pPen)
  {
    str = strstr(Payload,"stroke-width:");
    if(str)
    {
      str += 13;
      pPen->PenWidth = atof(str);
    }
    str = strstr(Payload,"stroke:");
    if(str)
    {
      str += 7;
      if(GetStyleColor(&pPen->LineColor,str))
          pPen->LineStyle = 1;
    }
  }
  if(pBrush)
  {
    str = strstr(Payload,"fill:");
    if(str)
    {
      str += 5;
      if(GetStyleColor(&pBrush->FillColor,str))
          pBrush->BrushStyle = FILL_SOLID;
    }
  }
}


float *TconvertedPass1_SVG::LoadPoints(int &n)
{
int i;

  n = 0;
  if((i=TAG_Args IN "points")<0) return NULL;
  const char * const StrPoints = TAG_Args.Member(i,1);
  if(StrPoints==NULL) return NULL;

  i = 0;
  while(StrPoints[i] != 0)
  {
    if(isdigit(StrPoints[i]))
    {
      n++;
      do
        { i++;}
      while(isdigit(StrPoints[i]));
      continue;
    }
    i++;
  }
  if(n<=1) return NULL;

  float *Points = (float*)malloc(sizeof(float)*n);
  if(Points == NULL) return NULL;

  n = i = 0;
  while(StrPoints[i] != 0)
  {
    if(isdigit(StrPoints[i]))
    {
      Points[n++] = atof(StrPoints+i);
      do
        { i++;}
      while(isdigit(StrPoints[i]));
      continue;
    }
    i++;
  }

  n/=2;
  for(i=0; i<n; i++)
    UpdateBBox(bbx,0, Points[2*i], Points[2*i+1], 0, 0);
return Points;
}


AbstractTransformXY *TconvertedPass1_SVG::getTransform(void)
{
int i;

  if((i=TAG_Args IN "transform")<0) return NULL;
  const char * StrTransform = TAG_Args.Member(i,1);
  if(StrTransform==NULL) return NULL;
  while(isspace(*StrTransform)) StrTransform++;
  if(*StrTransform==0) return NULL;

  TransformSVG *pTransformSVG = new TransformSVG;
  while(*StrTransform!=0)
  {
    if(isspace(*StrTransform)) {StrTransform++; continue;}

    if(!strncmp("translateX",StrTransform,10))
    {
      StrTransform += 10;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform!='(') continue;
      StrTransform++;
      float_matrix Tx(4,4,(float)0);
      if(ReadFloat(&StrTransform, Tx(3,0)))
      {
        Tx(0,0) = Tx(1,1) = Tx(2,2) = Tx(3,3) = 1;
        pTransformSVG->CTM *= Tx;
      }
    } else if(!strncmp("translateY",StrTransform,10))
    {
      StrTransform += 10;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform!='(') continue;
      StrTransform++;
      float_matrix Tx(4,4,(float)0);
      if(ReadFloat(&StrTransform, Tx(3,1)))
      {
        Tx(0,0) = Tx(1,1) = Tx(2,2) = Tx(3,3) = 1;
        pTransformSVG->CTM *= Tx;
      }
    } else if(!strncmp("translate",StrTransform,9))
    {
      StrTransform += 9;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform!='(') continue;
      StrTransform++;
      float_matrix Tx(4,4,(float)0);
      if(ReadFloat(&StrTransform, Tx(3,0)))
      {
        Tx(0,0) = Tx(1,1) = Tx(2,2) = Tx(3,3) = 1;
        if(*StrTransform==',')
        {
          StrTransform++;
          if(ReadFloat(&StrTransform, Tx(3,1)))
          {
            pTransformSVG->CTM *= Tx;
          }
        }
      }
    } else if(!strncmp("scaleX",StrTransform,6))
    {
      StrTransform += 6;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform!='(') continue;
      StrTransform++;
      float_matrix Tx(4,4,(float)0);
      if(ReadFloat(&StrTransform, Tx(0,0)))
      {
        Tx(1,1) = Tx(2,2) = Tx(3,3) = 1;
        pTransformSVG->CTM *= Tx;
      }
    } else if(!strncmp("scaleY",StrTransform,6))
    {
      StrTransform += 6;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform!='(') continue;
      StrTransform++;
      float_matrix Tx(4,4,(float)0);
      if(ReadFloat(&StrTransform, Tx(1,1)))
      {
         Tx(0,0) = Tx(2,2) = Tx(3,3) = 1;
         pTransformSVG->CTM *= Tx;
      }
    } else if(!strncmp("scale",StrTransform,5))
    {
      StrTransform += 5;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform=='(')
      {
        StrTransform++;
        float_matrix Tx(4,4,(float)0);
        if(ReadFloat(&StrTransform, Tx(0,0)))
        {
           Tx(2,2) = Tx(3,3) = 1;
           if(*StrTransform==',')
           {
             StrTransform++;
             if(ReadFloat(&StrTransform, Tx(1,1)))
             {
               pTransformSVG->CTM *= Tx;
             }
           }
        }
      }
    } else if(!strncmp("rotate",StrTransform,6))
    {
      StrTransform += 6;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform!='(') continue;
      StrTransform++;
      float angle;
      if(ReadFloat(&StrTransform,angle))
      {
        if(fabs(angle) > 1e-4)
        {
          angle = DEG2RAD(angle);
          float_matrix Tx(4,4,(float)0);
          Tx(2,2) = Tx(3,3) = 1;
          Tx(1,1) = Tx(0,0) = cos(angle);
          Tx(0,1) = sin(angle);
          Tx(1,0) =-Tx(0,1);
          pTransformSVG->CTM *= Tx;
        }
      }
    } else if(!strncmp("matrix",StrTransform,6))	// Only 3x2 matrix is supported, 4x4 not.
    {
      StrTransform += 6;
      while(isspace(*StrTransform)) {StrTransform++;}
      if(*StrTransform!='(') continue;
      StrTransform++;
      float_matrix Tx(4,4,(float)0);
      Tx(2,2) = Tx(3,3) = 1;

      bool Result = ReadFloat(&StrTransform, Tx(0,0));
      if(*StrTransform==',') StrTransform++;
      Result &= ReadFloat(&StrTransform, Tx(0,1));

      if(*StrTransform==',') StrTransform++;
      Result &= ReadFloat(&StrTransform, Tx(1,0));
      if(*StrTransform==',') StrTransform++;
      Result &= ReadFloat(&StrTransform, Tx(1,1));

      if(*StrTransform==',') StrTransform++;
      Result &= ReadFloat(&StrTransform, Tx(3,0));
      if(*StrTransform==',') StrTransform++;
      Result &= ReadFloat(&StrTransform, Tx(3,1));

      if(Result)
      {
        pTransformSVG->CTM *= Tx;
      }
    } else
    {			// No keyword recognised; skip one character.
      StrTransform++;
      continue;
    }

    while(*StrTransform!=')')
    {
      if(*StrTransform==0) break;
          StrTransform++;
    }
    if(*StrTransform==')') StrTransform++;

//skew(0, 0), skewX(0), skewY(0)
//   1 tg(a) 0. 0      1     0  0. 0
//   0   1   0. 0      tg(b) 1  0  0
//X  0   0   1  0   Y  0   0   1  0
//   0...0   0  1      0...0   0  1
  }

return pTransformSVG;
}


/////////////////////////////////////////////////////////////


//static void ProcessKeySVG(TconvertedPass1_XML *cq);


/*This function extracts some information from meta ?xml tag*/
/*
static void MetaXML(TconvertedPass1_XML *cq)
{
#ifdef DEBUG
  fprintf(cq->log,"\n#MetaXML() ");fflush(cq->log);
#endif
int i;
char *charset;
  //strcpy(cq->ObjType, "?xml");

  if((i=cq->TAG_Args IN "encoding")>=0)
	{
	charset = cq->TAG_Args.Member(i,1);
	if(charset==NULL) return;

	cq->SelectTranslator(charset);
	}
}
*/


void TconvertedPass1_SVG::Circle(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Circle ");fflush(log);
#endif
static const char ObjName[] = "!Circle";
float	cx, cy, r;
float stroke_width;

  if(!GetProp("cx",cx)) cx=PositionX;
  if(!GetProp("cy",cy)) cy=PositionY;
  if(GetProp("r",r))
  {
    //const float Scale = GetScale2PSU((TMapMode)MapMode);

    VectorEllipse *pVectCirc = new VectorEllipse(cy-r, cy+r, cx+r, cx-r);
    pVectCirc->AttribFromPSS(PSS);
    GetStyle(pVectCirc,pVectCirc);
    if(GetProp("stroke-width",stroke_width))
    {
      pVectCirc->PenWidth = stroke_width;
    }
    GetColor(pVectCirc->LineColor);
    GetLineCap(pVectCirc->LineCap);
    GetLineJoin(pVectCirc->LineJoin);

    UpdateBBox(bbx, 0, cx-r-pVectCirc->PenWidth/2, cy-r-pVectCirc->PenWidth/2, 2*r+pVectCirc->PenWidth, 2*r+pVectCirc->PenWidth);
    VectList.AddObject(pVectCirc);

    strcpy(ObjType,ObjName+1);
    return;
  }

  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_SVG::Ellipse(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Ellipse ");fflush(log);
#endif
static const char ObjName[] = "!Ellipse";
float	cx, cy, rx, ry;
float stroke_width;

  if(!GetProp("cx",cx)) cx=PositionX;
  if(!GetProp("cy",cy)) cy=PositionY;
  if(!GetProp("rx",rx)) goto ExitErr;
  if(!GetProp("ry",ry)) goto ExitErr;

  {
    VectorEllipse *pVectEll = new VectorEllipse(cy-ry, cy+ry, cx+rx, cx-rx);
    pVectEll->AttribFromPSS(PSS);
    GetStyle(pVectEll,pVectEll);
    if(GetProp("stroke-width",stroke_width))
    {
      pVectEll->PenWidth = stroke_width;
    }
    GetColor(pVectEll->LineColor);
    GetLineCap(pVectEll->LineCap);
    GetLineJoin(pVectEll->LineJoin);

    UpdateBBox(bbx, 0, cx-rx-pVectEll->PenWidth/2, cy-ry-pVectEll->PenWidth/2, 2*rx+pVectEll->PenWidth, 2*ry+pVectEll->PenWidth);
    VectList.AddObject(pVectEll);
  }
  strcpy(ObjType,ObjName+1);
  return;

ExitErr:
  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_SVG::Group(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Group ");fflush(log);
#endif
VectorList VectListIn;
FloatBBox bbxBk = bbx;
RGB_Record LineColorBK = PSS.LineColor;
unsigned char LineCapBK = PSS.LineCap;
unsigned char LineJoinBK = PSS.LineJoin;

  GetLineCap(PSS.LineCap);
  GetLineJoin(PSS.LineJoin);
  GetColor(PSS.LineColor);
  AbstractTransformXY *pTRx = getTransform();

  bbx.MinX=65537; bbx.MaxX=-1; bbx.MinY=65537; bbx.MaxY=-1;
  VectList.Swap(VectListIn);
  recursion++;
  while(!feof(wpd))
  {
    ReadXMLTag(false);
    if(by==XML_closetag && TAG=="</g>")
        break;
    ProcessKeySVG();
  }
  recursion--;
  VectList.Swap(VectListIn);

  if(VectListIn.VectorObjects > 0)
  {		// Bounding box is in PS units.
    if(pTRx != NULL)
    {
      pTRx->ApplyTransform(bbx.MinX,bbx.MinY);
      pTRx->ApplyTransform(bbx.MaxX,bbx.MaxY);
      VectListIn.Transform(*pTRx);
    }
    if(VectList.VectorObjects > 0)
    {
      UpdateBBox(bbx,0, bbxBk.MinX,bbxBk.MinY, bbxBk.MaxX-bbxBk.MinX, bbxBk.MaxY-bbxBk.MinY);
    }
    VectList.Append(VectListIn);
  }
  else
    bbx = bbxBk;
  if(pTRx != NULL) {delete(pTRx); pTRx=NULL;}

  PSS.LineCap = LineCapBK;
  PSS.LineJoin = LineJoinBK;
  PSS.LineColor = LineColorBK;

strcpy(ObjType,"Group");
}


void TconvertedPass1_SVG::Text(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Text ");fflush(log);
#endif
string txt;
float x, y;
int LineLen = 0;
const RGB_Record BkTextColor = PSS.TextColor;

  if(!GetProp("x",x)) x=0;
  if(!GetProp("y",y)) y=0;
  GetColor(PSS.TextColor,FILL_COLOR);

  recursion++;
  while(!feof(wpd))
  {
    ReadXMLTag(false);
    if(by==XML_closetag && TAG=="</text>")
        break;
    if(by==XML_char)
    {
      if(!txt.isEmpty())
      {
        if(txt[txt.length()-1] == '\n')
        {
          txt[txt.length()-1] = ' ';
          if(subby=='\r') continue;
        }
        if(txt[txt.length()-1] == '\r')
        {
          txt[txt.length()-1] = ' ';
          if(subby=='\n') continue;
        }
      }

      txt += subby;
      LineLen++;
      continue;
    }
    ProcessKeySVG();
  }
  recursion--;

  txt = replacesubstring(txt,"\n"," ");
  txt = replacesubstring(txt,"\r"," ");
  LineLen = txt.length();

  if(!txt.isEmpty())
  {
    TextContainer *pTextCont = new TextContainer;
    pTextCont->PosX = x;
    pTextCont->PosY = y;
    pTextCont->AddText(temp_string(txt),PSS);
    VectList.AddObject(pTextCont);
    float FontSize = (PSS.FontSize <= 0) ? 0.25f : PSS.FontSize;
    UpdateBBox(bbx,0, x,y, LineLen*mm2PSu(FontSize), -1.1*mm2PSu(FontSize));
  }

  PSS.TextColor = BkTextColor;
strcpy(ObjType,"Group");
}


void TconvertedPass1_SVG::Line(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Line ");fflush(log);
#endif
static const char ObjName[] = "!Line";
float *Points = (float*)malloc(4*sizeof(float));
float stroke_width;

  if(Points==NULL) goto ExitErr;
  if(!GetProp("x1",Points[0])) Points[0]=PositionX;
  if(!GetProp("y1",Points[1])) Points[1]=PositionY;
  if(!GetProp("x2",Points[2])) goto ExitErr;
  if(!GetProp("y2",Points[3])) goto ExitErr;
  
  {
    VectorLine *pVecLine = new VectorLine(Points, 2); Points=NULL;
    pVecLine->AttribFromPSS(PSS);
    GetStyle(pVecLine,NULL);
    if(GetProp("stroke-width",stroke_width))
    {
      pVecLine->PenWidth = stroke_width;
    }
    GetColor(pVecLine->LineColor);
    GetLineCap(pVecLine->LineCap);
    GetLineJoin(pVecLine->LineJoin);
    VectList.AddObject(pVecLine);
  }
  strcpy(ObjType,ObjName+1);
  return;

ExitErr:
  if(Points!=NULL)
    {free(Points); Points=NULL;}
  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_SVG::ClosePathLine(float **pPoints, int & n, bool Close, AbstractTransformXY *Tx)
{
int i;
float stroke_width;
RGB_Record FillColor;

  if(*pPoints==NULL) return;
  if(n<=0)
  {
    free(*pPoints); *pPoints=NULL;
    return;
  }

//  PositionX = (*pPoints)[Close?0:(2*n-2)];
//  PositionY = (*pPoints)[Close?1:(2*n-1)];
  for(i=0; i<n; i++)
  {
    if(Tx) Tx->ApplyTransform((*pPoints)[2*i], (*pPoints)[2*i+1]);
    UpdateBBox(bbx,0, (*pPoints)[2*i], (*pPoints)[2*i+1], 0, 0);
  }

  VectorLine *pVecLine;
  if(GetColor(FillColor,FILL_COLOR))
  {
     VectorPolygon *pVecPoly = new VectorPolygon(*pPoints,n);
     //pVecPoly->AttribFromPSS(PSS);
     pVecPoly->FillColor = FillColor;
     //pVecPoly->Outline = true;
     pVecLine = pVecPoly;
  }
  else
  {
    pVecLine = new VectorLine(*pPoints,n);
    //pVecLine->AttribFromPSS(PSS);
  }
  pVecLine->AttribFromPSS(PSS);
  if(pVecLine->LineStyle==0) pVecLine->LineStyle=1;

  n = 0;
  *pPoints = NULL;

  if(GetProp("stroke-width",stroke_width))
  {
    pVecLine->PenWidth = stroke_width;
  }
  GetColor(pVecLine->LineColor);
  GetLineCap(pVecLine->LineCap);
  GetLineJoin(pVecLine->LineJoin);
  pVecLine->Close = Close;

  VectList.AddObject(pVecLine);
}


void TconvertedPass1_SVG::ClosePathCurve(float **pPoints, int & n, bool Close, AbstractTransformXY *Tx)
{
int i;
float stroke_width;
  if(*pPoints==NULL) return;
  if(n<=0)
  {
    free(*pPoints); *pPoints=NULL;
    return;
  }

  for(i=0; i<n; i++)
  {
    if(Tx)
    {
      Tx->ApplyTransform((*pPoints)[6*i], (*pPoints)[6*i+1]);
      Tx->ApplyTransform((*pPoints)[6*i+2], (*pPoints)[6*i+3]);
      Tx->ApplyTransform((*pPoints)[6*i+4], (*pPoints)[6*i+5]);
    }
    UpdateBBox(bbx,0, (*pPoints)[6*i], (*pPoints)[6*i+1], 0, 0);
  }
  PositionX = (*pPoints)[6*n];
  PositionY = (*pPoints)[6*n+1];
  if(Tx) Tx->ApplyTransform((*pPoints)[6*n], (*pPoints)[6*n+1]);	// The last curve point must be also transformed.

  VectorCurve *pVecCurve = new VectorCurve(*pPoints, 3*n+1); n=0;
  *pPoints = NULL;
  pVecCurve->AttribFromPSS(PSS);
  if(GetProp("stroke-width",stroke_width))
  {
    pVecCurve->PenWidth = stroke_width;
  }
  GetColor(pVecCurve->LineColor);
  GetLineCap(pVecCurve->LineCap);
  GetLineJoin(pVecCurve->LineJoin);
  pVecCurve->Close = Close;
  VectList.AddObject(pVecCurve);
}


void TconvertedPass1_SVG::Path(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Path ");fflush(log);
#endif
static const char ObjName[] = "!Path";
float *Points = NULL;
float val;
int n, i;
const char *StrMovements;
float PositionOffsetX = 0;
float PositionOffsetY = 0;
bool isCurve = false;
bool FirstCommand = true;
char LastCommand = 0;
AbstractTransformXY *Tx = NULL;
int SegmentCount = 0;

  n = 0;
  if((i=TAG_Args IN "d")<0) goto ExitErr;
  StrMovements = TAG_Args.Member(i,1);
  if(StrMovements==NULL) goto ExitErr;

  Tx = getTransform();
  while(*StrMovements != 0)
  {
    while(isspace(*StrMovements)) StrMovements++;
    switch((isdigit(*StrMovements) || *StrMovements=='.' || *StrMovements=='-' || *StrMovements==0) ? LastCommand : *StrMovements++)
    {
      case 'M':			//move to.
        if(n>0) SegmentCount++;
        if(isCurve)
          ClosePathCurve(&Points,n,false,Tx);
        else
          ClosePathLine(&Points,n,false,Tx);

        ReadFloat(&StrMovements, PositionX);
        if(*StrMovements==',') StrMovements++;
        while(isspace(*StrMovements)) StrMovements++;
        if(isdigit(*StrMovements) || *StrMovements=='.' || *StrMovements=='-')
        {
          ReadFloat(&StrMovements, PositionY);
        }
        PositionOffsetX = PositionOffsetY = 0;
        FirstCommand = false;
        break;

      case 'm':			//relative move to.
        if(n>0) SegmentCount++;
        if(isCurve)
          ClosePathCurve(&Points,n,false,Tx);
        else
          ClosePathLine(&Points,n,false,Tx);

        ReadFloat(&StrMovements, PositionOffsetX);
        if(FirstCommand)
            PositionX = PositionOffsetX;
        else
        {
          PositionX += PositionOffsetX;
          PositionOffsetX = PositionX;
        }

        if(*StrMovements==',') StrMovements++;
        while(isspace(*StrMovements)) StrMovements++;
        if(isdigit(*StrMovements) || *StrMovements=='.' || *StrMovements=='-')
        {
          ReadFloat(&StrMovements, PositionOffsetY);
          if(FirstCommand)
            PositionY = PositionOffsetY;
          else
          {
            PositionY += PositionOffsetY;
            PositionOffsetY = PositionY;
          }
        }
        FirstCommand = false;
        break;

     case 'H':		//horizontal line to.
        LastCommand = 'H';
        if(isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathCurve(&Points,n,false,Tx);
          isCurve = false;
        }

          if(Points==NULL)
          {
            Points = (float*)malloc(4*sizeof(float));
            if(!Points) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 2;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,2*n*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, Points[2*n-2]);
          Points[2*n-2] += PositionOffsetX;
          Points[2*n-1] = PositionY + PositionOffsetY;
        break;

     case 'h':		// horizontal relative line to.
        LastCommand = 'h';
        if(isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathCurve(&Points,n,false,Tx);
          isCurve = false;
        }

          if(Points==NULL)
          {
            Points = (float*)malloc(4*sizeof(float));
            if(!Points) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 2;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,2*n*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, val);
          PositionX += val;
          Points[2*n-2] = PositionX;
          Points[2*n-1] = PositionY;
        break;

     case 'V':		//vertical line to.
        LastCommand = 'V';
        if(isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathCurve(&Points,n,false,Tx);
          isCurve = false;
        }

          if(Points==NULL)
          {
            Points = (float*)malloc(4*sizeof(float));
            if(!Points) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 2;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,2*n*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, Points[2*n-1]);
          Points[2*n-1] += PositionOffsetY;
          Points[2*n-2] = PositionX + PositionOffsetX;
        break;

     case 'v':		// vertical relative line to.
        LastCommand = 'v';
        if(isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathCurve(&Points,n,false,Tx);
          isCurve = false;
        }

          if(Points==NULL)
          {
            Points = (float*)malloc(4*sizeof(float));
            if(!Points) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 2;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,2*n*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, val);
          PositionY += val;
          Points[2*n-2] = PositionX;
          Points[2*n-1] = PositionY;
        break;

     case 'L':		//line to.
        LastCommand = 'L';
        if(isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathCurve(&Points,n,false,Tx);
          isCurve = false;
        }

          if(Points==NULL)
          {
            Points = (float*)malloc(4*sizeof(float));
            if(!Points) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 2;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,2*n*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, Points[2*n-2]);
          if(*StrMovements==',') StrMovements++;
          while(isspace(*StrMovements)) StrMovements++;
          if(isdigit(*StrMovements) || *StrMovements=='.' || *StrMovements=='-')
          {
            ReadFloat(&StrMovements, Points[2*n-1]);
          }
          else
            Points[2*n-1] = PositionY;

          Points[2*n-2] += PositionOffsetX;
          Points[2*n-1] += PositionOffsetY;
       break;

     case 'l':		//relative line to.
        LastCommand = 'l';
        if(isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathCurve(&Points,n,false,Tx);
          isCurve = false;
        }
          if(Points==NULL)
          {
            Points = (float*)malloc(4*sizeof(float));
            if(!Points) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 2;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,2*n*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, val);
          PositionX += val;
          Points[2*n-2] = PositionX;
          if(*StrMovements==',') StrMovements++;
          while(isspace(*StrMovements)) StrMovements++;
          if(isdigit(*StrMovements) || *StrMovements=='.' || *StrMovements=='-')
          {
            ReadFloat(&StrMovements, val);
            PositionY += val;
          }
          Points[2*n-1] = PositionY;
       break;

    case 'C':		//curve to.
        LastCommand = 'C';
        if(!isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathLine(&Points,n,false,Tx);
          isCurve = true;
        }

          if(Points==NULL)
          {
            Points=(float*)malloc(8*sizeof(float));
            if(Points==NULL) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 1;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,(2+6*n)*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, Points[2+6*n-6]);
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, Points[2+6*n-5]);
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, Points[2+6*n-4]);
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, Points[2+6*n-3]);
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, Points[2+6*n-2]);
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, Points[2+6*n-1]);

          Points[2*n-6] += PositionOffsetX;
          Points[2*n-4] += PositionOffsetX;
          Points[2*n-2] += PositionOffsetX;
          Points[2*n-5] += PositionOffsetY;
          Points[2*n-3] += PositionOffsetY;
          Points[2*n-1] += PositionOffsetY;
        break;

    case 'c':		//relative curve to.
        LastCommand = 'c';
        if(!isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathLine(&Points,n,false,Tx);
          isCurve = true;
        }

          if(Points==NULL)
          {
            Points=(float*)malloc(8*sizeof(float));
            if(Points==NULL) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 1;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,(2+6*n)*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, val);
          Points[2+6*n-6] = PositionX + val;
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, val);
          Points[2+6*n-5] = PositionY + val;
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, val);
          Points[2+6*n-4] = PositionX + val;
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, val);
          Points[2+6*n-3] = PositionY + val;

          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, val);
          PositionX += val;
          Points[2+6*n-2] = PositionX;
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, val);
          PositionY += val;
          Points[2+6*n-1] = PositionY;
        break;

    case 'S':		// shorter curve to.
        LastCommand = 'S';
        if(!isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathLine(&Points,n,false,Tx);
          isCurve = true;
        }
        if(Points==NULL)
        {
          Points=(float*)malloc(8*sizeof(float));
          if(Points==NULL) goto ExitErr;
          Points[0]=PositionX; Points[1]=PositionY;
          n = 1;
        }
        else
        {
          n++;
          Points = (float*)realloc(Points,(2+6*n)*sizeof(float));
          if(Points==NULL) goto ExitErr;
        }

        ReadFloat(&StrMovements, Points[2+6*n-4]);
        if(*StrMovements==',') StrMovements++;
        ReadFloat(&StrMovements, Points[2+6*n-3]);
        ReadFloat(&StrMovements, Points[2+6*n-2]);
        if(*StrMovements==',') StrMovements++;
        ReadFloat(&StrMovements, Points[2+6*n-1]);
        if(n==1)
        {
          Points[2+6*n-6] = Points[2+6*n-4];
          Points[2+6*n-5] = Points[2+6*n-3];
        }
        else
        {
          Points[2+6*n-6] = 2*Points[2+6*n-8] - Points[2+6*n-10];
          Points[2+6*n-5] = 2*Points[2+6*n-7] - Points[2+6*n-9];
        }
        break;

    case 's':		// relative shorter curve to.
        LastCommand = 's';
        if(!isCurve)
        {
          if(n>0) SegmentCount++;
          ClosePathLine(&Points,n,false,Tx);
          isCurve = true;
        }

          if(Points==NULL)
          {
            Points=(float*)malloc(8*sizeof(float));
            if(Points==NULL) goto ExitErr;
            Points[0]=PositionX; Points[1]=PositionY;
            n = 1;
          }
          else
          {
            n++;
            Points = (float*)realloc(Points,(2+6*n)*sizeof(float));
            if(Points==NULL) goto ExitErr;
          }

          ReadFloat(&StrMovements, Points[2+6*n-4]);
          Points[2+6*n-4] += PositionX;
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, Points[2+6*n-3]);
          Points[2+6*n-3] += PositionY;
          ReadFloat(&StrMovements, Points[2+6*n-2]);
          Points[2+6*n-2] += PositionX;
          if(*StrMovements==',') StrMovements++;
          ReadFloat(&StrMovements, Points[2+6*n-1]);
          Points[2+6*n-1] += PositionY;
          if(n==1)
          {
            Points[2+6*n-6] = Points[2+6*n-4];
            Points[2+6*n-5] = Points[2+6*n-3];
          }
          else
          {
            Points[2+6*n-6] = 2*Points[2+6*n-8] - Points[2+6*n-10];
            Points[2+6*n-5] = 2*Points[2+6*n-7] - Points[2+6*n-9];
          }
          PositionX = Points[2+6*n-2];
          PositionY = Points[2+6*n-1];
        break;

      case 'Z':		// close path
      case 'z':
        if(isCurve)
            ClosePathCurve(&Points, n, SegmentCount<=0, Tx);
        else
            ClosePathLine(&Points, n, SegmentCount<=0, Tx);
        SegmentCount = 0;
        break;

      default:
        if(isdigit(*StrMovements) || *StrMovements=='.' || *StrMovements=='-')
            StrMovements++;		// Not incremented in switch argument.
        else
        {
          if(err!=NULL)
              fprintf(err,_("\nError: Unsupported command '%c' in SVG path!"),*(StrMovements-1));
        }
        break;

   }

  }

  if(isCurve)
    ClosePathCurve(&Points,n,false,Tx);
  else
    ClosePathLine(&Points,n,false,Tx);

  strcpy(ObjType,ObjName+1);
  if(Tx) delete Tx;
  return;

ExitErr:
  if(Points) {free(Points);Points=NULL;}
  strcpy(ObjType,ObjName);
  if(Tx) delete Tx;
}


void TconvertedPass1_SVG::PolyLine(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::PolyLine ");fflush(log);
#endif
static const char ObjName[] = "!PolyLine";
float *Points;
float stroke_width;
int n;

  Points = LoadPoints(n);
  if(Points!=NULL)
  {

    VectorLine *pVecLine = new VectorLine(Points, n); Points=NULL;
    pVecLine->AttribFromPSS(PSS);
    GetStyle(pVecLine,NULL);
    if(GetProp("stroke-width",stroke_width))
    {
      pVecLine->PenWidth = stroke_width;
    }
    GetColor(pVecLine->LineColor);
    GetLineCap(pVecLine->LineCap);
    VectList.AddObject(pVecLine);

    strcpy(ObjType,ObjName+1);
    return;
  }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_SVG::Polygon(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Polygon ");fflush(log);
#endif
static const char ObjName[] = "!Polygon";
float *Points;
float stroke_width;
int n;

  Points = LoadPoints(n);
  if(Points!=NULL)
  {

    VectorPolygon *pVecPoly = new VectorPolygon(Points, n); Points=NULL;
    pVecPoly->AttribFromPSS(PSS);
    GetStyle(pVecPoly,pVecPoly);
    if(GetProp("stroke-width",stroke_width))
    {
      pVecPoly->PenWidth = stroke_width;
    }
    GetColor(pVecPoly->LineColor);
    GetColor(pVecPoly->FillColor,FILL_COLOR);
    GetLineCap(pVecPoly->LineCap);
    pVecPoly->Close = true;
    VectList.AddObject(pVecPoly);

    strcpy(ObjType,ObjName+1);
    return;
  }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_SVG::Rectangle(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Rectangle ");fflush(log);
#endif
static const char ObjName[] = "!Rectangle";
float	x, y, Width, Height, rx, ry;
float stroke_width;
VectorRectangle *pVectRec;
AbstractTransformXY *Tx = NULL;

  if(!GetProp("width",Width)) goto ExitErr;
  if(!GetProp("height",Height)) goto ExitErr;
  if(!GetProp("x",x)) x=0;
  if(!GetProp("y",y)) y=0;
  if(!GetProp("rx",rx)) rx=0;
  if(!GetProp("ry",ry)) ry=0;
  Tx = getTransform();

  if(rx>0 && ry>0)
    pVectRec = new VectorRectangleArc(y, y+Height, x, x+Width, rx, ry);
  else
    pVectRec = new VectorRectangle(y, y+Height, x, x+Width);
  pVectRec->AttribFromPSS(PSS);
  GetStyle(pVectRec,pVectRec);
  if(GetProp("stroke-width",stroke_width))
  {
    pVectRec->PenWidth = stroke_width;
  }
  GetColor(pVectRec->LineColor);
  GetColor(pVectRec->FillColor,FILL_COLOR);

  if(Tx && pVectRec->Tx==NULL)
  {
    pVectRec->Tx = Tx;
    Tx = NULL;
  }
  pVectRec->CalcBoundingBox(bbx);

  VectList.AddObject(pVectRec);

  strcpy(ObjType,ObjName+1);
  if(Tx) delete Tx;
  return;

ExitErr:
  strcpy(ObjType,ObjName);
}


void TconvertedPass1_SVG::Defs(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Defs ");fflush(log);
#endif
static const char ObjName[] = "!Defs";
int i;

  recursion++;
  while(!feof(wpd))
  {
    ReadXMLTag(false);
    if(by==XML_closetag && TAG=="</defs>")
        break;

    if((i=TAG_Args IN "id") >= 0)
    {
      const char * const Payload = TAG_Args.Member(i,1);
      if(Payload!=NULL)
      {
        DefinedObject *pDefObj = new DefinedObject;
        if(pDefObj!=NULL)
        {
          pDefObj->id = Payload;
          VectList.Swap(pDefObj->VectList);
          ProcessKeySVG();
          VectList.Swap(pDefObj->VectList);
          if(pDefObj->VectList.VectorObjects > 0)
              AddDefine(pDefObj);
          else
              delete pDefObj;
          continue;	// The command has been already processed.
        }
      }
    }

    ProcessKeySVG();
  }
  recursion--;

  strcpy(ObjType,ObjName+1);
}


/// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use
void TconvertedPass1_SVG::Use(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Use ");fflush(log);
#endif
static const char ObjName[] = "!Use";
float x, y;
int i;
TransformSVG *pTx = NULL;

  // href
  if(!GetProp("x",x)) x=0;
  if(!GetProp("y",y)) y=0;
  //Note: width, and height have no effect on use elements, unless the element referenced has a viewBox - i.e. they only have an effect when use refers to a svg or symbol element.
  // width
  // height

  if(x!=0 || y!=0)
  {
    pTx = new TransformSVG;
    pTx->CTM(3,0) = x;
    pTx->CTM(3,1) = y;
  }

  if((i=TAG_Args IN "xlink:href")>=0)
  {
    const char * const Payload = TAG_Args.Member(i,1);
    if(Payload==NULL) goto ExitFail;
    if(Payload[0]!='#') goto ExitFail;

    const DefinedObject *pDObj = GetDefine(Payload+1);
    if(pDObj==NULL) goto ExitFail;
    VectorObject *pObj = pDObj->VectList.Duplicate();
    if(pObj==NULL) goto ExitFail;

    if(pTx) pObj->Transform(*pTx);	// Apply shift x,y operation.
    VectList.AddObject(pObj);

    strcpy(ObjType,ObjName+1);
    if(pTx) {delete(pTx);pTx=NULL;}
    return;
  }

ExitFail:
  strcpy(ObjType,ObjName);
  if(pTx) {delete(pTx);pTx=NULL;}
}


void TconvertedPass1_SVG::ProcessKeySVG(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG:::ProcessKeySVG() ");fflush(log);
#endif
string loc_TAG;
const char *tag;
uint8_t by, subby;

 *ObjType=0;
 if(TAG.isEmpty()) ReadXMLTag(false);
 by = this->by;
 subby = this->subby;

 switch(by)
	{
	case XML_char:
		if(this->subby=='\n')
		  {ObjType[0]='\\'; ObjType[1]='n'; ObjType[2]=0;}
		else
		  {ObjType[0]=this->subby; ObjType[1]=0;}
		tag = ObjType;
		switch(this->subby)			//Normal character
		  {
		  case 10:
		  case 13:strcpy(ObjType, "\\n");break;	//CR
		  case  9:strcpy(ObjType, "!Tab");break;
		  case 32:by=32;break;  //Space
		  }
	       break;
	case XML_extchar:
	       if(TAG.isEmpty()) break;			//Extended chatacter &xxx;
	       loc_TAG = Ext_chr_str(TAG[0],this)+copy(TAG,1,length(TAG)-1);
	       tag = loc_TAG();
	       //by=201;
	       break;

	case XML_badextchar:
               loc_TAG = copy(TAG,1,length(TAG)-2);   //Extended chatacter &xxx;
	       if((tag=loc_TAG())==NULL) break;
/*
	       if(TAG=="nbsp")	{by=200;break;}  	//Hard space

	       if((i=(TAG() IN HTMLChars))>0)
		  {
		  i--;
		  by=201;
		  tag = Ext_chr_str(i, cq, ConvertHTML); //Translate HTML character set to WP5.x one
		  } */
	       break;

	case XML_tag:
               loc_TAG = copy(TAG,1,length(TAG)-2);	//Normal tag <xxx>
	       if((tag=loc_TAG())==NULL) break;

	       //if(TAG=="?xml")    {MetaXML(this);break;}
	       if(loc_TAG=="rect")    {by=130;break;}
	       if(loc_TAG=="circle")  {by=131;break;}
	       if(loc_TAG=="ellipse") {by=132;break;}
	       if(loc_TAG=="line")    {by=133;break;}
	       if(loc_TAG=="polyline"){by=134;break;}
	       if(loc_TAG=="polygon") {by=135;break;}
	       if(loc_TAG=="path")    {by=136;break;}
	       if(loc_TAG=="g")       {by=137;break;}
	       if(loc_TAG=="text")    {by=138;break;}
	       if(loc_TAG=="defs")    {by=139;break;}
               if(loc_TAG=="use")     {by=140;break;}
	       break;
	case XML_closetag:
               loc_TAG = copy(TAG,2,length(TAG)-3);	//Closing tag </xxx>
	       if((tag=loc_TAG())==NULL) break;
	       if(loc_TAG=="defs")    {by=139;break;}
	       break;
	case XML_comment: 			//comment
        case XML_CDATA:
	       break;
	}

  this->by = by;
  this->subby = subby;
  if(flag<Nothing)
    switch(by)
	{
/*	case XML_char:		//Normal character
               tag=Ext_chr_str(subby,cq,ConvertCpg);
	       CharacterStr(cq,tag);
	       break;		//Normal character */
        case XML_CDATA:
	case XML_comment:
               CommentXML();
	       break;
/*	case XML_unicode:
               CharacterStr(cq,TAG);
	       break;		//Already expanded unicode character */

	case 32:putc(' ', strip);   /*soft space*/
		break;

	case 130:Rectangle(); break;
	case 131:Circle(); break;
	case 132:Ellipse(); break;
	case 133:Line(); break;
	case 134:PolyLine(); break;
	case 135:Polygon(); break;
	case 136:Path(); break;
	case 137:Group(); break;
	case 138:Text(); break;
	case 139:Defs(); break;
	case 140:Use(); break;
	}


 this->by = by;
 this->subby = subby;		// restore local by & subby.
 if (log != NULL)
    {   /**/
    if(by==128)
        fputc('\n',log);
    else if(by==' ' || by==200) fputc(' ',log);
    else if(by==0 || by==201)
	{
	fprintf(log,"%s",tag);
	}
    else
	{
	fprintf(log, _("\n%*s [%s %s]   "),
		  recursion * 2, "", TAG(), ObjType);
//	if(*ObjType==0) UnknownObjects++;
	}
    }

 ActualPos = ftell(wpd);
}


int TconvertedPass1_SVG::Convert_first_pass(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_SVG::Convert_first_pass() ");fflush(log);
#endif
uint32_t fsize;
int RetVal = 0;

  PositionX = PositionY = 0;
  if(Verbosing >= 1)
     printf(_("\n>>>SVG2LaTeX<<< Conversion program: From SVG to LaTeX Version %s\n"
	      "      Made by J.Fojtik  (Hosted on WP2LaTeX :))))\n\n"),
			SVGVersion);
  ConvertHTML = GetTranslator("htmlTOinternal");
  CharReader = &ch_fgetc;

  TablePos=0;

  DocumentStart = ftell(wpd);
  fsize = FileSize(wpd);
  perc.Init(ftell(wpd), fsize,_("First pass SVG:") );

  ActualPos = ftell(wpd);
  while(ActualPos < fsize)
      {
      if(Verbosing >= 1)		//actualise a procentage counter
	      perc.Actualise(ActualPos);

      TAG.erase();
      ProcessKeySVG();
      }

  const float Scale = /*GetScale2PSU((TMapMode)MapMode) * */ 25.4f / 71.0f;	// convert PSu to WPGu (quite bad).

  if(VectList.VectorObjects>0)
  {
    vFlip flipTrx(bbx.MinY, bbx.MaxY);
    VectList.Transform(flipTrx);

    if(Img.VecImage==NULL)
    {
      Img.AttachVecImg(new VectorImage(VectList,PSS));

      if(Img.dx!=0 && Img.dy!=0 && Img.Raster!=NULL)
      {
        if(Img.VecImage!=NULL)	// Move raster data to different image frame.
        {
          Image *Img2 = &Img;
          while(Img2->Next!=NULL)
              Img2 = Img2->Next;
          Img2->Next = new Image();
          Img2 = Img2->Next;

          Img2->x =  bbx.MinX * Scale;
          Img2->y =  bbx.MinY * Scale;
          Img2->dx = (bbx.MaxX - bbx.MinX) * Scale;
          Img2->dy = (bbx.MaxY - bbx.MinY) * Scale;
          Img2->VecImage = Img.VecImage; Img.VecImage=NULL;
        }
      }
      else	// Use whole frame as bounding box.
      {
        Img.x =  bbx.MinX * Scale;
        Img.y =  bbx.MinY * Scale;
        Img.dx = (bbx.MaxX - bbx.MinX) * Scale;
        Img.dy = (bbx.MaxY - bbx.MinY) * Scale;
      }
    }
  }

  if(Img.Raster!=NULL || Img.VecImage!=NULL)
    {
    for(Image *pImg=&Img; pImg!=NULL; pImg=pImg->Next)
      if(pImg->Raster!=NULL)
        ReducePalette(pImg,256);

    string NewFilename = MergePaths(OutputDir,RelativeFigDir);
    string wpd_cut = CutFileName(wpd_filename);
    if(recursion==0 && length(wpd_cut)>0)
      NewFilename += wpd_cut + ".eps";
    else
      NewFilename += GetFullFileName(GetSomeImgName(".eps"));
    if(SavePictureEPS(NewFilename(),Img)<0)
	{
        if(err != NULL)
	  {
	  perc.Hide();
	  fprintf(err, _("\nError: Cannot save file: \"%s\"!"), NewFilename());
	  }
	return 0;
        }

    NewFilename = CutFileName(NewFilename); 	//New Filename only

    PutImageIncluder(NewFilename());

    InputPS |= 1;		//mark style as used
    Finalise_Conversion(this);
    RetVal++;
    }

  //OutCodePage = CodePageBk;
  return(RetVal);
}

