Files
core/ASCPresentationEditor/OfficeDrawing/SVGFramework.h
Elen.Subbotina 4fcc2101c8 X2t Converter подключение txt &ppt
fix bugs ppt

git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@62503 954022d7-b5bf-4e40-9824-e11837661b57
2016-05-21 00:02:10 +03:00

6305 lines
158 KiB
C++

#pragma once
#include <math.h>
#include "Shapes/BaseShape/GraphicsPath.h"
#include "../../DesktopEditor/graphics/IRenderer.h"
#define GET_ATTRIBUTEN(NAME) if(style==NAME)return m_n##NAME;
#define GET_ATTRIBUTED(NAME) if(style==NAME)return m_n##NAME;
#define GET_ATTRIBUTE(NAME) if(style==NAME)return m_##NAME;
#define VALIDATE_ATTRIBUTE(NAME) if(nStyle==NAME)return m_bHave##NAME;
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
// Êîíñòàíòà äëÿ ìàêñèìàëüíîãî ÷èñëà ñèìâîëîâ â ñòðîêå
#define MAX_SIZE 256
// Êîíñòàíòà äëÿ ìàêñèìàëüíîãî ÷èñëà çàãðóæàåìûõ áàéò
#define MAX_PATH_DOWNLOAD_FILE_SIZE 32768
#define MAX_SINGLE_DOWNLOAD_FILE_SIZE 524288
// Êîíñòàíòà äëÿ ïîëó÷åíèÿ ðàçìåðà ôàéëà
#define CONTENT_RANGE _T("bytes 0-0/")
// Êîíñòàíòà äëÿ êîëëè÷åñòâà ñèìâîëîâ ó CONTENT_RANGE
#define CONTENT_RANGE_SIZE ( 11/*sizeof ( CONTENT_RANGE )*/ - 1 )
#define BUFSIZE 4096
//------------------------------------------------------------------------------------------------------
namespace SVG
{
const long c_ag_LineCapFlat = 0;
const long c_ag_LineCapSquare = 1;
const long c_ag_LineCapTriangle = 3;
const long c_ag_LineCapNoAnchor = 16;
const long c_ag_LineCapSquareAnchor = 17;
const long c_ag_LineCapRoundAnchor = 18;
const long c_ag_LineCapDiamondAnchor = 19;
const long c_ag_LineCapArrowAnchor = 20;
const long c_ag_LineCapAnchorMask = 240;
const long c_ag_LineCapCustom = 255;
const long c_ag_DashCapFlat = 0;
const long c_ag_DashCapRound = 2;
const long c_ag_DashCapTriangle = 3;
const long c_ag_LineJoinMiter = 0;
const long c_ag_LineJoinBevel = 1;
const long c_ag_LineJoinRound = 2;
const long c_ag_LineJoinMiterClipped = 3;
const long c_ag_PenAlignmentCenter = 0;
const long c_ag_PenAlignmentInset = 1;
const long c_ag_PenAlignmentOutset = 2;
const long c_ag_PenAlignmentLeft = 3;
const long c_ag_PenAlignmentRight = 4;
const long c_dirHorizontal = 1;
const long c_dirVertical = -1;
const long PNG_ENCODER = 0;
const long JPG_ENCODER = 1;
const long INVALID_ENCODER = -1;
const long c_BrushTypeSolid = 1000;
const long c_BrushTypeHorizontal = 2001;
const long c_BrushTypeVertical = 2002;
const long c_BrushTypeDiagonal1 = 2003;
const long c_BrushTypeDiagonal2 = 2004;
const long c_BrushTypeCenter = 2005;
const long c_BrushTypePathGradient1 = 2006;
const long c_BrushTypePathGradient2 = 2007;
const long c_BrushTypeCylinderHor = 2008;
const long c_BrushTypeCylinderVer = 2009;
const long c_BrushTypeTexture = 3008;
const long c_BrushTypePattern = 3009;
const long c_BrushTypeHatch1 = 4009;
const long c_BrushTypeHatch53 = 4061;
}
namespace StringHelpers
{
static inline bool RemoveTagHTMLA (CStringA& strXml, const CStringA& strBeginTrag, const CStringA& strEndTrag)
{
int from = 0;
int to = 0;
from = strXml.Find (strBeginTrag, from);
if ( -1 == from )
return false;
to = strXml.Find (strEndTrag, from);
if ( -1 == to )
return false;
if ( (to != from) && to > from )
{
CStringA strRes;
if ( from - 1 > 0 )
strRes = strXml.Mid (0, from);
strRes += strXml.Mid (to + 1, strXml.GetLength () - to - 1);
strXml = strRes;
return RemoveTagHTMLA (strXml, strBeginTrag, strEndTrag);
}
return false;
}
static inline bool RemoveCommentsA (CStringA& strXml)
{
int from = 0;
int to = 0;
from = strXml.Find ("<!--", from );
if ( -1 == from )
return false;
to = strXml.Find ("-->", from );
if ( -1 == to )
return false;
if ( (to != from) && to > from )
{
CString result;
if ( from - 1 > 0 )
result = strXml.Mid ( 0, from - 1 );
result += strXml.Mid ( to + 3, strXml.GetLength () - to - 3 );
strXml = result;
return RemoveCommentsA (strXml);
}
return false;
}
static inline bool RemoveTagHTML (CString& strXml, const CString& strBeginTrag, const CString& strEndTrag)
{
int from = 0;
int to = 0;
from = strXml.Find (strBeginTrag, from);
if ( -1 == from )
return false;
to = strXml.Find (strEndTrag, from);
if ( -1 == to )
return false;
if ( (to != from) && to > from )
{
CString strRes;
if ( from - 1 > 0 )
strRes = strXml.Mid (0, from);
strRes += strXml.Mid (to + 1, strXml.GetLength () - to - 1);
strXml = strRes;
return RemoveTagHTML (strXml, strBeginTrag, strEndTrag);
}
return false;
}
static inline bool RemoveComments (CString& strXml)
{
int from = 0;
int to = 0;
from = strXml.Find ( _T("<!--"), from );
if ( -1 == from )
return false;
to = strXml.Find ( _T("-->"), from );
if ( -1 == to )
return false;
if ( (to != from) && to > from )
{
CString result = _T("");
if ( from - 1 > 0 )
result = strXml.Mid ( 0, from - 1 );
result += strXml.Mid ( to + 3, strXml.GetLength () - to - 3 );
strXml = result;
return RemoveComments (strXml);
}
return false;
}
//static inline bool LoadXmlFile (const CString& File, CStringA& strXmlA)
//{
// CAtlFile oFile;
// if (FAILED(oFile.Create(File, GENERIC_READ, FILE_SHARE_READ, OPEN_ALWAYS)))
// return false;
// ULONGLONG bufSize = 0L;
// if (FAILED(oFile.GetSize(bufSize)))
// {
// oFile.Close ();
// return false;
// }
// BYTE* buffer = new BYTE [ bufSize ];
// if ( NULL == buffer )
// {
// oFile.Close ();
// return false;
// }
// memset ( buffer, 0, bufSize );
// DWORD dwBufSize = (DWORD) bufSize;
// if ( FAILED ( oFile.Read ( buffer, dwBufSize ) ) )
// {
// RELEASEARRAYOBJECTS(buffer);
// oFile.Close ();
// return false;
// }
// oFile.Close ();
// BYTE Symbol = buffer[bufSize];
// buffer[bufSize] = L'\0';
// strXmlA = CStringA(buffer);
// buffer[bufSize] = Symbol;
// //if (strXmlA.GetLength() > 1)
// //{
// // StringHelpers::RemoveTagHTMLA (strXmlA, CStringA("<!ENTITY"), CStringA(">"));
// // StringHelpers::RemoveTagHTMLA (strXmlA, CStringA("<!DOCTYPE"), CStringA(">"));
// // StringHelpers::RemoveCommentsA (strXmlA);
// //}
// //strXml = XmlUtils::ConvertToUnicode (strXmlA);
// RELEASEARRAYOBJECTS(buffer);
// return true;
//}
};
namespace SVG
{
inline static double DoubleFromString(CString& strValue)
{
TCHAR* buffer = strValue.GetBuffer();
int nLen = strValue.GetLength();
int i = 0;
for (; i < nLen; ++i)
{
if (((buffer[i] >= TCHAR('0')) && (buffer[i] <= TCHAR('9'))) || (buffer[i] == TCHAR('.')))
continue;
return 1.0;
}
return _tstof(buffer);
}
}
namespace SVG
{
enum ENodeType
{
ECircle,
EClipPath,
EDefs,
EEllipse,
EG,
ELine,
ELinearGradient,
EPath,
EPolygon,
EPolyline,
ERadialGradient,
ERectangle,
EStop,
ESvg,
ETitle,
EText,
EImage,
EUse,
ESymbol,
EPattern,
EGraphicsContainer,
ENodesCount
};
enum Attribute
{
Opacity,
FillColor,
FillOpacity,
FillRule,
StrokeColor,
StrokeWidth,
StrokeOpacity,
StrokeLineCap,
StrokeLineJoin,
StrokeMiterLimit,
StrokeDashArray,
StrokeDashOffset,
FontSize,
FontFamily,
FontMetrics,
FontWeight,
FontStyleAttr,
FontTextAnchor,
FontTextAnchorStart,
FontTextAnchorMiddle,
FontTextAnchorEnd,
FontWeightNormal,
FontWeightBold,
FontStyleNormal,
FontStyleItalic,
FontStyleOblique,
FontStyleInherit,
TLinearGradient,
///
None
};
enum Metrics
{
EM,
EX,
PX,
PT,
PC,
CM,
MM,
INCH,
PCT, // percent
UNDEFINED
};
struct Point
{
public:
Point ()
{
X = 0.0;
Y = 0.0;
}
Point (double dX, double dY) : X(dX), Y(dY)
{
}
inline void operator+= (const Point& point)
{
X += point.X;
Y += point.Y;
}
inline Point operator+ (const Point& point)
{
return Point ( X + point.X, Y + point.Y );
}
inline void operator*= (const Point& point)
{
X *= point.X;
Y *= point.Y;
}
public:
double X;
double Y;
};
struct Rect
{
public:
Rect ()
{
X = 0.0;
Y = 0.0;
Width = 0.0;
Height = 0.0;
}
Rect (double dX, double dY, double dWidth, double dHeight) : X(dX), Y(dY), Width(dWidth), Height(dHeight)
{
}
inline double CenterX ()
{
return X + Width * 0.5;
}
inline double CenterY ()
{
return Y + Height * 0.5;
}
inline double GetX() const
{
return X;
}
inline double GetY() const
{
return Y;
}
inline int GetWidth() const
{
return Width;
}
inline int GetHeight() const
{
return Height;
}
public:
double X;
double Y;
double Width;
double Height;
};
struct PointPath
{
PointPath (): oPoint()
{
code = -1;
subCode = -1;
}
Point oPoint;
int code;
int subCode;
// M(m) - move to
// Z(z) - close path
// L(l) - line to
// V(v) - vertical line
// H(h) - horizontal line
// C(c) - curve to (x1 y1 x2 y2 x y)
// Q(q) - quadratic bezier (x1 y1 x y)
};
struct StopColor
{
public:
StopColor()
{
m_fOffset = 0.0;
m_nColor = -1;
m_fOpacity = 0.0;
}
inline bool FromStyle(const CString& oStyle)
{
return true;
}
inline bool FromXml(XmlUtils::CXmlNode& oXml)
{
return true;
}
public:
double m_fOffset;
unsigned long m_nColor;
double m_fOpacity;
};
}
namespace SVG
{
class StrUtils
{
public:
static inline long LongValue(const CString& value)
{
for (int i = 0; i < value.GetLength(); ++i)
{
if (isdigit(value[i]) || (value[i] == L'-') /* || (value[i] == L'.') || (value[i] == L',') */)
continue;
return _wtoi(value.Mid(0, i));
}
return _wtoi(value);
}
static inline double DoubleValue(const CString& value)
{
for (int i = 0; i < value.GetLength(); ++i)
{
if (isdigit(value[i]) || (value[i] == L'.') || (value[i] == L',') || (value[i] == L'-') || (value[i] == 'e'))
continue;
return _tstof(value.Mid(0, i));
}
return _tstof(value);
}
static inline double DoubleValuePct(const CString& sVal)
{
if (sVal.GetLength())
{
if (_T('%') == sVal[sVal.GetLength() - 1])
{
return _tstof(sVal.Mid(0, sVal.GetLength() - 1)) * 0.01;
}
}
return _tstof(sVal);
}
static inline bool DoubleValues(const CString& Source, std::vector<double>& Values)
{
CString number = _T("");
int length = Source.GetLength();
for (int i = 0; i < length; ++i)
{
if (L'-' == Source [i])
{
if (i > 1)
{
if (L'e' == Source [i - 1])
{
number.AppendChar(Source[i]);
continue;
}
}
if (number.GetLength())
Values.push_back(_tstof(number));
number = _T("");
}
if ( isdigit ( Source [ i ] ) || ( Source [ i ] == L'.' ) || ( Source [ i ] == L'-' ) || ( Source [ i ] == 'e' ) )
{
number.AppendChar(Source[i]);
continue;
}
if (number.GetLength())
Values.push_back(_tstof(number));
number = _T("");
}
if (number.GetLength ())
Values.push_back(_tstof(number));
return (0 != Values.size());
}
//static inline bool DoubleValues(const CString& Source, std::vector<double>& Values)
//{
// CString number = _T("");
// int length = Source.GetLength();
// for (int i = 0; i < length; ++i)
// {
// if (L'-' == Source [i])
// {
// if (i > 1)
// {
// if (L'e' == Source [i - 1])
// {
// number.AppendChar(Source[i]);
// continue;
// }
// }
// if (number.GetLength())
// Values.push_back(_tstof(number));
// number = _T("");
// }
// if ( isdigit (Source [ i ] ) || ( Source [ i ] == L'.' ) || ( Source [ i ] == L'-' ) || ( Source [ i ] == 'e' ) )
// {
// number.AppendChar(Source[i]);
// continue;
// }
// if (number.GetLength())
// Values.push_back(_tstof(number));
// number = _T("");
// }
// if (number.GetLength ())
// Values.push_back(_tstof(number));
// return (0 != Values.size());
//}
//
static inline CString RemoveSpaces(CString& src)
{
if (0 == src.GetLength())
return CString(_T(""));
while (0 != src.Remove(_T(' ')))
{
}
return src;
}
static inline CString RemoveSymbol(CString& src, TCHAR symbol)
{
if (0 == src.GetLength())
return CString(_T(""));
while (0 != src.Remove(symbol))
{
}
return src;
}
static inline Metrics GetMetrics(const CString& value ) // only for long numbers in value
{
for ( int i = 0; i < value.GetLength (); ++i )
{
if ( isdigit ( value [ i ] ) || ( value [ i ] == L'.' ) || ( value [ i ] == L',' ) )
continue;
CString metrics = value.Mid ( i, value.GetLength () - i );
if ( 0 == metrics.GetLength () )
return PX;
if ( metrics == CString ( _T("px") ) )
return PX;
if ( metrics == CString ( _T("mm") ) )
return MM;
if ( metrics == CString ( _T("cm") ) )
return CM;
if ( metrics == CString ( _T("%") ) )
return PCT;
if ( metrics == CString ( _T("in") ) )
return INCH;
if ( metrics == CString ( _T("em") ) ) // default - 16px
return EM;
if ( metrics == CString ( _T("pt") ) )
return PT;
return UNDEFINED;
}
return UNDEFINED;
}
static inline CString UrlRefValue(const CString& sUrlRef)
{
if (sUrlRef.GetLength() > 3)
{
CString str = sUrlRef;
StrUtils::RemoveSpaces (str);
if ((str [ 0 ] == L'u') || (str [ 1 ] == L'r') || (str [ 2 ] == L'l'))
{
int Oct = 0;
CString sTemp = str.Tokenize (_T("#"), Oct);
if (sTemp.GetLength() >0)
{
if (L')' == str[str.GetLength () - 1] )
return str.Mid (Oct, str.GetLength () - Oct - 1);
return str.Mid (Oct, str.GetLength () - Oct);
}
}
}
return _T("");
}
static inline bool UrlRefValue2(CString& sUrlRef)
{
CString sRet = StrUtils::UrlRefValue(sUrlRef);
if (sRet.GetLength ())
{
sUrlRef = sRet;
return true;
}
return false;
}
static inline CString UrlDecode(const CString& Source)
{
CString strDecoded;
for ( int i = 0; i < Source.GetLength (); ++i )
{
if ( _T ( '%' ) == Source [ i ] && isxdigit ( Source [ i + 1 ] ) && isxdigit ( Source [ i + 2 ] ) )
{
BYTE byHex1 = toupper ( Source [ i + 1 ] ) - _T ( '0' );
if ( byHex1 > 9 )
byHex1 -= ( _T ( 'A' ) - ( _T ( '9' ) + 1 ) );
BYTE byHex2 = toupper ( Source [ i + 2 ] ) - _T ( '0' );
if ( byHex2 > 9 )
byHex2 -= ( _T ( 'A' ) - ( _T ( '9' ) + 1 ) );
strDecoded.AppendChar ( byHex1 * 16 + byHex2 );
i += 2;
}
else
{
strDecoded.AppendChar ( Source [i] );
}
}
return strDecoded;
}
};
struct CubicBezier
{
public:
CubicBezier()
{
}
CubicBezier(double X1, double Y1, double CX0, double CY0, double CX1, double CY1)
{
m_Points[0].X = X1;
m_Points[0].Y = Y1;
m_Points[1].X = CX0;
m_Points[1].Y = CY0;
m_Points[2].X = CX1;
m_Points[2].Y = CY1;
}
public:
Point m_Points[3];
};
class CArcToCubicBezier
{
public:
CArcToCubicBezier(double fX, double fY, double fWidth, double fHeight, double fStartAngle, double fSweepAngle, bool bClockDirection = false)
{
AddArc ( fX, fY, fWidth, fHeight, -fStartAngle, -fSweepAngle );
}
inline const std::vector <CubicBezier>& GetCurves() const
{
return m_arrCurves;
}
private:
inline int EllipseArc(double fX, double fY, double fXRad, double fYRad, double fAngle1, double fAngle2, bool bClockDirection)
{
int nRet = 0;
while ( fAngle1 < 0 )
fAngle1 += 360;
while ( fAngle1 > 360 )
fAngle1 -= 360;
while ( fAngle2 < 0 )
fAngle2 += 360;
while ( fAngle2 >= 360 )
fAngle2 -= 360;
if ( !bClockDirection )
{
if ( fAngle1 <= fAngle2 )
nRet = EllipseArc2( fX, fY, fXRad, fYRad, fAngle1, fAngle2, false );
else
{
nRet += EllipseArc2( fX, fY, fXRad, fYRad, fAngle1, 360, false );
nRet += EllipseArc2( fX, fY, fXRad, fYRad, 0, fAngle2, false );
}
}
else
{
if ( fAngle1 >= fAngle2 )
nRet = EllipseArc2( fX, fY, fXRad, fYRad, fAngle1, fAngle2, true );
else
{
nRet += EllipseArc2( fX, fY, fXRad, fYRad, fAngle1, 0, true );
nRet += EllipseArc2( fX, fY, fXRad, fYRad, 360, fAngle2, true );
}
}
return nRet;
}
inline double AngToEllPrm(double fAngle, double fXRad, double fYRad)
{
// Ôóíêöèÿ äëÿ ïåðåâîäà ðåàëüíîãî óãëà â ïàðàìåòðè÷åñêîå çàäàíèå ýëëïèñà
// ò.å. x= a cos(t) y = b sin(t) - ïàðàìåòðè÷åñêîå çàäàíèå ýëëïèñà.
// x = r cos(p), y = r sin(p) => t = atan2( sin(p) / b, cos(p) / a );
return atan2( sin( fAngle ) / fYRad, cos( fAngle ) / fXRad );
}
inline int EllipseArc2(double fX, double fY, double fXRad, double fYRad, double fAngle1, double fAngle2, bool bClockDirection)
{
// ïåðåâåäåì óãëû â ðàäèàíû
int nRet = 0;
double dAngle1 = fAngle1 * 3.141592 / 180;
double dAngle2 = fAngle2 * 3.141592 / 180;
// Âûÿñíèì â êàêèõ ÷åòâåðòÿõ íàõîäÿòñÿ íà÷àëüíàÿ è êîíå÷íàÿ òî÷êè
unsigned int nFirstPointQuard = int(fAngle1) / 90 + 1;
unsigned int nSecondPointQuard = int(fAngle2) / 90 + 1;
nSecondPointQuard = (std::min)( (unsigned int)4, (std::max)( (unsigned int)1, nSecondPointQuard ) );
nFirstPointQuard = (std::min)( (unsigned int)4, (std::max)( (unsigned int)1, nFirstPointQuard ) );
// Ïðîâåäåì ëèíèþ â íà÷àëüíóþ òî÷êó äóãè
double fStartX = 0.0, fStartY = 0.0, fEndX = 0.0, fEndY = 0.0;
fStartX = fX + fXRad * cos( AngToEllPrm( dAngle1, fXRad, fYRad ) );
fStartY = fY + fYRad * sin( AngToEllPrm( dAngle1, fXRad, fYRad ) );
// _LineTo(fStartX, fStartY);
// Äàëüøå ðèñóåì ïî ÷åòâåðÿì
double fCurX = fStartX, fCurY = fStartY;
double dStartAngle = dAngle1;
double dEndAngle = 0;
if ( !bClockDirection )
{
for( unsigned int nIndex = nFirstPointQuard; nIndex <= nSecondPointQuard; nIndex++ )
{
if ( nIndex == nSecondPointQuard )
dEndAngle = dAngle2;
else
dEndAngle = (90 * (nIndex ) ) * 3.141592f / 180;
if ( !( nIndex == nFirstPointQuard ) )
dStartAngle = (90 * (nIndex - 1 ) ) * 3.141592f / 180;
EllipseArc3(fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), &fEndX, &fEndY, false);
}
}
else
{
for( unsigned int nIndex = nFirstPointQuard; nIndex >= nSecondPointQuard; nIndex-- )
{
if ( nIndex == nFirstPointQuard )
dStartAngle = dAngle1;
else
dStartAngle = (90 * (nIndex ) ) * 3.141592f / 180;
if ( !( nIndex == nSecondPointQuard ) )
dEndAngle = (90 * (nIndex - 1 ) ) * 3.141592f / 180;
else
dEndAngle = dAngle2;
EllipseArc3(fX, fY, fXRad, fYRad, AngToEllPrm( dStartAngle, fXRad, fYRad ), AngToEllPrm( dEndAngle, fXRad, fYRad ), &fEndX, &fEndY, false);
}
}
return nRet;
}
inline int EllipseArc3(double fX, double fY, double fXRad, double fYRad, double dAngle1, double dAngle2, double *pfXCur, double *pfYCur, bool bClockDirection = false)
{
// Ðàññ÷èòàåì íà÷àëüíóþ, êîíå÷íóþ è êîíòðîëüíûå òî÷êè
double fX1 = 0.0, fX2 = 0.0, fY1 = 0.0, fY2 = 0.0;
double fCX1 = 0.0, fCX2 = 0.0, fCY1 = 0.0, fCY2 = 0.0;
double fAlpha = sin( dAngle2 - dAngle1 ) * ( sqrt( 4.0 + 3.0 * tan( (dAngle2 - dAngle1) / 2.0 ) * tan( (dAngle2 - dAngle1) / 2.0 ) ) - 1.0 ) / 3.0;
double fKoef = 1;
fX1 = fX + fXRad * cos( dAngle1 );
fY1 = fY + fYRad * sin( dAngle1 );
fX2 = fX + fXRad * cos( dAngle2 );
fY2 = fY + fYRad * sin( dAngle2 );
fCX1 = fX1 - fAlpha * fXRad * sin ( dAngle1 );
fCY1 = fY1 + fAlpha * fYRad * cos ( dAngle1 );
fCX2 = fX2 + fAlpha * fXRad * sin ( dAngle2 );
fCY2 = fY2 - fAlpha * fYRad * cos ( dAngle2 );
if ( !bClockDirection )
{
CubicBezier oBezier ( fCX1, fCY1, fCX2, fCY2, fX2, fY2 );
m_arrCurves.push_back ( oBezier );
*pfXCur = fX2;
*pfYCur = fY2;
}
else
{
CubicBezier oBezier ( fCX1, fCY1, fCX2, fCY2, fX2, fY2 );
m_arrCurves.push_back ( oBezier );
*pfXCur = fX1;
*pfYCur = fY1;
}
return 0;
}
inline bool AddArc(double fX, double fY, double fWidth, double fHeight, double fStartAngle, double fSweepAngle)
{
if (0.0 >= fWidth || 0.0 >= fHeight)
return false;
bool bClockDirection = false;
double fEndAngle = 360 - ( fSweepAngle + fStartAngle );
double fSrtAngle = 360 - fStartAngle;
if( fSweepAngle > 0 )
bClockDirection = true;
return (0 == EllipseArc(fX + fWidth / 2, fY + fHeight / 2, fWidth / 2, fHeight / 2, fSrtAngle, fEndAngle, bClockDirection)) ? true : false;
}
private:
std::vector <CubicBezier> m_arrCurves;
};
}
namespace SVG
{
struct IRefStorage;
struct IRef
{
virtual ~IRef ()
{
}
virtual bool RefreshXLinkSource(IRefStorage* pStorage) = 0;
virtual bool Normalize(const double& dAfX, const double& dAfY) = 0;
};
struct ISvgRef: public IRef
{
virtual ~ISvgRef ()
{
}
// base
inline const ENodeType nodeType() const
{
return m_nodeType;
}
inline const CString& nodeId() const
{
return m_nodeId;
}
// clip-path
inline const CString& GetUrlClip() const
{
return m_urlClipPath;
}
inline void AttachClip(ISvgRef* pClip)
{
if (m_pClip)
return;
m_pClip = pClip;
}
inline ISvgRef* GetClip()
{
return m_pClip;
}
public:
// base
ENodeType m_nodeType;
CString m_nodeId;
// clip-path
CString m_urlClipPath; // id -> url(#AABB)
ISvgRef* m_pClip;
};
struct IRefStorage : public IRef
{
virtual ~IRefStorage ()
{
}
virtual bool HashRef(ISvgRef* pRef, bool bDef) = 0;
virtual bool GetRef(const CString& ID, ISvgRef*& pRef) = 0;
virtual ISvgRef* Get(long index) = 0;
virtual long GetSize() = 0;
virtual bool Push(ISvgRef* pRef) = 0;
};
}
namespace SVG
{
class ColorTable
{
public:
ColorTable ()
{
InitClrTable ();
}
inline long Find(const CString& sKey)
{
std::map<CString, unsigned long>::iterator pPair = m_Table.find(sKey);
if (pPair != m_Table.end())
{
long clr = pPair->second;
return ((clr & 0xFF) << 16) | ((clr & 0xFF00)) | ((clr & 0xFF0000) >> 16);
}
return -1;
}
private:
bool InitClrTable();
private:
std::map <CString, unsigned long> m_Table;
};
class ColorParser
{
public:
static long ColorFromString(const CString& sColor);
static long ColorFromRgbString(const CString& Rgb);
static long ColorFromHexString(const CString& Hex);
private:
static ColorTable m_oTable;
};
class GradientColor
{
public:
GradientColor()
{
}
inline bool Add(XmlUtils::CXmlNode& oXml)
{
StopColor color;
color.m_nColor = ColorParser::ColorFromString(oXml.GetAttributeOrValue(_T("stop-color"), _T("#000000")));
color.m_fOffset = StrUtils::DoubleValuePct(oXml.GetAttributeOrValue(_T("offset"),_T("0.0")));
color.m_fOpacity = StrUtils::DoubleValuePct(oXml.GetAttributeOrValue(_T("stop-opacity"),_T("1.0")));
CString Styles = oXml.GetAttributeOrValue(_T("style"), _T(""));
if (Styles.GetLength())
{
int sTok = 0;
while (-1 != sTok)
{
CString sSrc = Styles.Tokenize ( _T(";"), sTok);
if (-1 != sTok)
{
int index = 0;
CString strTemp = sSrc.Tokenize(_T(":"), index);
CString sAttr = StrUtils::RemoveSpaces(strTemp);
if (-1 == index)
continue;
strTemp = sSrc.Mid(index, sSrc.GetLength() - index);
CString sVal = StrUtils::RemoveSpaces(strTemp);
if (_T("stop-color") == sAttr)
{
color.m_nColor = ColorParser::ColorFromString(sVal); continue;
}
else if (_T("offset") == sAttr)
{
color.m_fOffset = StrUtils::DoubleValuePct(sVal); continue;
}
else if (_T("stop-opacity") == sAttr)
{
color.m_fOpacity = StrUtils::DoubleValuePct(sVal); continue;
}
}
}
}
m_colors.push_back(color);
return true;
}
inline bool Add(const StopColor& color)
{
m_colors.push_back(color);
return true;
}
//
inline const StopColor& Get(int index) const
{
return m_colors[index];
}
inline long Count() const
{
return (long)m_colors.size();
}
private:
std::vector <StopColor> m_colors;
};
}
namespace SVG
{
class ViewBox
{
public:
ViewBox ()
{
m_nWidth = 0;
m_nHeight = 0;
m_nX = 0;
m_nY = 0;
m_bInUse = false;
}
bool FromXml (XmlUtils::CXmlNode& oXmlNode)
{
return FromString(oXmlNode.GetAttribute(_T("viewBox")));
}
bool FromString (const CString& Str)
{
std::vector<double> Values;
if (StrUtils::DoubleValues(Str, Values))
{
if (4 == Values.size())
{
m_nX = static_cast<int>(Values[0]);
m_nY = static_cast<int>(Values[1]);
m_nWidth = static_cast<int>(Values[2]);
m_nHeight = static_cast<int>(Values[3]);
m_bInUse = true;
return true;
}
}
return false;
}
inline int GetX() const
{
return m_nX;
}
inline int GetY() const
{
return m_nY;
}
inline int GetWidth() const
{
return m_nWidth;
}
inline int GetHeight() const
{
return m_nHeight;
}
public:
int m_nWidth;
int m_nHeight;
int m_nX;
int m_nY;
bool m_bInUse;
};
class UnitSystem
{
public:
UnitSystem ()
{
m_bIsValid = false;
m_nFontSize = 0.0;
m_dOffSetX = 0.0;
m_dOffSetY = 0.0;
}
inline void SetViewBox(int SvgWidth, int SvgHeight, const ViewBox& oBox, Metrics oMetrics)
{
m_bIsValid = true;
m_nSvgWidth = SvgWidth;
m_nSvgHeight = SvgHeight;
m_oViewBox = oBox;
if (oBox.m_bInUse)
{
if ( 0 != (int)oBox.m_nWidth && 0 != (int)oBox.m_nHeight )
{
m_dFactorX = (double) (m_nSvgWidth) / abs ( (double) (oBox.m_nWidth) );
m_dFactorY = m_dFactorX;//(double) (m_nSvgHeight) / (double) (oBox.m_nHeight);
m_dOffSetX = -oBox.m_nX;// * m_dFactorX;
m_dOffSetY = -oBox.m_nY;// * m_dFactorY;
m_dFactorQ = ( sqrt ( (double) ( m_nSvgWidth * m_nSvgWidth + m_nSvgHeight * m_nSvgHeight ) ) ) /
( sqrt ( (double) ( oBox.m_nWidth * oBox.m_nWidth + oBox.m_nHeight * oBox.m_nHeight ) ) );
return;
}
}
if ( MM == oMetrics )
{
//m_dFactorX = 3.543307;
//m_dFactorY = 3.543307;
//m_dFactorQ = 3.543307;
//return;
}
m_dFactorX = 1.0;
m_dFactorY = 1.0;
m_dFactorQ = 1.0;
}
inline void SetFontSizeForEM(double Size)
{
m_nFontSize = Size;
}
inline double GetFactorFontSize()
{
return m_dFactorQ;
}
template <typename T>
inline T Convert(T value, Metrics m, int direction) // '1' - x ; '-1' - y
{
if (!m_bIsValid)
return value;
if (m == UNDEFINED) // in VB CO
{
if (1 == direction) value *= m_dFactorX;
else if (-1 == direction) value *= m_dFactorY;
}
else if (m == INCH)
{
if (1 == direction) value *= 90 * m_dFactorX;
else if (-1 == direction) value *= 90 * m_dFactorY;
}
else if (m == PCT)
{
if (1 == direction) value = m_nSvgWidth * 0.01 * value;
else if (-1 == direction) value = m_nSvgHeight * 0.01 * value;
}
else if (m == EM)
{
if (1 == direction) value *= m_nFontSize * m_dFactorX;
else if (-1 == direction) value *= m_nFontSize * m_dFactorY;
}
else if (m == CM)
{
if (1 == direction) value *= 90 * m_dFactorX / 2.54;
else if (-1 == direction) value *= 90 * m_dFactorY / 2.54;
}
else if (m == MM)
{
if (1 == direction) value *= 90 * m_dFactorX / 25.4;
else if (-1 == direction) value *= 90 * m_dFactorY / 25.4;
}
return value;
}
inline double GetPX(double value, Metrics m)
{
/*
"1pt" equals "1.25px" (and therefore 1.25 user units)
"1pc" equals "15px" (and therefore 15 user units)
"1mm" would be "3.543307px" (3.543307 user units)
"1cm" equals "35.43307px" (and therefore 35.43307 user units)
"1in" equals "90px" (and therefore 90 user units)
*/
if (m == PC) return value * 15.0;
else if (m == PT) return value * 1.25;
else if (m == MM) return value * 3.543307;
else if (m == CM) return value * 35.43307;
else if (m == INCH) return value * 90.0;
return value;
}
inline double StrokeWidth(double value, Metrics m)
{
if (m == UNDEFINED) value *= m_dFactorQ;
else if (m == INCH) value *= 90 * m_dFactorQ;
else if (m == EM) value *= m_nFontSize * m_dFactorQ;
else if (m == PCT) value = sqrt ((double)(m_nSvgWidth * m_nSvgWidth + m_nSvgHeight * m_nSvgHeight)) / sqrt (2.0) * 0.01 * value;
else if (m == CM) value *= 90 * m_dFactorQ / 2.54;
else if (m == MM) value *= 90 * m_dFactorQ / 25.4;
return value;
}
//
inline const double& OffSetX () const
{
return m_dOffSetX;
}
inline const double& OffSetY () const
{
return m_dOffSetY;
}
inline const int& GetWidth () const
{
return m_nSvgWidth;
}
inline const int& GetHeight () const
{
return m_nSvgHeight;
}
private:
bool m_bIsValid;
int m_nSvgWidth;
int m_nSvgHeight;
ViewBox m_oViewBox;
double m_dFactorX;
double m_dFactorY;
double m_dFactorQ;
double m_nFontSize;
double m_dOffSetX;
double m_dOffSetY;
};
class Style // map äîáàâèì ïî ìåðå íàäîáíîñòè
{
public:
Style()
{
SetDefault ();
}
inline void SetDefault ()
{
m_nOpacity = 1.0;
m_nFillColor = 0;//-1;
m_nFillOpacity = 1.0;
m_nStrokeColor = -1;
m_nStrokeWidth = 1.0;
m_nStrokeOpacity = 1.0;
m_nStrokeLineCap = -1;
m_nStrokeLineJoin = c_ag_LineJoinMiter;
m_pRefFill = NULL;
m_pRefStroke = NULL;
m_bHaveOpacity = false;
m_bHaveFillColor = false;
m_bHaveFillOpacity = false;
m_bHaveStrokeColor = false;
m_bHaveStrokeWidth = false;
m_bHaveStrokeOpacity = false;
m_bHaveStrokeLineCap = false;
m_bHaveStrokeLineJoin = false;
m_IsCSS = false;
}
inline void ClearOpacity ()
{
m_nOpacity = 1.0;
}
//
inline bool SetStyle (const CString& Styles, bool Clear, UnitSystem& oUnitSystem, IRefStorage* pStorage, const ColorTable& Table = ColorTable()) // from string
{
if ( Clear )
{
SetDefault ();
}
int To = 0;
while ( -1 != To )
{
CString Source = Styles.Tokenize ( _T(";"), To );
if (-1 != To)
{
int Ind = 0;
CString strT = Source.Tokenize ( _T(":"), Ind);
CString attr = StrUtils::RemoveSpaces(strT);
if ( -1 == Ind)
continue;
CString strTemp = Source.Mid(Ind, Source.GetLength() - Ind);
CString Value = StrUtils::RemoveSpaces(strTemp);
if (_T("opacity") == attr)
{
m_nOpacity = DoubleFromString(Value);
m_bHaveOpacity = true;
}
else if ( _T("fill") == attr)
{
m_fillUrlRef = StrUtils::UrlRefValue(Value);
if (m_fillUrlRef.GetLength())
{
if (pStorage)
{
ISvgRef* pDef = NULL;
if (pStorage->GetRef(m_fillUrlRef, pDef))
{
m_pRefFill = pDef;
continue;
}
}
}
m_nFillColor = ColorParser::ColorFromString(Value);
m_bHaveFillColor = true;
}
else if ( _T("fill-opacity") == attr)
{
m_nFillOpacity = DoubleFromString(Value);
m_bHaveFillOpacity = true;
}
else if ( _T("stroke") == attr)
{
CString sUrlRef = StrUtils::UrlRefValue(Value);
if (sUrlRef.GetLength())
{
if (pStorage)
{
ISvgRef* pDef = NULL;
if (pStorage->GetRef(sUrlRef, pDef))
{
m_pRefStroke = pDef;
continue;
}
}
}
m_nStrokeColor = ColorParser::ColorFromString ( Value );
m_bHaveStrokeColor = true;
}
else if ( _T("stroke-width") == attr)
{
m_nStrokeWidth = DoubleValue (Value, oUnitSystem);
m_bHaveStrokeWidth = true;
}
else if ( _T("stroke-opacity") == attr)
{
m_nStrokeOpacity = DoubleFromString(Value);
m_bHaveStrokeOpacity = true;
}
else if ( _T("stroke-linecap") == attr)
{
m_nStrokeLineCap = c_ag_LineCapFlat;
if ( CString ( _T("round") ) == Value )
{
m_nStrokeLineCap = c_ag_LineCapRoundAnchor;
}
if ( CString ( _T("square") ) == Value )
{
m_nStrokeLineCap = c_ag_LineCapSquareAnchor;
}
m_bHaveStrokeLineCap = true;
}
else if ( _T("stroke-linejoin") == attr)
{
m_nStrokeLineJoin = c_ag_LineJoinMiter;
if ( CString ( _T("round") ) == Value )
{
m_nStrokeLineJoin = c_ag_LineJoinRound;
}
if ( CString ( _T("bevel") ) == Value )
{
m_nStrokeLineJoin = c_ag_LineJoinBevel;
}
m_bHaveStrokeLineJoin = true;
}
}
}
return true;
}
inline bool SetStyle (XmlUtils::CXmlNode& oXmlNode, bool bResetStyle, UnitSystem& oUnitSystem, IRefStorage* pStorage, const ColorTable& Table = ColorTable())
{
if (bResetStyle)
SetDefault ();
CString FillColor = oXmlNode.GetAttributeOrValue ( _T("fill") );
CString sUrlRef = StrUtils::UrlRefValue(FillColor);
if (sUrlRef.GetLength ())
{
ISvgRef* pDef = NULL;
if (pStorage->GetRef(sUrlRef, pDef))
{
m_pRefFill = pDef;
}
}
else
{
m_nFillColor = ColorParser::ColorFromString ( oXmlNode.GetAttributeOrValue ( _T("fill"), _T("#000000") ) );
}
CString strOpacity = oXmlNode.GetAttributeOrValue ( _T("opacity"), _T("") );
if (strOpacity.GetLength())
{
m_nOpacity = DoubleFromString (strOpacity);
m_bHaveOpacity = true;
}
CString strFillOpacity = oXmlNode.GetAttributeOrValue(_T("fill-opacity"),_T("1.0"));
if (strOpacity.GetLength())
{
m_nFillOpacity = DoubleFromString (strFillOpacity);
m_bHaveFillOpacity = true;
}
// stroke settings
CString StrokeColor = oXmlNode.GetAttributeOrValue ( _T("stroke") );
CString DefSID = StrUtils::UrlRefValue(StrokeColor);
if ( DefSID.GetLength () > 1 )
{
ISvgRef* pDef = NULL;
if ( pStorage->GetRef ( DefSID, pDef ) )
{
m_pRefStroke = pDef;
}
}
else
{
m_nStrokeColor = ColorParser::ColorFromString ( oXmlNode.GetAttributeOrValue ( _T("stroke"), _T("#000000") ) );
}
CString strTemp = oXmlNode.GetAttributeOrValue ( _T("stroke-opacity"), _T("1.0") ) ;
m_nStrokeOpacity = DoubleFromString ( strTemp );
m_nStrokeWidth = DoubleValue ( oXmlNode, _T("stroke-width"), oUnitSystem ); // StrUtils::DoubleValue ( oXmlNode.GetAttributeOrValue ( _T("stroke-width"), _T("1.0") ) );
CString LineCap = oXmlNode.GetAttributeOrValue ( _T("stroke-linecap"), _T("") );
if ( LineCap.GetLength() )
{
m_nStrokeLineCap = c_ag_LineCapFlat;
if ( CString ( _T("round") ) == LineCap )
{
m_nStrokeLineCap = c_ag_LineCapRoundAnchor;
}
if ( CString ( _T("square") ) == LineCap )
{
m_nStrokeLineCap = c_ag_LineCapSquare;
}
}
CString LineJoin = oXmlNode.GetAttributeOrValue ( _T("stroke-linejoin"), _T("miter") );
if ( LineJoin.GetLength() )
{
m_nStrokeLineJoin = c_ag_LineJoinMiter;
if ( CString ( _T("round") ) == LineJoin )
{
m_nStrokeLineJoin = c_ag_LineJoinRound;
}
if ( CString ( _T("bevel") ) == LineJoin )
{
m_nStrokeLineJoin = c_ag_LineJoinBevel;
}
}
return true;
}
inline bool UpdateStyle (XmlUtils::CXmlNode& oXmlNode, UnitSystem& oUnitSystem, IRefStorage* pStorage, const ColorTable& Table = ColorTable())
{
// FILL
CString strFillColor = oXmlNode.GetAttributeOrValue ( _T("fill") );
if (strFillColor.GetLength())
{
CString sUrlRef = StrUtils::UrlRefValue(strFillColor);
if (sUrlRef.GetLength())
{
ISvgRef* pDef = NULL;
if (pStorage->GetRef(sUrlRef, pDef))
m_pRefFill = pDef;
}
else
{
m_nFillColor = ColorParser::ColorFromString(oXmlNode.GetAttributeOrValue(_T("fill"),_T("#000000")));
m_bHaveFillColor = true;
}
}
CString strOpacity = oXmlNode.GetAttributeOrValue(_T("opacity"),_T(""));
if (strOpacity.GetLength())
{
m_nOpacity = DoubleFromString (strOpacity);
m_bHaveOpacity = true;
}
CString strFillOpacity = oXmlNode.GetAttributeOrValue(_T("fill-opacity"),_T("1.0"));
if (strOpacity.GetLength())
{
m_nFillOpacity = DoubleFromString (strFillOpacity);
m_bHaveFillOpacity = true;
}
// STROKE
CString StrokeColor = oXmlNode.GetAttributeOrValue ( _T("stroke") );
if ( StrokeColor.GetLength () > 1 )
{
CString sUrlRef = StrUtils::UrlRefValue(StrokeColor);
if (sUrlRef.GetLength())
{
ISvgRef* pDef = NULL;
if (pStorage->GetRef(sUrlRef, pDef))
{
m_pRefStroke = pDef;
}
}
else
{
m_nStrokeColor = ColorParser::ColorFromString ( oXmlNode.GetAttributeOrValue ( _T("stroke"), _T("#000000") ) );
m_bHaveStrokeColor = true;
}
}
if (oXmlNode.GetAttributeOrValue(_T("stroke-opacity")).GetLength())
{
CString strTemp = oXmlNode.GetAttributeOrValue ( _T("stroke-opacity"), _T("1.0") );
m_nStrokeOpacity = DoubleFromString ( strTemp );
m_bHaveStrokeOpacity = true;
}
if (oXmlNode.GetAttributeOrValue(_T("stroke-width")).GetLength())
{
m_nStrokeWidth = DoubleValue ( oXmlNode, _T("stroke-width"), oUnitSystem ); // StrUtils::DoubleValue ( oXmlNode.GetAttributeOrValue ( _T("stroke-width"), _T("1.0") ) );
m_bHaveStrokeWidth = true;
}
CString LineCap = oXmlNode.GetAttributeOrValue ( _T("stroke-linecap"), _T("") );
if ( LineCap.GetLength() )
{
if ( CString ( _T("round") ) == LineCap )
{
m_nStrokeLineCap = c_ag_LineCapRoundAnchor;
m_bHaveStrokeLineCap = true;
}
if ( CString ( _T("square") ) == LineCap )
{
m_nStrokeLineCap = c_ag_LineCapSquare;
m_bHaveStrokeLineCap = true;
}
}
CString strLineJoin = oXmlNode.GetAttributeOrValue ( _T("stroke-linejoin"), _T("miter") );
if (strLineJoin.GetLength())
{
m_nStrokeLineJoin = c_ag_LineJoinMiter;
if ( CString ( _T("round") ) == strLineJoin )
{
m_nStrokeLineJoin = c_ag_LineJoinRound;
m_bHaveStrokeLineJoin = true;
}
if ( CString ( _T("bevel") ) == strLineJoin )
{
m_nStrokeLineJoin = c_ag_LineJoinBevel;
m_bHaveStrokeLineJoin = true;
}
}
return true;
}
// EX
inline Style (const CString& Styles, bool Clear, UnitSystem& oUnitSystem, IRefStorage* pStorage, const ColorTable& Table = ColorTable())
{
SetStyle (Styles, Clear, oUnitSystem, pStorage, Table);
}
inline bool UpdateStyle (const CString& Styles, UnitSystem& oUnitSystem, IRefStorage* pStorage, const ColorTable& Table = ColorTable())
{
return SetStyle (Styles, false, oUnitSystem, pStorage, Table);
}
inline void Combine(const Style& oSrc)
{
// opacity
if(oSrc.ValidAttribute(Opacity))
{
m_nOpacity *= oSrc.m_nOpacity;
}
}
//
inline long LongAttribute (SVG::Attribute style) const
{
GET_ATTRIBUTEN(FillColor);
GET_ATTRIBUTEN(StrokeColor);
GET_ATTRIBUTEN(StrokeLineCap);
GET_ATTRIBUTEN(StrokeLineJoin);
return 0;
}
inline double DoubleAttribute (SVG::Attribute style) const
{
GET_ATTRIBUTED(Opacity);
GET_ATTRIBUTED(FillOpacity);
GET_ATTRIBUTED(StrokeWidth);
GET_ATTRIBUTED(StrokeOpacity);
return 0.0;
}
inline void ClearFillColor()
{
m_nFillColor = -3;
}
//
inline bool ValidAttribute (Attribute nStyle) const
{
VALIDATE_ATTRIBUTE (Opacity);
VALIDATE_ATTRIBUTE (FillColor);
VALIDATE_ATTRIBUTE (FillOpacity);
VALIDATE_ATTRIBUTE (StrokeColor);
VALIDATE_ATTRIBUTE (StrokeWidth);
VALIDATE_ATTRIBUTE (StrokeOpacity);
VALIDATE_ATTRIBUTE (StrokeLineCap);
VALIDATE_ATTRIBUTE (StrokeLineJoin);
return false;
}
inline static void UpdateValidateAttributes (const Style& oSrc, Style& oTo)
{
if (oSrc.ValidAttribute(Opacity) && (false == oTo.ValidAttribute(Opacity)))
oTo.m_nOpacity = oSrc.m_nOpacity;
else if(oSrc.ValidAttribute(Opacity) && oTo.ValidAttribute(Opacity))
oTo.m_nOpacity *= oSrc.m_nOpacity;
if (oSrc.ValidAttribute(FillColor))
oTo.m_nFillColor = oSrc.m_nFillColor;
if (oSrc.ValidAttribute(FillOpacity))
oTo.m_nFillOpacity = oSrc.m_nFillOpacity;
if (oSrc.ValidAttribute(StrokeColor))
oTo.m_nStrokeColor = oSrc.m_nStrokeColor;
if (oSrc.ValidAttribute(StrokeWidth))
oTo.m_nStrokeWidth = oSrc.m_nStrokeWidth;
if (oSrc.ValidAttribute(StrokeOpacity))
oTo.m_nStrokeOpacity = oSrc.m_nStrokeOpacity;
if (oSrc.ValidAttribute(StrokeLineCap))
oTo.m_nStrokeLineCap = oSrc.m_nStrokeLineCap;
if (oSrc.ValidAttribute(StrokeOpacity))
oTo.m_nStrokeLineJoin = oSrc.m_nStrokeLineJoin;
}
//
inline ISvgRef* GetFill() const
{
return m_pRefFill;
}
inline ISvgRef* GetStroke() const
{
return m_pRefStroke;
}
inline const CString& GetFillUrlRef() const
{
return m_fillUrlRef;
}
inline void SetCSS(bool isCSS)
{
m_IsCSS = isCSS;
}
inline bool IsCSS() const
{
return m_IsCSS;
}
private:
inline static double DoubleValue (CString& sVal, UnitSystem& us)
{
if (0 == sVal.GetLength())
return 0.0;
double number = StrUtils::DoubleValue(sVal);
SVG::Metrics ms = StrUtils::GetMetrics(sVal);
return us.StrokeWidth (number, ms);
}
inline static double DoubleValue (XmlUtils::CXmlNode& oXmlNode, CString strAttr, UnitSystem& oUnitSystem)
{
CString strTemp = oXmlNode.GetAttribute (strAttr);
return DoubleValue ( strTemp, oUnitSystem);
}
private:
bool m_bHaveOpacity;
bool m_bHaveFillColor;
bool m_bHaveFillOpacity;
bool m_bHaveStrokeColor;
bool m_bHaveStrokeWidth;
bool m_bHaveStrokeOpacity;
bool m_bHaveStrokeLineCap;
bool m_bHaveStrokeLineJoin;
double m_nOpacity;
long m_nFillColor;
double m_nFillOpacity;
// stroke
long m_nStrokeColor;
double m_nStrokeWidth;
double m_nStrokeOpacity;
long m_nStrokeLineCap;
long m_nStrokeLineJoin;
ISvgRef* m_pRefFill;
ISvgRef* m_pRefStroke;
CString m_fillUrlRef;
bool m_IsCSS;
};
class StyleStack
{
public:
StyleStack()
{
}
inline bool Push(const Style& oStyle, bool combine = true)
{
if ((0 == m_styles.size()) || (false == combine))
{
m_styles.push_back (oStyle);
return true;
}
if (combine)
{
Style oStyleTo = oStyle;
oStyleTo.Combine(GetTop());
m_styles.push_back(oStyleTo);
return true;
}
m_styles.push_back (oStyle);
return true;
}
inline bool Pop()
{
if (m_styles.size())
{
m_styles.pop_back();
return true;
}
return false;
}
inline Style GetTop()
{
Style oStyle;
if (m_styles.size())
oStyle = m_styles[m_styles.size() - 1];
return oStyle;
}
private:
std::vector <Style> m_styles;
};
class FontStyle
{
public:
FontStyle ()
{
SetDefault ();
}
bool SetStyle(const CString& src)
{
/*
<text id="svg_7" text-decoration="underline"
font-style="italic"
fill="#cc0000"
dominant-baseline="text-before-edge"
space="preserve"
text-anchor="start"
font-weight="normal"
font-family="Arial"
font-size="40pt"
y="100"
x="100">Simple Text</text>
*/
return true;
}
bool SetStyle(XmlUtils::CXmlNode& oXml)
{
m_nFontSize = StrUtils::DoubleValue(oXml.GetAttribute(_T("font-size")));
m_nFontMetrics = StrUtils::GetMetrics(oXml.GetAttribute(_T("font-size")));
m_FontFamily = oXml.GetAttributeOrValue(_T("font-family"), _T("Arial"));
m_nFontTextAnchor = FontTextAnchorStart;
CString anchor = oXml.GetAttributeOrValue(_T("text-anchor"), _T("start"));
if (CString(_T("middle")) == anchor)
m_nFontTextAnchor = FontTextAnchorMiddle;
if (CString(_T("end")) == anchor)
m_nFontTextAnchor = FontTextAnchorEnd;
m_nFontWeight = FontWeightNormal;
CString FontWeight = oXml.GetAttributeOrValue(_T("font-weight"), _T(""));
if (CString(_T("bold")) == FontWeight )
m_nFontWeight = FontWeightBold;
m_nFontStyleAttr = FontStyleNormal;
CString StyleAttr = oXml.GetAttributeOrValue(_T("font-style"), _T(""));
if (CString(_T("italic")) == StyleAttr)
m_nFontStyleAttr = FontStyleItalic;
if (CString(_T("oblique")) == StyleAttr)
m_nFontStyleAttr = FontStyleItalic; // FontStyleOblique;
//if ( CString ( _T("inherit") ) == FontWeight )
// m_nFontStyleAttr = FontStyleInherit;
return true;
}
bool SetStyle(const CString& Styles, bool Clear)
{
if ( Clear )
{
SetDefault ();
}
int To = 0;
while ( -1 != To )
{
CString Source = Styles.Tokenize ( _T(";"), To );
if ( -1 != To )
{
int Ind = 0;
CString strTemp = Source.Tokenize ( _T(":"), Ind ) ;
CString Attribute = StrUtils::RemoveSpaces ( strTemp );
if ( -1 == Ind )
continue;
strTemp = Source.Mid ( Ind, Source.GetLength () - Ind ) ;
CString Value = StrUtils::RemoveSpaces ( strTemp );
if ( _T("font-size") == Attribute )
{
m_nFontSize = StrUtils::DoubleValue ( Value );
m_nFontMetrics = StrUtils::GetMetrics ( Value );
continue;
}
if ( _T("font-family") == Attribute )
{
m_FontFamily = Value;
continue;
}
if ( _T("text-anchor") == Attribute )
{
m_nFontTextAnchor = FontTextAnchorStart;
if ( CString ( _T("middle") ) == Value )
m_nFontTextAnchor = FontTextAnchorMiddle;
if ( CString ( _T("end") ) == Value )
m_nFontTextAnchor = FontTextAnchorEnd;
continue;
}
if ( _T("font-weight") == Attribute )
{
m_nFontWeight = FontWeightNormal;
if ( CString ( _T("bold") ) == Value )
m_nFontWeight = FontWeightBold;
}
if ( _T("font-style") == Attribute )
{
m_nFontStyleAttr = FontStyleNormal;
if ( CString ( _T("italic") ) == Value )
m_nFontStyleAttr = FontStyleItalic;
if ( CString ( _T("oblique") ) == Value )
m_nFontStyleAttr = FontStyleItalic; // FontStyleOblique;
//if ( CString ( _T("inherit") ) == FontWeight )
// m_nFontWeight = FontStyleInherit;
}
}
}
return true;
}
bool UpdateStyle(XmlUtils::CXmlNode& oXmlNode)
{
if ( oXmlNode.GetAttribute ( _T("font-size") ).GetLength () )
m_nFontSize = StrUtils::DoubleValue ( oXmlNode.GetAttribute ( _T("font-size") ) );
if ( oXmlNode.GetAttribute ( _T("font-size") ).GetLength () )
m_nFontMetrics = StrUtils::GetMetrics ( oXmlNode.GetAttribute ( _T("font-size") ) );
if ( oXmlNode.GetAttributeOrValue ( _T("font-family"), _T("Arial") ).GetLength () )
m_FontFamily = oXmlNode.GetAttributeOrValue ( _T("font-family"), _T("Arial") );
if ( oXmlNode.GetAttributeOrValue ( _T("text-anchor"), _T("") ).GetLength () )
{
m_nFontTextAnchor = FontTextAnchorStart;
CString anchor = oXmlNode.GetAttributeOrValue ( _T("text-anchor"), _T("start") );
if ( CString ( _T("middle") ) == anchor )
m_nFontTextAnchor = FontTextAnchorMiddle;
if ( CString ( _T("end") ) == anchor )
m_nFontTextAnchor = FontTextAnchorEnd;
}
if ( oXmlNode.GetAttributeOrValue ( _T("font-weight"), _T("") ).GetLength () )
{
m_nFontWeight = FontWeightNormal;
CString FontWeight = oXmlNode.GetAttributeOrValue ( _T("font-weight"), _T("") );
if ( CString ( _T("bold") ) == FontWeight )
m_nFontWeight = FontWeightBold;
}
if ( oXmlNode.GetAttributeOrValue ( _T("font-style"), _T("") ).GetLength () )
{
m_nFontStyleAttr = FontStyleNormal;
CString StyleAttr = oXmlNode.GetAttributeOrValue ( _T("font-style"), _T("") );
if ( CString ( _T("italic") ) == StyleAttr )
m_nFontStyleAttr = FontStyleItalic;
if ( CString ( _T("oblique") ) == StyleAttr )
m_nFontStyleAttr = FontStyleItalic; // FontStyleOblique;
//if ( CString ( _T("inherit") ) == FontWeight )
// m_nFontStyleAttr = FontStyleInherit;
}
return true;
}
inline double DoubleAttribute(SVG::Attribute style) const
{
GET_ATTRIBUTED(FontSize);
return 0.0;
}
inline long LongAttribute(SVG::Attribute style) const
{
GET_ATTRIBUTEN(FontMetrics);
GET_ATTRIBUTEN(FontTextAnchor);
GET_ATTRIBUTEN(FontWeight);
GET_ATTRIBUTEN(FontStyleAttr);
return 0;
}
inline CString GetAttribute(SVG::Attribute style) const
{
GET_ATTRIBUTE(FontFamily);
return _T("");
}
inline void SetDefault ()
{
m_FontFamily = _T("");
m_nFontTextAnchor = FontTextAnchorStart;
m_nFontSize = 0.0;
m_nFontWeight = FontWeightNormal;
m_nFontStyleAttr = FontStyleNormal;
}
private:
CString m_FontFamily;
int m_nFontTextAnchor;
int m_nFontWeight;
int m_nFontStyleAttr;
CString m_Preserve;
CString m_DominantBaseline;
CString m_TextDecoration;
double m_nFontSize;
Metrics m_nFontMetrics;
};
class CStyleCSS
{
public:
CStyleCSS() : m_IsValid(false)
{
}
inline bool Read (XmlUtils::CXmlNode& oXml, UnitSystem& us, IRefStorage* model, const ColorTable& colors = ColorTable())
{
// TODO: óíèâåðñàëüíûé ñåëåêòîð * {margin:0; padding:0;}
// TODO: ñåëåêòîðàìè ýëåìåíòîâ p {font-family: Garamond, serif;}
// TODO: ñåëåêòîðàìè êëàññîâ .note {color: red; background: yellow; font-weight: bold;}
// TODO: ñåëåêòîðàìè èäåíòèôèêàòîðîâ #paragraph1 {margin: 0;}
// TODO: ñåëåêòîðàìè àòðèáóòîâ a[href="http://www.somesite.com"]{font-weight:bold;}
// TODO: ñåëåêòîðàìè ïîòîìêîâ (êîíòåêñòíûìè ñåëåêòîðàìè) div#paragraph1 p.note {color: red;}
// TODO: ñåëåêòîðàìè äî÷åðíèõ ýëåìåíòîâ p.note > b {color: green;}
// TODO: ñåëåêòîðàìè ñåñòðèíñêèõ ýëåìåíòîâ h1 + p {font-size: 24pt;}
// TODO: ñåëåêòîðàìè ïñåâäîêëàññîâ a:active {color:yellow;}
// TODO: ñåëåêòîðàìè ïñåâäîýëåìåíòîâ p::first-letter {font-size: 32px;}
CString source = oXml.GetText();
StrUtils::RemoveSymbol(source, _T(' '));
StrUtils::RemoveSymbol(source, _T('\n'));
StrUtils::RemoveSymbol(source, _T('\t'));
if (0 == source.GetLength())
return false;
int begin = 0;
int right = 0;
while (-1 != right)
{
right = source.Find(_T("}"), right);
if (-1 == right)
break;
CString src = source.Mid(begin, right);
int left = 0;
left = src.Find(_T("{"), left);
if (-1 == left)
break;
CString selector = src.Mid(0, left);
if (selector.GetLength())
{
Style style;
style.SetStyle(CString(src.Mid(left + 1, src.GetLength() - left)), true, us, model, colors);
ReadSelList(selector, _T(','));
for (size_t i = 0; i < m_selectors.size(); ++i)
{
selector = m_selectors[i];
if ('.' == selector[0])
{
selector.Remove(_T('.'));
m_classStyles[selector] = style;
}
else
{
AddTagStyle(m_selectors[i], style);
}
m_IsValid = true;
}
}
right++;
begin = right;
}
return true;
}
inline bool GetStyleForType(int tag, Style& style)
{
if (m_typeStyles[tag].IsCSS())
{
style = m_typeStyles[tag];
return true;
}
return false;
}
inline bool GetClassStyle(const CString& name, Style& style)
{
std::map<CString, Style>::iterator cp = m_classStyles.find(name);
if (cp != m_classStyles.end())
{
style = cp->second;
return true;
}
return false;
}
inline bool IsValid()
{
return m_IsValid;
}
private:
inline bool AddTagStyle(const CString& selector, Style& style)
{
if (_T("rect") == selector) { m_typeStyles[ERectangle] = style; m_typeStyles[ERectangle].SetCSS(true); return true; }
else if (_T("ellipse") == selector) { m_typeStyles[EEllipse] = style; m_typeStyles[EEllipse].SetCSS(true); return true; }
else if (_T("circle") == selector) { m_typeStyles[ECircle] = style; m_typeStyles[ECircle].SetCSS(true); return true; }
else if (_T("path") == selector) { m_typeStyles[EPath] = style; m_typeStyles[EPath].SetCSS(true); return true; }
else if (_T("polygon") == selector) { m_typeStyles[EPolygon] = style; m_typeStyles[EPolygon].SetCSS(true); return true; }
else if (_T("polyline") == selector) { m_typeStyles[EPolyline] = style; m_typeStyles[EPolyline].SetCSS(true); return true; }
else if (_T("text") == selector) { m_typeStyles[EText] = style; m_typeStyles[EText].SetCSS(true); return true; }
else if (_T("image") == selector) { m_typeStyles[EImage] = style; m_typeStyles[EImage].SetCSS(true); return true; }
else if (_T("line") == selector) { m_typeStyles[ELine] = style; m_typeStyles[ELine].SetCSS(true); return true; }
//else if (_T("symbol") == selector) { m_typeStyles[ESymbol] = style; m_typeStyles[ESymbol].SetCSS(true); return true; }
//else if (_T("g") == selector) { m_typeStyles[EGraphicsContainer] = style; m_typeStyles[EGraphicsContainer].SetCSS(true); return true; }
return false;
}
inline void ReadSelList(const CString& src, TCHAR splitter)
{
m_selectors.clear();
CString selector;
if (src.GetLength())
{
int symbol = 0, begin = 0;
while(-1 != symbol)
{
symbol = src.Find(splitter, symbol);
if (-1 == symbol)
{
if (src.GetLength() - begin >= 1)
{
selector = src.Mid(begin, src.GetLength() - begin);
if (selector.GetLength())
m_selectors.push_back(selector);
}
break;
}
selector = src.Mid(begin, symbol);
if (selector.GetLength())
m_selectors.push_back(selector);
symbol++;
begin = symbol;
}
}
}
private:
bool m_IsValid;
std::map<CString, Style> m_classStyles; // ñåëåêòîðû êëàññîâ
Style m_typeStyles[ENodesCount]; // ñåëåêòîðû ýëåìåíòîâ
std::vector<CString> m_selectors;
// TODO: îñòàëüíûå òèïà ñåëåêòîðîâ
};
}
namespace SVG
{
class Matrix
{
public:
Matrix()
{
Identity();
}
Matrix(double mat[9])
{
memcpy (m_fMat, mat, 9 * sizeof(double));
}
Matrix(double m1, double m2, double m3, double m4, double m5, double m6, double m7, double m8, double m9)
{
m_fMat[0] = m1;
m_fMat[1] = m2;
m_fMat[2] = m3;
m_fMat[3] = m4;
m_fMat[4] = m5;
m_fMat[5] = m6;
m_fMat[6] = m7;
m_fMat[7] = m8;
m_fMat[8] = m9;
}
Matrix(const CString& transforms, UnitSystem& us)
{
FromString (transforms, us);
}
inline Matrix Copy() const
{
return (*this);
}
inline const double& operator [] (int i) const
{
return m_fMat[i];
}
inline Matrix& operator *= (const Matrix& transform)
{
double mat[9];
for (int i = 0 ; i < 3; ++i)
{
for( int k = 0; k < 3; ++k)
{
mat [i*3 + k] = 0;
for (int j = 0; j < 3; ++j)
{
mat[i*3 + k] += m_fMat[i * 3 + j] * transform.m_fMat [j*3 + k];
}
}
}
*this = Matrix(mat);
return (*this);
}
inline Matrix& Move(double fX, double fY)
{
m_fMat[2] += fX;
m_fMat[5] += fY;
return (*this);
}
inline Matrix& Translate(double dX, double dY)
{
m_fMat[2] = dX;
m_fMat[5] = dY;
return (*this);
}
//
inline static Matrix ScaleTransform(double dX, double dY)
{
Matrix mat;
mat.m_fMat[0] = dX;
mat.m_fMat[4] = dY;
return mat;
}
inline static Matrix RotateTransform(double angle)
{
Matrix mat;
mat.m_fMat[0] = cos(angle);
mat.m_fMat[1] = -sin(angle);
mat.m_fMat[3] = sin(angle);
mat.m_fMat[4] = cos(angle);
return mat;
}
inline static Matrix TranslateTransform(double dX, double dY)
{
Matrix mat;
mat.m_fMat[2] = dX;
mat.m_fMat[5] = dY;
return mat;
}
inline static Matrix ApplyAt(double dX, double dY, const Matrix& transform)
{
Matrix mat;
mat.m_fMat[2] = -dX;
mat.m_fMat[5] = -dY;
mat *= transform;
mat.m_fMat[2] += dX;
mat.m_fMat[5] += dY;
return mat;
}
inline static Matrix RotateAtPoint(const Point& point, const double& angle)
{
Matrix mat;
mat.m_fMat[6] = -point.X;
mat.m_fMat[7] = -point.Y;
mat *= Matrix::RotateTransform (angle);
mat.m_fMat[6] += point.X;
mat.m_fMat[7] += point.Y;
return mat;
}
//
inline Point TranformPoint (const Point& point)
{
return Point(point.X * m_fMat[0] + point.Y * m_fMat [3] + m_fMat[6], point.X * m_fMat[1] + point.Y * m_fMat [4] + m_fMat[7]);
}
private:
inline void Identity()
{
m_fMat[0] = 1;
m_fMat[1] = 0;
m_fMat[2] = 0;
m_fMat[3] = 0;
m_fMat[4] = 1;
m_fMat[5] = 0;
m_fMat[6] = 0;
m_fMat[7] = 0;
m_fMat[8] = 1;
}
inline bool FromString(const CString& sTransforms, UnitSystem& us)
{
std::vector<CString> arrMatrix;
if (GetTranforms(sTransforms, arrMatrix))
{
Matrix matrix;
for (int i = 0; i < arrMatrix.size(); ++i)
matrix *= Matrix::ReadMatrix(arrMatrix[i], us);
*this = matrix;
return true;
}
return false;
}
inline static CString GetTransform(const CString& strMat, int& index)
{
index = 0;
CString strText = strMat.Tokenize ( _T("("), index);
if (-1 == index)
{
index = -1;
return CString(_T(""));
}
int length = strText.GetLength();
for (int i = 0; i < length; ++i)
{
if (_T(' ') == strText[i])
{
strText.Delete(i);
i--;
continue;
}
}
return strText;
}
inline static Matrix ReadMatrix(const CString& sSrc, UnitSystem& us)
{
int index = -1;
CString matType = GetTransform(sSrc, index);
if (0 == matType.GetLength() || -1 == index)
return Matrix();
CString sMat = sSrc.Mid(index, sSrc.GetLength() - index);
if (0 == sMat.GetLength())
return Matrix();
std::vector<double> mat;
if (StrUtils::DoubleValues(sMat, mat))
{
int count = mat.size();
if (CString(_T("matrix")) == matType)
{
Matrix oTransform;
/*
oTransform.m_fMat [ 0 ] = mat [ 0 ]; // a
oTransform.m_fMat [ 1 ] = mat [ 2 ]; // c
oTransform.m_fMat [ 2 ] = mat [ 4 ]; // e // tx
oTransform.m_fMat [ 3 ] = mat [ 1 ]; // b
oTransform.m_fMat [ 4 ] = mat [ 3 ]; // d
oTransform.m_fMat [ 5 ] = mat [ 5 ]; // f // ty
oTransform.m_fMat [ 6 ] = 0.0;
oTransform.m_fMat [ 7 ] = 0.0;
oTransform.m_fMat [ 8 ] = 1.0;
*/
//matrix(0<a> 1<b> 2<c> 3<d> 4<e> 5<f>)
oTransform.m_fMat[0] = mat[0]; // a
oTransform.m_fMat[1] = mat[2]; // c
oTransform.m_fMat[2] = us.Convert(mat[4], UNDEFINED, c_dirHorizontal); // e // tx
oTransform.m_fMat[3] = mat[1]; // b
oTransform.m_fMat[4] = mat[3]; // d
oTransform.m_fMat[5] = us.Convert(mat[5], UNDEFINED, c_dirVertical); // f // ty
oTransform.m_fMat[6] = 0.0;
oTransform.m_fMat[7] = 0.0;
oTransform.m_fMat[8] = 1.0;
return oTransform;
}
else if (CString ( _T("translate") ) == matType)
{
if (1 == count) return Matrix::TranslateTransform(us.Convert(mat[0], UNDEFINED, c_dirHorizontal), 0.0);
if (2 == count) return Matrix::TranslateTransform(us.Convert(mat[0], UNDEFINED, c_dirHorizontal), us.Convert(mat[1], UNDEFINED, c_dirVertical));
}
else if (CString(_T("scale")) == matType)
{
if (1 == count) return Matrix::ScaleTransform(mat[0], mat[0]);
if (2 == count) return Matrix::ScaleTransform(mat[0], mat[1]);
}
else if (CString ( _T("rotate") ) == matType)
{
if (1 == count) return Matrix::RotateTransform(mat[0] * M_PI / 180.0);
if (3 == count)
{
Matrix oTransform = Matrix::TranslateTransform(mat[1], mat[2]);
oTransform *= Matrix::RotateTransform(mat[0] * M_PI / 180);
oTransform *= Matrix::TranslateTransform(-mat[1], -mat[2]);
return oTransform;
}
}
else if ( CString ( _T("skewX") ) == matType)
{
Matrix oTransform;
oTransform.m_fMat[1] = tan(mat[0] * M_PI / 180.0); // c
return oTransform;
}
else if (CString(_T("skewY")) == matType)
{
Matrix oTransform;
oTransform.m_fMat[3] = tan(mat[0] * M_PI / 180.0); // b
return oTransform;
}
}
return Matrix();
}
inline static bool GetTranforms(const CString& strMat, std::vector<CString>& refTransforms)
{
int index = 0;
while (-1 != index)
{
refTransforms.push_back(strMat.Tokenize( _T(")"), index));
}
return (0 != refTransforms.size());
}
private:
double m_fMat[9];
};
class MatrixStack
{
public:
MatrixStack()
{
}
inline bool Push(const Matrix& transform, bool combine = true) // êàæäàÿ ïîñëåäóþùàÿ òðàíñôîðìàöèÿ ïðèìåíÿåòñÿ ê âåðøèíå ñòýêà
{
if ((0 == m_transforms.size()) || (false == combine))
{
m_transforms.push_back(transform);
return true;
}
if (combine)
{
Matrix top = GetTop ();
top *= transform;
m_transforms.push_back(top);
return true;
}
m_transforms.push_back(transform);
return true;
}
inline bool Pop()
{
if (m_transforms.size())
{
m_transforms.pop_back();
return true;
}
return false;
}
inline const Matrix GetTop() const
{
Matrix transform;
if (m_transforms.size())
transform = m_transforms[m_transforms.size() - 1];
return transform;
}
inline const Matrix GetFinal()
{
Matrix transform;
for (size_t i = 0; i < m_transforms.size(); ++i)
transform *= m_transforms[i];
return transform;
}
private:
std::vector <Matrix> m_transforms;
};
class PathParser
{
public:
PathParser()
{
m_bIsClose = false;
}
PathParser(UnitSystem& oUs, const CString& path)
{
FromString (oUs, path);
}
inline bool FromString(UnitSystem& oUnitSystem, const CString& path)
{
m_Points.clear ();
int To = 0;
bool EndSegment = false;
CString Tokens = _T("mMLlCcVvHhCcQqTtSsaAhHvV");
int count = path.GetLength();
for (int i = 0; i < count; ++i)
{
WCHAR symbol = path [i];
// move to
if (_T('m') == symbol || _T('M') == symbol || _T('l') == symbol || _T('L') == symbol || _T('t') == symbol || _T('T') == symbol)
{
To = i + 1;
CString Source = path.Tokenize ( Tokens, To );
// ATLTRACE ( _T("%c : - %ls\n"), symbol, Source );
std::vector<double> Values;
if (StrUtils::DoubleValues(Source, Values))
{
if ((symbol == _T('M')) || (symbol == _T('m')))
{
int Segments = (int)Values.size() / 2;
if (Segments > 0)
{
PointPath oPointM;
oPointM.code = path[i];
oPointM.oPoint = Point ( Values [ 0 ], Values [ 1 ] );
oPointM.subCode = path[i];
m_Points.push_back ( oPointM );
}
int iNextCode = (symbol == _T('M')) ? _T('L') : _T('l');
for ( int j = 1; j < Segments; ++j )
{
PointPath oPoint;
oPoint.code = iNextCode;
oPoint.oPoint = Point ( Values [ 0 + 2 * j ], Values [ 1 + 2 * j ] );
oPoint.subCode = path[i];
m_Points.push_back ( oPoint );
EndSegment = false;
// ATLTRACE ( _T("LineTo : %c, - %f, %f\n"), oPoint.code, oPoint.oPoint.X, oPoint.oPoint.Y );
}
}
else
{
if (m_Points.size() > 0 && EndSegment == false )
{
if ( symbol == _T('M') )
{
PointPath oEndPoint;
oEndPoint.code = _T('Z');
m_Points.push_back ( oEndPoint );
}
if ( symbol == _T('m') )
{
PointPath oEndPoint;
oEndPoint.code = _T('z');
m_Points.push_back ( oEndPoint );
}
}
int Segments = (int)Values.size() / 2;
for ( int j = 0; j < Segments; ++j )
{
PointPath oPoint;
oPoint.code = symbol;
if ( m_Points.size() > 0 && EndSegment == false )
{
if ( oPoint.code == _T('M') )
oPoint.code = _T('L');
if ( oPoint.code == _T('m') )
oPoint.code = _T('l');
}
oPoint.oPoint = Point ( Values [ 0 + 2 * j ], Values [ 1 + 2 * j ] );
m_Points.push_back ( oPoint );
EndSegment = false;
// ATLTRACE ( _T("LineTo : %c, - %f, %f\n"), oPoint.code, oPoint.oPoint.X, oPoint.oPoint.Y );
}
}
}
if (To == -1)
{
m_Points.clear ();
return false;
}
}
else if ( _T('h') == symbol || _T('H') == symbol || _T('v') == symbol || _T('V') == symbol )
{
To = i + 1;
CString Source = path.Tokenize ( Tokens, To );
std::vector<double> Values;
if (StrUtils::DoubleValues(Source, Values))
{
for ( int j = 0; j < Values.size(); ++j )
{
PointPath oPoint;
oPoint.code = symbol;
if ( _T('h') == symbol || _T('H') == symbol )
oPoint.oPoint.X = Values [ j ];
if ( _T('v') == symbol || _T('V') == symbol )
oPoint.oPoint.Y = Values [ j ];
m_Points.push_back(oPoint);
}
}
if ( To == -1 )
{
m_Points.clear ();
return false;
}
}
else if ( _T('a') == symbol || _T('A') == symbol ) // Elliptical arc curve
{
To = i + 1;
CString Source = path.Tokenize ( Tokens, To );
std::vector<double> Values;
if (StrUtils::DoubleValues(Source, Values))
{
//rx ry x-axis-rotation large-arc-flag sweep-flag x y
int Size = ( Values.size() / 7 ) * 7;
for ( int j = 0; j < Size; j += 7 )
{
PointPath oPoint;
oPoint.code = symbol;
oPoint.oPoint = Point ( Values [ j ], Values [ j + 1 ] ); // rx ry
m_Points.push_back ( oPoint );
oPoint.oPoint = Point ( Values [ j + 2 ], Values [ j + 3 ] ); // x-axis-rotation large-arc-flag
m_Points.push_back ( oPoint );
oPoint.oPoint = Point ( Values [ j + 4 ], Values [ j + 4 ] ); // sweep-flag
m_Points.push_back ( oPoint );
oPoint.oPoint = Point ( Values [ j + 5 ], Values [ j + 6 ] ); // x y
m_Points.push_back ( oPoint );
}
}
if ( To == -1 )
{
m_Points.clear();
return false;
}
}
else if ( _T('q') == symbol || _T('Q') == symbol || _T('s') == symbol || _T('S') == symbol ) // Quadratic Bezier
{
To = i + 1;
CString Source = path.Tokenize ( Tokens, To );
std::vector<double> Values;
if (StrUtils::DoubleValues(Source, Values))
{
PointPath oPoint;
oPoint.code = symbol;
oPoint.oPoint = Point ( Values [ 0 ], Values [ 1 ] );
m_Points.push_back ( oPoint );
oPoint.oPoint = Point ( Values [ 2 ], Values [ 3 ] );
m_Points.push_back ( oPoint );
// ATLTRACE ( _T("LineTo : %f, %f "), oPoint.oPoint.X, oPoint.oPoint.Y );
}
if ( To == -1 )
{
m_Points.clear ();
return false;
}
}
else if ( _T('c') == symbol || _T('C') == symbol ) // Cubic Bezier
{
To = i + 1;
CString Source = path.Tokenize ( Tokens, To );
// ATLTRACE ( _T("%c : - %ls\n"), symbol, Source );
std::vector<double> Values;
if (StrUtils::DoubleValues(Source, Values))
{
int Size = ( Values.size() / 6 ) * 6;
for ( int j = 0; j < Size; j += 6 )
{
PointPath oPoint;
oPoint.code = symbol;
oPoint.oPoint = Point ( Values [ j ], Values [ j + 1 ] );
m_Points.push_back ( oPoint );
oPoint.oPoint = Point ( Values [ j + 2 ], Values [ j + 3 ] );
m_Points.push_back ( oPoint );
oPoint.oPoint = Point ( Values [ j + 4 ], Values [ j + 5 ] );
m_Points.push_back ( oPoint );
// ATLTRACE ( _T("add curve : [ %f, %f ] \n"), oPoint.oPoint.X, oPoint.oPoint.Y );
}
}
if (To == -1)
{
m_Points.clear();
return false;
}
}
else if (_T('z') == symbol || _T('Z') == symbol) // close path
{
PointPath point;
point.code = symbol;
m_Points.push_back(point);
m_bIsClose = true;
EndSegment = true;
}
}
count = (long)m_Points.size();
for (long i = 0; i < count; ++i)
{
if (_T('a') == m_Points [i].code || _T('A') == m_Points [i].code)
{
m_Points [ i ].oPoint.X = oUnitSystem.Convert ( m_Points [ i ].oPoint.X, UNDEFINED, c_dirHorizontal );
m_Points [ i ].oPoint.Y = oUnitSystem.Convert ( m_Points [ i ].oPoint.Y, UNDEFINED, c_dirVertical );
m_Points [ i + 3 ].oPoint.X = oUnitSystem.Convert ( m_Points [ i + 3 ].oPoint.X, UNDEFINED, c_dirHorizontal );
m_Points [ i + 3 ].oPoint.Y = oUnitSystem.Convert ( m_Points [ i + 3 ].oPoint.Y, UNDEFINED, c_dirVertical );
i += 3;
continue;
}
m_Points [ i ].oPoint.X = oUnitSystem.Convert ( m_Points [ i ].oPoint.X, UNDEFINED, c_dirHorizontal );
m_Points [ i ].oPoint.Y = oUnitSystem.Convert ( m_Points [ i ].oPoint.Y, UNDEFINED, c_dirVertical );
}
return true;
}
inline std::vector <PointPath>& GetPoints ()
{
return m_Points;
}
inline bool IsClose()
{
return m_bIsClose;
}
inline void SetPoint(long index, const Point& val)
{
if ((long)m_Points.size() > index)
m_Points[index].oPoint = val;
}
inline Point GetPoint(long index)
{
if ((long)m_Points.size() > index)
return m_Points[index].oPoint;
return Point();
}
private:
bool m_bIsClose;
std::vector <PointPath> m_Points;
};
//class ImageBase64 // for inner data image's
//{
//public:
// ImageBase64 ()
// {
// m_pBuffer = NULL;
// m_nBufferSize = 0L;
// }
// ~ImageBase64 ()
// {
// if ( m_pBuffer )
// {
// delete [] m_pBuffer;
// m_pBuffer = NULL;
// m_nBufferSize = 0L;
// }
// }
// inline bool FromString (const CString& Src)
// {
// if ( m_pBuffer )
// {
// RELEASEOBJECT(m_pBuffer);
// m_nBufferSize = 0L;
// }
// CString BASE64 = CString ( _T("base64") );
// int to = Src.Find ( BASE64, 0 );
// if ( -1 != to )
// {
// to = Src.Find ( _T(","), to );
// CString Options = Src.Mid ( 0, to + 1 );
// int EncoderType = INVALID_ENCODER;
// if ( -1 != Options.Find ( _T("jpeg"), 0 ) )
// EncoderType = JPG_ENCODER;
// if ( -1 != Options.Find ( _T("png"), 0 ) )
// EncoderType = PNG_ENCODER;
// if ( INVALID_ENCODER != EncoderType )
// {
// CString buffer = Src.Mid ( Options.GetLength (), Src.GetLength () - Options.GetLength () );
// int Ind = -1;
// while ( 0 != Ind )
// Ind = buffer.Remove ( _T(' ') ); // â íåêîòîðûõ SVG áûëè ïðîáåëû
// return CreateImage ( (BYTE*) ( buffer.GetBuffer () ), buffer.GetLength (), EncoderType );
// }
// }
// return false;
// }
// inline bool GetImage (IUnknown*& image)
// {
// return ImageBase64::EncodeBufferToImageCOM(m_pBuffer, m_nBufferSize, image);
// }
//private:
// bool CreateImage (BYTE* pBuffer, unsigned long Length, int ImageEncoder = INVALID_ENCODER);
// static bool EncodeBufferToImageCOM (const BYTE* pBuffer, const unsigned long& ImageSize, IUnknown*& pImage);
// static bool GdiImageToImageCOM (Gdiplus::Bitmap* pBitmap, IUnknown*& pImage);
// static bool Base64Decode(LPTSTR szSrc, int nSrcLen, BYTE *pbDest, int *pnDestLen) throw();
//private:
// BYTE* m_pBuffer;
// int m_nBufferSize;
//};
}
namespace SVG
{
class RefElement : public ISvgRef
{
public:
virtual ~RefElement()
{
}
virtual bool FromXml (XmlUtils::CXmlNode& oXml, IRefStorage* model, UnitSystem& oUs)
{
m_XLinkRef = oXml.GetAttribute(_T("xlink:href"));
m_nodeId = oXml.GetAttribute(_T("id"));
m_model = model;
m_gradientTransform = Matrix(oXml.GetAttribute(_T("gradientTransform")), oUs);
if (m_XLinkRef.GetLength())
{
StrUtils::RemoveSpaces (m_XLinkRef);
if (_T('#') == m_XLinkRef[0])
{
m_XLinkRef = m_XLinkRef.Mid(1, m_XLinkRef.GetLength()-1);
}
}
return false;
}
virtual bool FromString (CString Str, IRefStorage* pStorage)
{
return false;
}
virtual bool Normalize (const double& dAddFMX, const double& dAddFMY) = 0;
protected:
inline static double DoubleValue (XmlUtils::CXmlNode& oXml, CString oAttr, UnitSystem& oUs, long direction)
{
CString sVal = oXml.GetAttribute(oAttr);
if (sVal.GetLength())
{
if (_T('%') == sVal[sVal.GetLength() - 1])
{
return _tstof(sVal.Mid(0, sVal.GetLength() - 1)) * 0.01;
}
}
double dVal = StrUtils::DoubleValue(sVal);
SVG::Metrics oValMet = StrUtils::GetMetrics(sVal);
return oUs.Convert(dVal, oValMet, direction);
}
protected:
IRefStorage* m_model;
CString m_XLinkRef;
Matrix m_gradientTransform;
};
class LinearGradient : public RefElement
{
public:
LinearGradient ()
{
m_nodeType = ELinearGradient;
m_pClip = NULL;
m_begin = Point(0, 0);
m_end = Point(1, 0);
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, IRefStorage* model, UnitSystem& oUs)
{
RefElement::FromXml(oXml, model, oUs);
if (oXml.GetAttributeOrValue(_T("x1")).GetLength())
m_begin.X = DoubleValue(oXml, _T("x1"), oUs, c_dirHorizontal);
if (oXml.GetAttributeOrValue(_T("y1")).GetLength())
m_begin.Y = DoubleValue(oXml, _T("y1"), oUs, c_dirVertical);
if (oXml.GetAttributeOrValue(_T("x2")).GetLength())
m_end.X = DoubleValue(oXml, _T("x2"), oUs, c_dirHorizontal);
if (oXml.GetAttributeOrValue(_T("y2")).GetLength())
m_end.Y = DoubleValue(oXml, _T("y2"), oUs, c_dirVertical);
m_gradientUnits = oXml.GetAttributeOrValue(_T("gradientUnits"), _T(""));
//XML::IXMLDOMNodeListPtr comList = NULL;
//if (oXml.GetNodes(comList))
{
XmlUtils::CXmlNodes nodes;
if (oXml.GetNodes(_T("*"), nodes))
{
for (long i = 0; i < nodes.GetCount(); ++i)
{
XmlUtils::CXmlNode oXml2;
if (nodes.GetAt(i, oXml2))
{
if (_T("stop") == oXml2.GetName())
{
m_Color.Add(oXml2);
}
}
}
}
}
return false;
}
virtual bool FromString(const CString& Str, IRefStorage* model, UnitSystem& oUs)
{
return false;
}
virtual bool RefreshXLinkSource(IRefStorage* model)
{
if (m_XLinkRef.GetLength())
{
ISvgRef* pDef = NULL;
if (model->GetRef(m_XLinkRef, pDef))
{
if (ELinearGradient == pDef->nodeType())
{
LinearGradient* gradient = static_cast<LinearGradient*>(pDef);
if (gradient)
{
for (int i = 0; i < gradient->GetColors().Count(); ++i)
m_Color.Add(gradient->GetColors().Get(i));
return true;
}
}
}
}
return false;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
return false;
}
//
inline const GradientColor& GetColors()
{
return m_Color;
}
inline const CString& GetXml()
{
if (0 == m_sXml.GetLength())
{
m_sXml.Format(_T("<linearGradient x1='%f' y1='%f' x2='%f' y2='%f' gradientUnits ='%ls' gradientTransform='matrix(%f, %f, %f, %f, %f, %f)' sourceType='svg' >"),
m_begin.X, m_begin.Y, m_end.X, m_end.Y, m_gradientUnits,
m_gradientTransform[0], m_gradientTransform[1],
m_gradientTransform[3], m_gradientTransform[4],
m_gradientTransform[2], m_gradientTransform[5]);
CString sVal;
for (int i = 0; i < m_Color.Count(); ++i)
{
sVal.Format(_T("<stop stop-color = '%d' offset ='%f' stop-opacity ='%f'/>"), m_Color.Get(i).m_nColor, m_Color.Get(i).m_fOffset, m_Color.Get(i).m_fOpacity);
m_sXml += sVal;
}
m_sXml += _T("</linearGradient>");
}
return m_sXml;
}
private:
GradientColor m_Color;
CString m_sXml;
CString m_gradientUnits;
Point m_begin;
Point m_end;
};
class RadialGradient : public RefElement
{
public:
RadialGradient ()
{
m_nodeType = ERadialGradient;
m_pClip = NULL;
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, IRefStorage* pStorage, UnitSystem& oUs)
{
RefElement::FromXml(oXml, pStorage, oUs);
m_c.X = DoubleValue(oXml, _T("cx"), oUs, c_dirHorizontal);
m_c.Y = DoubleValue(oXml, _T("cy"), oUs, c_dirVertical);
m_f.X = DoubleValue(oXml, _T("fx"), oUs, c_dirHorizontal);
m_f.Y = DoubleValue(oXml, _T("fy"), oUs, c_dirVertical);
m_R = DoubleValue(oXml, _T("r"), oUs, c_dirHorizontal);
m_gradientUnits = oXml.GetAttributeOrValue(_T("gradientUnits"), _T(""));
//XML::IXMLDOMNodeListPtr pXmlNodes = NULL;
//if (oXml.GetNodes(pXmlNodes))
{
XmlUtils::CXmlNodes oXmlNodes;
if (oXml.GetNodes(_T("*"), oXmlNodes))
{
for (long i = 0; i < oXmlNodes.GetCount(); ++i)
{
XmlUtils::CXmlNode oXmlNode2;
if (oXmlNodes.GetAt(i, oXmlNode2))
{
if (_T("stop") == oXmlNode2.GetName())
{
m_Color.Add(oXmlNode2);
}
}
}
}
}
return false;
}
virtual bool FromString(const CString& Str, IRefStorage* pStorage, UnitSystem& oUs)
{
return false;
}
virtual bool RefreshXLinkSource(IRefStorage* pStorage)
{
if (m_XLinkRef.GetLength())
{
ISvgRef* pDef = NULL;
if (pStorage->GetRef (m_XLinkRef, pDef))
{
if (ELinearGradient == pDef->nodeType())
{
LinearGradient* gradient = static_cast<LinearGradient*>(pDef);
if (gradient)
{
for (int i = 0; i < gradient->GetColors().Count(); ++i)
m_Color.Add(gradient->GetColors().Get(i));
return true;
}
}
}
}
return false;
}
virtual bool Normalize(const double& dAddFMX, const double& dAddFMY)
{
return false;
}
//
inline const GradientColor& GetColors() const
{
return m_Color;
}
inline const CString& GetXml()
{
if (0 == m_sXml.GetLength())
{
m_sXml.Format(_T("<radialGradient cx='%f' cy='%f' fx='%f' fy='%f' r='%f' gradientUnits='%ls' gradientTransform='matrix(%f, %f, %f, %f, %f, %f)' sourceType='svg' >"),
m_c.X, m_c.Y, m_f.X, m_f.Y, m_R,
m_gradientUnits,
m_gradientTransform[0], m_gradientTransform[1],
m_gradientTransform[3], m_gradientTransform[4],
m_gradientTransform[2], m_gradientTransform[5]);
CString sVal;
for (int i = 0; i < m_Color.Count(); ++i)
{
sVal.Format(_T("<stop stop-color = '%d' offset ='%f' stop-opacity ='%f'/>"), m_Color.Get(i).m_nColor, m_Color.Get(i).m_fOffset, m_Color.Get(i).m_fOpacity);
m_sXml += sVal;
}
m_sXml += _T("</radialGradient>");
}
return m_sXml;
}
private:
CString m_gradientUnits;
GradientColor m_Color;
Point m_c;
Point m_f;
double m_R;
CString m_sXml;
};
}
namespace SVG
{
class DrawElement : public ISvgRef
{
public:
virtual ~DrawElement()
{
}
virtual bool FromXml (XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
m_nodeId = oXml.GetAttribute(_T("id"));
m_className = oXml.GetAttribute(_T("class"));
m_pClip = NULL;
m_urlClipPath = oXml.GetAttribute(_T("clip-path"));
StrUtils::UrlRefValue2(m_urlClipPath);
return true;
}
virtual bool FromXml (CString sXml, UnitSystem& oUs)
{
return false;
}
//
virtual void SetStyle(const Style& oStyle)
{
m_oStyle = oStyle;
}
virtual const Style& GetStyle()
{
return m_oStyle;
}
virtual void SetTransform (const Matrix& oTransform)
{
m_oTransform = oTransform;
}
virtual const Matrix& GetTransform () const
{
return m_oTransform;
}
virtual const CString& ClassName () const
{
return m_className;
}
//
virtual bool Normalize (const double& dAddFMX, const double& dAddFMY)
{
return false;
}
// link
virtual bool RefreshXLinkSource (IRefStorage* pStorage)
{
#if defined(_DEBUG) && (defined(_WIN32) || defined(_WIN64))
// ATLTRACE (L"NOT IMPLEMENTED - RefreshXLinkSource: id - %ls\n", nodeId());
#endif
return false;
}
protected:
inline static double DoubleValue (XmlUtils::CXmlNode& oXml, CString oAttr, UnitSystem& oUs, long direction)
{
double dVal = StrUtils::DoubleValue(oXml.GetAttribute(oAttr));
SVG::Metrics oValMet = StrUtils::GetMetrics(oXml.GetAttribute(oAttr));
return oUs.Convert(dVal, oValMet, direction);
}
protected:
Style m_oStyle;
Matrix m_oTransform;
CString m_className;
};
class Line : public DrawElement
{
public:
Line ()
{
m_nodeType = ELine;
m_pClip = NULL;
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
DrawElement::FromXml (oXml, oUs);
m_From.X = DoubleValue(oXml, _T("x1"), oUs, c_dirHorizontal);
m_From.Y = DoubleValue(oXml, _T("y1"), oUs, c_dirVertical);
m_To.X = DoubleValue(oXml, _T("x2"), oUs, c_dirHorizontal);
m_To.Y = DoubleValue(oXml, _T("y2"), oUs, c_dirVertical);
return false;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
m_From *= Point(dAfX, dAfY);
m_To *= Point(dAfX, dAfY);
return true;
}
inline const Point& GetFrom() const
{
return m_From;
}
inline const Point& GetTo() const
{
return m_To;
}
private:
Point m_From;
Point m_To;
};
class Rectangle : public DrawElement
{
public:
Rectangle ()
{
m_nodeType = ERectangle;
m_pClip = NULL;
m_Arc.X = 0.0;
m_Arc.Y = 0.0;
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
DrawElement::FromXml(oXml, oUs);
m_From.X = DoubleValue(oXml, _T("x"), oUs, c_dirHorizontal);
m_From.Y = DoubleValue(oXml, _T("y"), oUs, c_dirVertical);
m_To.X = m_From.X + DoubleValue(oXml, _T("width"), oUs, c_dirHorizontal);
m_To.Y = m_From.Y + DoubleValue(oXml, _T("height"), oUs, c_dirVertical);
m_Arc.X = DoubleValue(oXml, _T("rx"), oUs, c_dirHorizontal);
m_Arc.Y = DoubleValue(oXml, _T("ry"), oUs, c_dirVertical);
return true;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
m_From *= Point(dAfX, dAfY);
m_To *= Point(dAfX, dAfY);
m_Arc *= Point(dAfX, dAfY);
return false;
}
inline const Point& GetFrom() const
{
return m_From;
}
inline const Point& GetTo() const
{
return m_To;
}
inline const Point& GetArc() const
{
return m_Arc;
}
private:
Point m_From;
Point m_To;
Point m_Arc;
};
class Ellipse : public DrawElement
{
public:
Ellipse ()
{
m_nodeType = EEllipse;
m_pClip = NULL;
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
DrawElement::FromXml(oXml, oUs);
m_C.X = DoubleValue(oXml, _T("cx"), oUs, c_dirHorizontal);
m_C.Y = DoubleValue(oXml, _T("cy"), oUs, c_dirVertical);
m_R.X = DoubleValue(oXml, _T("rx"), oUs, c_dirHorizontal);
m_R.Y = DoubleValue(oXml, _T("ry"), oUs, c_dirVertical);
return true;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
m_C *= Point(dAfX, dAfY);
m_R *= Point(dAfX, dAfY);
return true;
}
public:
Point m_C;
Point m_R;
};
class Circle : public DrawElement
{
public:
Circle ()
{
m_nodeType = ECircle;
m_pClip = NULL;
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
DrawElement::FromXml (oXml, oUs);
m_C.X = DoubleValue(oXml, _T("cx"), oUs, c_dirHorizontal);
m_C.Y = DoubleValue(oXml, _T("cy"), oUs, c_dirVertical);
m_R.X = DoubleValue(oXml, _T("r"), oUs, c_dirHorizontal);
m_R.Y = m_R.X;
return true;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
m_C *= Point(dAfX, dAfY);
m_R *= Point(dAfX, dAfY);
return true;
}
public:
Point m_C;
Point m_R;
};
class Path : public DrawElement
{
public:
Path ()
{
m_nodeType = EPath;
m_pClip = NULL;
}
virtual bool FromXml (XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
DrawElement::FromXml(oXml, oUs);
m_oUs = oUs;
m_oParser.FromString(oUs, oXml.GetAttribute(_T("d")));
return false;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
long count = (long)m_oParser.GetPoints().size();
for (long i = 0; i < count; ++i)
{
Point oPoint = m_oParser.GetPoint(i);
oPoint *= Point (dAfX, dAfY);
m_oParser.SetPoint(i, oPoint);
}
return true;
}
inline PathParser& GetPath ()
{
return m_oParser;
}
inline double GetX (long index)
{
return m_oParser.GetPoints()[index].oPoint.X;
}
inline double GetY (long index)
{
return m_oParser.GetPoints()[index].oPoint.Y;
}
inline const Point& Get (long index)
{
return m_oParser.GetPoints()[index].oPoint;
}
inline int GetCode (long index)
{
return m_oParser.GetPoints()[index].code;
}
inline int GetSubCode (long index)
{
return m_oParser.GetPoints()[index].subCode;
}
inline long GetSize ()
{
return (long)m_oParser.GetPoints().size();
}
private:
inline static double DoubleValue(UnitSystem& oUnitSystem, double Value, long Direction)
{
return oUnitSystem.Convert(Value, UNDEFINED, Direction);
}
private:
PathParser m_oParser;
UnitSystem m_oUs;
CString m_ClipRule;
};
class Polyline : public DrawElement
{
public:
Polyline ()
{
m_nodeType = EPolyline;
m_pClip = NULL;
}
virtual bool FromXml (XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
DrawElement::FromXml (oXml, oUs);
m_points.clear ();
StrUtils::DoubleValues(oXml.GetAttribute(_T("points")), m_points);
for (size_t i = 0; i < m_points.size(); i += 2)
{
m_points[i] = DoubleValue(oUs, m_points[i], c_dirHorizontal);
m_points[i+1] = DoubleValue(oUs, m_points[i+1], c_dirVertical);
}
return (m_points.size() > 0);
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
for (size_t i = 0; i < m_points.size(); i += 2)
{
m_points[i] *= dAfX;
m_points[i + 1] *= dAfY;
}
return true;
}
inline double GetX (long index) const
{
return m_points[index * 2];
}
inline double GetY (long index) const
{
return m_points[index * 2 + 1];
}
inline long GetSize () const
{
return (long)m_points.size() / 2;
}
private:
inline static double DoubleValue(UnitSystem& oUnitSystem, double Value, long Direction)
{
return oUnitSystem.Convert(Value, UNDEFINED, Direction);
}
protected:
std::vector <double> m_points;
};
class Polygon : public Polyline
{
public:
Polygon ()
{
m_nodeType = EPolygon;
m_pClip = NULL;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
for (size_t i = 0; i < m_points.size(); i += 2)
{
m_points[i] *= dAfX;
m_points[i + 1] *= dAfY;
}
return true;
}
};
class Text : public DrawElement
{
public:
Text ()
{
m_nodeType = EText;
m_pClip = NULL;
}
virtual bool FromXml ( XmlUtils::CXmlNode& oXmlNode, UnitSystem& oUnitSystem )
{
DrawElement::FromXml ( oXmlNode, oUnitSystem );
m_oUs = oUnitSystem;
m_Pos.X = DoubleValue ( oXmlNode, _T("x"), oUnitSystem, c_dirHorizontal );
m_Pos.Y = DoubleValue ( oXmlNode, _T("y"), oUnitSystem, c_dirVertical );
m_Shift.X = DoubleValue ( oXmlNode, _T("dx"), oUnitSystem, c_dirHorizontal );
m_Shift.Y = DoubleValue ( oXmlNode, _T("dy"), oUnitSystem, c_dirVertical );
m_Source = oXmlNode.GetText ();
// ñòèëü ìîæåò çàäàâàòüñÿ âîîáùå ãäå òî ââåðõó ïî äåðåâó
m_oFontStyle.UpdateStyle ( oXmlNode );
return true;
}
virtual bool Normalize ( const double& dAddFMX, const double& dAddFMY )
{
m_Pos *= Point ( dAddFMX, dAddFMY );
m_Shift *= Point ( dAddFMX, dAddFMY );
return true;
}
inline const FontStyle& GetFontStyle ()
{
return m_oFontStyle;
}
inline const CString& GetText ()
{
return m_Source;
}
public:
Point m_Pos;
Point m_Shift;
CString m_Source;
FontStyle m_oFontStyle;
UnitSystem m_oUs;
};
//class Image : public DrawElement
//{
//protected:
// class CFileDownloader : public CBaseThread
// {
// public :
// CFileDownloader (CString sFileUrl, bool bDelete = true) : CBaseThread(0)
// {
// m_pFile = NULL;
// m_sFilePath = _T("");
// m_sFileUrl = sFileUrl;
// m_bComplete = false;
// m_bDelete = bDelete;
// }
// ~CFileDownloader ()
// {
// if ( m_pFile )
// {
// ::fclose( m_pFile );
// m_pFile = NULL;
// }
// if ( m_sFilePath.GetLength() > 0 && m_bDelete )
// {
// DeleteFileW( m_sFilePath.GetBuffer() );
// m_sFilePath = _T("");
// }
// }
// CString GetFilePath()
// {
// return m_sFilePath;
// }
// bool IsFileDownloaded()
// {
// return m_bComplete;
// }
// protected :
// unsigned int DownloadFile(CString sFileUrl)
// {
// if ( false == InternetGetConnectedState ( 0, 0 ) )
// return S_false;
// char sTempPath[MAX_PATH], sTempFile[MAX_PATH];
// if ( 0 == GetTempPathA( MAX_PATH, sTempPath ) )
// return S_false;
// if ( 0 == GetTempFileNameA( sTempPath, "CSS", 0, sTempFile ) )
// return S_false;
// m_pFile = ::fopen( sTempFile, "wb" );
// if ( !m_pFile )
// return S_false;
// m_sFilePath = CString( sTempFile );
// HINTERNET hInternetSession = InternetOpen ( _T("Microsoft Internet Explorer"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
// if ( NULL == hInternetSession )
// return S_false;
// CString sHTTPHeader = _T("Range: bytes=0-0");
// HINTERNET hInternetOpenURL = InternetOpenUrl ( hInternetSession, sFileUrl.GetBuffer(), sHTTPHeader, -1, INTERNET_FLAG_RESYNCHRONIZE, 0 );
// if ( NULL != hInternetOpenURL )
// {
// if ( true == QueryStatusCode ( hInternetOpenURL, true ) )
// {
// LONGLONG nFileSize = GetFileLength( hInternetOpenURL, true );
// InternetCloseHandle ( hInternetOpenURL );
// if ( -1 != nFileSize )
// {
// LONGLONG nStartByte = 0;
// while ( m_bRunThread )
// {
// if ( nStartByte == nFileSize - 1 )
// {
// InternetCloseHandle ( hInternetSession );
// return S_OK;
// }
// LONGLONG nEndByte = nStartByte + MAX_PATH_DOWNLOAD_FILE_SIZE;
// if ( nEndByte >= nFileSize )
// nEndByte = nFileSize - 1;
// BYTE arrBuffer[ MAX_PATH_DOWNLOAD_FILE_SIZE ] = { 0 };
// DWORD dwBytesDownload = DownloadFilePath ( hInternetSession, arrBuffer, nStartByte, nEndByte, sFileUrl, true, MAX_PATH_DOWNLOAD_FILE_SIZE );
// nStartByte = nEndByte;
// if ( -1 == dwBytesDownload )
// {
// InternetCloseHandle ( hInternetSession );
// return S_false;
// }
// ::fwrite( (BYTE*)arrBuffer, 1, dwBytesDownload, m_pFile );
// ::fflush( m_pFile );
// CheckSuspend ();
// }
// }
// }
// else if ( true == QueryStatusCode( hInternetOpenURL, false ) )
// {
// LONGLONG nFileSize = GetFileLength( hInternetOpenURL, false );
// InternetCloseHandle ( hInternetOpenURL );
// if ( -1 != nFileSize && nFileSize < MAX_SINGLE_DOWNLOAD_FILE_SIZE )
// {
// while ( m_bRunThread )
// {
// BYTE arrBuffer[ MAX_SINGLE_DOWNLOAD_FILE_SIZE ] = { 0 };
// DWORD dwBytesDownload = DownloadFilePath ( hInternetSession, arrBuffer, 0, nFileSize, sFileUrl, false, MAX_SINGLE_DOWNLOAD_FILE_SIZE );
// if ( -1 == dwBytesDownload )
// {
// InternetCloseHandle ( hInternetSession );
// return S_false;
// }
// ::fwrite( (BYTE*)arrBuffer, 1, dwBytesDownload, m_pFile );
// ::fflush( m_pFile );
// InternetCloseHandle( hInternetSession );
// return S_OK;
// }
// }
// }
// }
// DWORD dwError = GetLastError();
// InternetCloseHandle ( hInternetSession );
// return S_OK;
// }
// DWORD DownloadFilePath(HINTERNET hInternet, LPBYTE pBuffer, LONGLONG nStartByte, LONGLONG nEndByte, CString sFileURL, bool bIsRanges, DWORD dwReadBytes )
// {
// if ( NULL == hInternet )
// return -1;
// if ( nStartByte > nEndByte || !pBuffer )
// return -1;
// CString sHTTPHeader = _T("");
// sHTTPHeader.Format( _T("Range: bytes=%I64d-%I64d"), nStartByte, nEndByte );
// HINTERNET hInternetOpenURL = InternetOpenUrl ( hInternet, sFileURL, sHTTPHeader, -1, INTERNET_FLAG_RESYNCHRONIZE, 0 );
// if ( NULL == hInternetOpenURL )
// return -1;
// if ( false == QueryStatusCode ( hInternetOpenURL, bIsRanges ) )
// {
// InternetCloseHandle ( hInternetOpenURL );
// return -1;
// }
// DWORD dwBytesRead = 0;
// if ( false == InternetReadFile ( hInternetOpenURL, pBuffer, dwReadBytes, &dwBytesRead ) )
// {
// InternetCloseHandle ( hInternetOpenURL );
// return -1;
// }
// InternetCloseHandle ( hInternetOpenURL );
// return dwBytesRead;
// }
// virtual DWORD ThreadProc ()
// {
// m_bComplete = false;
// CoInitialize ( NULL );
// if ( S_OK != DownloadFile ( m_sFileUrl ) )
// {
// m_bRunThread = false;
// CoUninitialize ();
// return 0;
// }
// m_bRunThread = false;
// CoUninitialize ();
// m_bComplete = true;
// return 0;
// }
// bool QueryStatusCode (HINTERNET hInternet, bool bIsRanges)
// {
// if ( NULL == hInternet )
// return false;
// int nResult = 0;
// DWORD dwLengthDataSize = 4;
// if ( false == HttpQueryInfo ( hInternet, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &nResult, &dwLengthDataSize, NULL ) )
// return false;
// if ( HTTP_STATUS_NOT_FOUND == nResult )
// {
// return false;
// }
// else if ( ( HTTP_STATUS_OK != nResult && false == bIsRanges ) || ( HTTP_STATUS_PARTIAL_CONTENT != nResult && true == bIsRanges ) )
// {
// return false;
// }
// return true;
// }
// LONGLONG GetFileLength (HINTERNET hInternet, bool bIsRanges )
// {
// if ( NULL == hInternet )
// return -1;
// if ( bIsRanges )
// {
// char arrResult[ MAX_SIZE ] = { 0 };
// DWORD dwLengthDataSize = sizeof ( arrResult );
// if ( false == HttpQueryInfoA( hInternet, HTTP_QUERY_CONTENT_RANGE, &arrResult, &dwLengthDataSize, NULL ) )
// {
// return -1;
// }
// if ( 0 >= dwLengthDataSize )
// return -1;
// CString sResult( arrResult );
// int nStartIndex = sResult.Find ( CONTENT_RANGE );
// if ( -1 == nStartIndex )
// return -1;
// sResult = sResult.Mid( nStartIndex + CONTENT_RANGE_SIZE );
// LONGLONG nFileSize = _wtoi64 ( sResult.GetBuffer() );
// if ( 0 < nFileSize )
// nFileSize += 1;
// return nFileSize;
// }
// else
// {
// char arrResult[ MAX_SIZE ] = { 0 };
// DWORD dwLengthDataSize = sizeof ( arrResult );
// if ( false == HttpQueryInfoA( hInternet, HTTP_QUERY_CONTENT_LENGTH, &arrResult, &dwLengthDataSize, NULL ) )
// {
// return -1;
// }
// if ( 0 >= dwLengthDataSize )
// return -1;
// CString sResult( arrResult );
// LONGLONG nFileSize = 0;
// nFileSize = _wtoi64 ( sResult.GetBuffer () );
// return nFileSize;
// }
// }
// protected :
// FILE *m_pFile; // Õýíäë íà âðåìåííûé ôàéë
// CString m_sFilePath; // Ïóòü ê ñîõðàíåííîìó ôàéëó íà äèñêå
// CString m_sFileUrl; // Ññûëêà íà ñêà÷èâàíèå ôàéëà
// bool m_bComplete; // Çàêà÷àëñÿ ôàéë èëè íåò
// bool m_bDelete; // Óäàëÿòü ëè ôàéë â äåñòðóêòîðå
// };
// class CImageManager
// {
// public:
// CImageManager()
// {
// }
// public:
// inline CString GenerateImage(const CString& strInput)
// {
// if (IsNeedDownload(strInput))
// return DownloadImage(strInput);
// bool doCopyFile = false;
// CString strExts = _T(".jpg");
// int nIndexExt = strInput.ReverseFind(TCHAR('.'));
// if (-1 != nIndexExt)
// strExts = strInput.Mid(nIndexExt);
// if (strExts == _T(".tmp"))
// {
// strExts = _T(".png");
// doCopyFile = true;
// }
// if ( false == doCopyFile )
// return strInput;
// TCHAR sTempPath[MAX_PATH];
// if ( 0 == GetTempPath ( MAX_PATH, sTempPath ) )
// return strInput;
// SYSTEMTIME oTime;
// GetSystemTime ( &oTime );
// CString fileName;
// fileName.Format (_T("%ls\\%d%d%d%d%d%d%ls"), sTempPath, oTime.wYear, oTime.wDay, oTime.wHour, oTime.wMinute, oTime.wSecond, oTime.wMilliseconds, strExts );
// CImageManager::CopyFile(strInput, fileName, NULL, NULL);
// return fileName;
// }
// inline bool IsNeedDownload(const CString& strFile)
// {
// int n1 = strFile.Find(_T("www"));
// int n2 = strFile.Find(_T("http"));
// int n3 = strFile.Find(_T("ftp"));
// if (((n1 >= 0) && (n1 < 10)) || ((n2 >= 0) && (n2 < 10)) || ((n3 >= 0) && (n3 < 10)))
// return true;
// return false;
// }
// inline CString DownloadImage(const CString& strFile)
// {
// CFileDownloader oDownloader(strFile, true);
// oDownloader.StartWork ( 1 );
// while ( oDownloader.IsRunned() )
// {
// ::Sleep( 10 );
// }
// if ( oDownloader.IsFileDownloaded() )
// {
// return GenerateImage( oDownloader.GetFilePath() );
// }
// return _T("");
// }
// static bool CopyFile(CString strExists, CString strNew, LPPROGRESS_ROUTINE lpFunc, LPVOID lpData)
// {
// DeleteFile(strNew);
// return ::CopyFileEx(strExists, strNew, lpFunc, lpData, false, 0);
// }
// };
//public:
// Image ()
// {
// m_nodeType = EImage;
// m_pClip = NULL;
// }
// virtual bool FromXml (XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
// {
// DrawElement::FromXml (oXml, oUs);
// m_Or.X = DoubleValue(oXml, _T("x"), oUs, c_dirHorizontal);
// m_Or.Y = DoubleValue(oXml, _T("y"), oUs, c_dirVertical);
// m_Size.X = DoubleValue(oXml, _T("width"), oUs, c_dirHorizontal);
// m_Size.Y = DoubleValue(oXml, _T("height"), oUs, c_dirVertical);
// m_sPreserveAspectRatio = oXml.GetAttributeOrValue(_T("preserveAspectRatio"), _T(""));
// m_XLinkRef = oXml.GetAttribute(_T("xlink:href"));
// if (m_XLinkRef.GetLength ())
// {
// StrUtils::RemoveSpaces (m_XLinkRef);
// /*
// if ( _T('#') == m_XLinkRef [0] )
// {
// }
// */
// if (m_XLinkRef.GetLength () > 4)
// {
// CImageManager onlineImage;
// if (onlineImage.IsNeedDownload(m_XLinkRef))
// {
// m_ImagePath = onlineImage.GenerateImage(m_XLinkRef);
// if ( m_ImagePath.GetLength() > 1 )
// return true;
// }
// if (_T('d') == m_XLinkRef[0] && _T('a') == m_XLinkRef[1] && _T('t') == m_XLinkRef[2] && _T('a') == m_XLinkRef[3])
// {
// m_bin64Image.FromString(m_XLinkRef);
// }
// else
// {
// m_ImagePath = StrUtils::UrlDecode (m_XLinkRef).MakeLower();
// CString URLFile = CString(_T("file:///"));
// int to = m_ImagePath.Find(URLFile, 0);
// if (-1 != to)
// {
// m_ImagePath = m_ImagePath.Mid(URLFile.GetLength(), m_ImagePath.GetLength() - to - URLFile.GetLength());
// }
// }
// }
// }
// return true;
// }
// virtual bool Normalize(const double& dAfX, const double& dAfY)
// {
// m_Or *= Point(dAfX, dAfY);
// m_Size *= Point(dAfX, dAfY);
// return true;
// }
// inline const Point& GetFrom() const
// {
// return m_Or;
// }
// inline const Point& GetSize() const
// {
// return m_Size;
// }
// inline const CString& GetXLink() const
// {
// return m_XLinkRef;
// }
// inline CString LivePath(const CString& sWorkingDirectory)
// {
// if (GetXLink().GetLength())
// {
// CString sFile = FileUtils::GetFullPathName (GetXLink());
// if ((0 == sFile.GetLength()) || !FileUtils::FileExists (sFile))
// {
// sFile = CString(sWorkingDirectory + "\\" + GetXLink());
// if (!FileUtils::FileExists (sFile))
// {
// sFile = GetXLink();
// if (!FileUtils::FileExists (sFile))
// {
// return m_ImagePath;
// }
// }
// }
// return FileUtils::GetFullPathName(sFile);
// }
// return m_ImagePath;
// }
// inline const CString& PreserveAspectRatio() const
// {
// return m_sPreserveAspectRatio;
// }
//public:
// Point m_Or;
// Point m_Size;
// CString m_sPreserveAspectRatio;
// CString m_XLinkRef;
// CString m_ImagePath;
// ImageBase64 m_bin64Image;
//};
class Use : public DrawElement
{
public:
Use()
{
m_nodeType = EUse;
m_pClip = NULL;
m_bBrokeRefLink = false;
m_pRefLink = NULL;
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, UnitSystem& oUs)
{
DrawElement::FromXml (oXml, oUs);
m_bBrokeRefLink = false;
m_From.X = DoubleValue(oXml, _T("x"), oUs, c_dirHorizontal);
m_From.Y = DoubleValue(oXml, _T("y"), oUs, c_dirVertical);
m_To.X = DoubleValue(oXml, _T("width"), oUs, c_dirHorizontal) + m_From.X;
m_To.Y = DoubleValue(oXml, _T("height"), oUs, c_dirVertical) + m_From.Y;
m_XLinkRef = oXml.GetAttribute(_T("xlink:href"));
if (m_XLinkRef.GetLength())
{
StrUtils::RemoveSpaces (m_XLinkRef);
if (m_XLinkRef.GetLength())
{
if (_T('#') == m_XLinkRef[0])
{
m_XLinkRef = m_XLinkRef.Mid(1, m_XLinkRef.GetLength() - 1);
}
}
}
return true;
}
virtual bool RefreshXLinkSource (IRefStorage* pStorage)
{
if (NULL != m_pRefLink) // ñâÿçü óæå åñòü, íåò ñìûñëà îïÿòü èñêàòü ñîîòâåñòâèå
return true;
if (m_bBrokeRefLink) // íåòó ñâÿçè
return false;
if (m_XLinkRef.GetLength())
{
ISvgRef* pRefLink = NULL;
if (pStorage->GetRef(m_XLinkRef, pRefLink))
{
m_pRefLink = pRefLink;
// ATLTRACE(_T("RefLink for object : %ls - %ls\n"), nodeId(), m_pRefLink->nodeId());
return true;
}
}
m_bBrokeRefLink = true;
return false;
}
virtual bool Normalize(const double& dAddFMX, const double& dAddFMY)
{
return false;
}
inline ISvgRef* GetRefLink ()
{
return m_pRefLink;
}
inline const Point& GetFrom() const
{
return m_From;
}
inline const Point& GetTo() const
{
return m_To;
}
inline const CString& GetXLink() const
{
return m_XLinkRef;
}
private:
Point m_From;
Point m_To;
CString m_XLinkRef;
bool m_bBrokeRefLink;
ISvgRef* m_pRefLink;
};
}
namespace SVG
{
class Painter;
//
class DrawBuilder
{
public:
inline DrawElement* Build (const CString& sName)
{
if (CString(_T("rect")) == sName) return new Rectangle();
else if (CString(_T("ellipse")) == sName) return new Ellipse();
else if (CString(_T("line")) == sName) return new Line();
else if (CString(_T("circle")) == sName) return new Circle();
else if (CString(_T("path")) == sName) return new Path();
else if (CString(_T("polyline")) == sName) return new Polyline();
else if (CString(_T("polygon")) == sName) return new Polygon();
else if (CString(_T("text")) == sName) return new Text();
//else if (CString(_T("image")) == sName) return new Image();
else if (CString(_T("use")) == sName) return new Use();
return NULL;
}
};
class Symbol : public RefElement // content element
{
public:
Symbol()
{
m_nodeType = ESymbol;
m_pClip = NULL;
}
virtual ~Symbol()
{
for (size_t i = 0; i < m_arrRefElems.size(); ++i)
RELEASEOBJECT (m_arrRefElems[i]);
m_arrRefElems.clear();
}
virtual bool FromXml(XmlUtils::CXmlNode& oXmlNode, IRefStorage* pStorage, UnitSystem& oUs)
{
RefElement::FromXml (oXmlNode, pStorage, oUs);
m_oViewBox.FromXml (oXmlNode);
return true;
}
inline void AddContent(DrawElement* pReference) // õðàíèì äàííûå, ïîýòîìó ñàìè è î÷èùàåì äàííûå
{
if (pReference)
{
m_arrRefElems.push_back (pReference);
}
}
inline long GetCount() const
{
return (long)m_arrRefElems.size();
}
inline DrawElement* GetAt(long nInd)
{
return m_arrRefElems[nInd];
}
// RefElement
virtual bool RefreshXLinkSource(IRefStorage* pStorage) // NOT IMPLEMENTED
{
return 0;
}
virtual bool Normalize(const double& dAddFMX, const double& dAddFMY) // NOT IMPLEMENTED
{
return 0;
}
public:
ViewBox m_oViewBox;
std::vector<DrawElement*> m_arrRefElems;
};
class ClipPath : public RefElement // content element
{
public:
ClipPath()
{
m_nodeType = EClipPath;
m_pClip = NULL;
}
virtual ~ClipPath()
{
for (size_t i = 0; i < m_clips.size(); ++i)
RELEASEOBJECT (m_clips[i]);
m_clips.clear();
}
virtual bool FromXml (XmlUtils::CXmlNode& oXml, IRefStorage* pStorage, UnitSystem& oUs)
{
RefElement::FromXml (oXml, pStorage, oUs);
Explore(oXml);
return true;
}
inline long GetCount ()
{
return (long)m_clips.size();
}
inline ISvgRef* GetAt (long nInd)
{
return m_clips[nInd];
}
// RefElement
virtual bool RefreshXLinkSource (IRefStorage* pStorage) // NOT IMPLEMENTED
{
return 0;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
for (size_t i = 0; i < m_clips.size(); ++i)
m_clips[i]->Normalize(dAfX, dAfY);
return true;
}
protected:
inline bool Explore (XmlUtils::CXmlNode& oXml)
{
Load (oXml);
//if (oXml.HasChildNodes())
{
//XmlUtils::CXmlNodes pXmlNodes = NULL;
//if (oXml.GetNodes (pXml))
{
XmlUtils::CXmlNodes oXmlNodes;
if (oXml.GetNodes(_T("*"), oXmlNodes))
{
for (long i = 0; i < oXmlNodes.GetCount(); ++i)
{
XmlUtils::CXmlNode oChild;
if (oXmlNodes.GetAt(i, oChild))
{
if (!Explore(oChild))
{
return false;
}
}
}
}
}
}
return true;
}
inline bool Load (XmlUtils::CXmlNode& oXml)
{
if (L"clipPath" == oXml.GetName ())
return false;
#if defined(_DEBUG) && (defined(_WIN32) || defined(_WIN64))
ATLTRACE (L"[svg] ClipPath-NodeName : %ls\n", oXml.GetName());
#endif
DrawElement* pClip = m_oBuilder.Build (oXml.GetName());
if (pClip)
{
pClip->FromXml(oXml,m_oUs);
m_clips.push_back (pClip);
return true;
}
return false;
}
protected:
std::vector <DrawElement*> m_clips;
DrawBuilder m_oBuilder;
UnitSystem m_oUs;
};
class Pattern : public RefElement, public IRefStorage // content element
{
public:
Pattern()
{
m_nodeType = EPattern;
m_pClip = NULL;
}
virtual ~Pattern()
{
for (size_t i = 0; i < m_elements.size(); ++i)
RELEASEOBJECT (m_elements[i]);
m_elements.clear();
}
virtual bool FromXml(XmlUtils::CXmlNode& oXml, IRefStorage* model, UnitSystem& oUs)
{
m_rect.X = DoubleValue(oXml, _T("x"), oUs, c_dirHorizontal);
m_rect.Y = DoubleValue(oXml, _T("y"), oUs, c_dirVertical);
m_rect.Width = DoubleValue(oXml, _T("width"), oUs, c_dirHorizontal);
m_rect.Height = DoubleValue(oXml, _T("height"), oUs, c_dirVertical);
m_patternUnits = oXml.GetAttributeOrValue(_T("patternUnits"), _T(""));
m_preserveAspectRatio = oXml.GetAttributeOrValue(_T("preserveAspectRatio"), _T(""));
m_model = model;
RefElement::FromXml (oXml, model, oUs);
m_oViewBox.FromXml (oXml);
Explore(oXml);
//Pattern::FromXml (oXml, m_model, oUs);
return true;
}
// RefElement
virtual bool RefreshXLinkSource(IRefStorage* pStorage) // NOT IMPLEMENTED
{
return 0;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
//for (size_t i = 0; i < m_elements.size(); ++i)
// m_elements[i]->Normalize(dAfX, dAfY);
return true;
}
//
virtual ISvgRef* Get(long index)
{
return m_elements[index];
}
virtual long GetSize()
{
return (long)m_elements.size();
}
// NOT IMPLEMENTED
virtual bool HashRef(ISvgRef* pRef, bool bDef)
{
return false;
}
// NOT IMPLEMENTED
virtual bool GetRef(const CString& ID, ISvgRef*& pRef)
{
return false;
}
// NOT IMPLEMENTED
virtual bool Push(ISvgRef* pRef)
{
return false;
}
//
inline const ViewBox& GetBox() const
{
return m_oViewBox;
}
inline const Rect& GetBound() const
{
return m_rect;
}
inline const CString& PreserveAspectRatio() const
{
return m_preserveAspectRatio;
}
inline bool NormalizeEx(const double& dAfX, const double& dAfY)
{
for (size_t i = 0; i < m_elements.size(); ++i)
m_elements[i]->Normalize(dAfX, dAfY);
return true;
}
protected:
inline bool Explore(XmlUtils::CXmlNode& oXml)
{
Load (oXml);
//if (oXml.HasChildNodes())
{
//XML::IXMLDOMNodeListPtr pXmlNodes = NULL;
//if (oXml.GetNodes (pXmlNodes))
{
XmlUtils::CXmlNodes oXmlNodes;
if (oXml.GetNodes (_T("*"), oXmlNodes))
{
for (long i = 0; i < oXmlNodes.GetCount(); ++i)
{
XmlUtils::CXmlNode oChild;
if (oXmlNodes.GetAt(i, oChild))
{
if (!Explore(oChild))
{
return false;
}
}
}
}
}
}
return true;
}
inline bool Load(XmlUtils::CXmlNode& oXml)
{
#if defined(_DEBUG) && (defined(_WIN32) || defined(_WIN64))
ATLTRACE (L"[svg] Pattern-NodeName : %ls\n", oXml.GetName());
#endif
DrawElement* element = m_oBuilder.Build (oXml.GetName());
if (element)
{
Style oStyle = m_oStyle;
FontStyle oFontStyle = m_oFontStyle;
CString css = oXml.GetAttribute(_T("style"));
if (css.GetLength())
{
oStyle.SetStyle(css, false, m_oUs, NULL, m_oColTable);
oFontStyle.SetStyle(css, false);
}
else
{
oStyle.UpdateStyle(oXml, m_oUs, NULL, m_oColTable);
oFontStyle.UpdateStyle(oXml);
}
m_oUs.SetFontSizeForEM(oFontStyle.DoubleAttribute(FontSize));
element->SetStyle(oStyle);
if (EText == element->nodeType())
{
Text* pText = static_cast<Text*>(element);
if (pText)
{
pText->m_oFontStyle = oFontStyle;
}
}
CString transform = oXml.GetAttribute(_T("transform"));
if (transform.GetLength())
{
m_transforms.Push(Matrix(transform, m_oUs));
element->SetTransform(m_transforms.GetTop());
m_transforms.Pop();
}
else
{
element->SetTransform(m_transforms.GetTop());
}
element->FromXml(oXml,m_oUs);
m_elements.push_back (element);
return true;
}
return false;
}
protected:
std::vector <DrawElement*> m_elements;
DrawBuilder m_oBuilder;
UnitSystem m_oUs;
ColorTable m_oColTable;
Style m_oStyle;
FontStyle m_oFontStyle;
MatrixStack m_transforms;
ViewBox m_oViewBox;
Rect m_rect;
CString m_patternUnits;
CString m_preserveAspectRatio;
};
//class PatternImage
//{
//public:
// PatternImage() : m_pattern(NULL), m_baseRender(NULL), m_render(NULL)
// {
// //m_pPatternFrame = NULL;
// }
// PatternImage(Pattern* pattern, Painter* basePainter) : m_render(NULL), m_pattern(pattern), m_basePainter(basePainter)
// {
// //m_pPatternFrame = NULL;
// }
// ~PatternImage()
// {
// //RELEASEINTERFACE(m_render);
// //RELEASEINTERFACE(m_pFrame);
// //RELEASEINTERFACE(m_pPatternFrame);
// if (m_sLivePath.GetLength())
// {
// DeleteFile(m_sLivePath);
// }
// }
// inline const CString& LivePath()
// {
// Build();
// return m_sLivePath;
// }
//private:
// bool Build();
// bool InitFrame();
// bool InitPatternFrame();
// bool InitRender(void *render, int frameWidth, int frameHeight);
// bool Render();
// //bool SaveImage(IUnknown* punkFrame, CString file);
// Point GetNormalizeFactor();
//private:
// IRenderer *m_render;
// //IAVSGraphicsRenderer* m_render;
// //MediaCore::IAVSUncompressedVideoFrame* m_pFrame;
// //MediaCore::IAVSUncompressedVideoFrame* m_pPatternFrame;
// CString m_sLivePath;
// Pattern* m_pattern;
// Painter* m_basePainter;
//};
class DefsBuilder
{
public:
RefElement* Build (const CString& sName)
{
if (CString (L"linearGradient") == sName) return new LinearGradient ();
else if (CString (L"radialGradient") == sName) return new RadialGradient ();
else if (CString(L"symbol")== sName) return new Symbol();
else if (CString(L"clipPath") == sName) return new ClipPath();
else if (CString(L"pattern") == sName) return new Pattern();
return NULL;
}
};
class GraphicsContainer : public DrawElement, public IRefStorage
{
public:
GraphicsContainer(bool bRefMode = false) // ïîä÷èùàåò ññûëêè íà îáúåêòû
{
m_nodeType = EGraphicsContainer;
m_pClip = NULL;
m_bRefMode = bRefMode;
m_bAddNormMM = false;
}
virtual ~GraphicsContainer()
{
GraphicsContainer::Clear ();
}
virtual bool FromXml(XmlUtils::CXmlNode& oXmlNode, IRefStorage* model, const ViewBox& oViewBox, const UnitSystem& oUnitSystem, const Matrix& oTransform)
{
m_model = model;
m_oViewBox = oViewBox;
m_oUs = oUnitSystem;
m_pClip = NULL;
m_urlClipPath = oXmlNode.GetAttribute(_T("clip-path"));
StrUtils::UrlRefValue2(m_urlClipPath);
m_transforms.Push(oTransform);
DrawElement::FromXml(oXmlNode, m_oUs);
UpdateMainStyle(oXmlNode);
UpdateMainTransform(oXmlNode);
Explore(oXmlNode);
m_model->HashRef(this, false);
m_oTransform = m_transforms.GetFinal();
return true;
}
virtual bool FromString(CString Str, IRefStorage* model)
{
return false;
}
virtual bool RefreshXLinkSource(IRefStorage* model)
{
return false;
}
// storage
inline ISvgRef* Get(long index)
{
if (index > (long)m_arrGroup.size())
return NULL;
return m_arrGroup[index];
}
inline long GetSize()
{
return (long)(m_arrGroup.size());
}
virtual bool Normalize(const double& dAddFMX, const double& dAddFMY)
{
if ( false == m_bAddNormMM )
{
for ( long i = 0; i < (long)m_arrGroup.size(); ++i )
{
ISvgRef* pE = m_arrGroup [ i ];
if ( pE )
{
pE->Normalize ( dAddFMX, dAddFMY );
}
}
}
m_bAddNormMM = true;
return true;
}
inline void Add(ISvgRef* element)
{
if (m_bRefMode)
{
m_arrGroup.push_back(element);
}
}
private:
// NOT IMPLEMENTED
virtual bool Push (ISvgRef* Elem)
{
return false;
}
virtual bool HashRef (ISvgRef* pElem, bool bDef)
{
return false;
}
virtual bool GetRef (const CString& ID, ISvgRef*& pElem)
{
return false;
}
private:
inline bool Explore (XmlUtils::CXmlNode& oXmlNode)
{
LoadElement ( oXmlNode );
//if ( oXmlNode.HasChildNodes () )
{
//XML::IXMLDOMNodeListPtr pXmlNodes = NULL;
//if ( oXmlNode.GetNodes ( pXmlNodes ) )
{
XmlUtils::CXmlNodes oXmlNodes;
if ( oXmlNode.GetNodes(_T("*"), oXmlNodes ) )
{
for ( long i = 0; i < oXmlNodes.GetCount(); ++i )
{
XmlUtils::CXmlNode oXmlNode2;
if ( oXmlNodes.GetAt ( i, oXmlNode2 ) )
{
if ( _T("g") == oXmlNode2.GetName() )
{
GraphicsContainer* pContainer = new GraphicsContainer();
if ( pContainer )
{
pContainer->FromXml(oXmlNode2, m_model, m_oViewBox, m_oUs, m_transforms.GetFinal());
m_model->HashRef(pContainer, false);
m_arrGroup.push_back(pContainer);
continue;
}
// return true;
}
if ( false == Explore ( oXmlNode2 ) )
{
return false;
}
}
}
}
}
}
return true;
}
inline bool LoadElement (XmlUtils::CXmlNode& oXml, bool Defines = false)
{
CString strXmlNode = oXml.GetName();
RefElement* pReference = m_oDefsBuilder.Build(strXmlNode);
if (pReference)
{
if (EPattern == pReference->nodeType())
{
((Pattern*)pReference)->FromXml(oXml, m_model, m_oUs);
}
else
{
pReference->FromXml(oXml, m_model, m_oUs);
}
if (m_model->HashRef(pReference, true))
UpdateSymbol(pReference, oXml);
#if defined(_DEBUG) && (defined(_WIN32) || defined(_WIN64))
ATLTRACE(L"[svg] ref element (g) - : %ls\n", strXmlNode);
#endif
return true;
}
if (NULL == Create(oXml))
return false;
return true;
}
inline DrawElement* Create(XmlUtils::CXmlNode& oXml, bool bAddStorage = true)
{
CString strXmlNode = oXml.GetName();
#if defined(_DEBUG) && (defined(_WIN32) || defined(_WIN64))
ATLTRACE(L"[svg] render element (g) - : %ls\n", strXmlNode);
#endif
DrawElement* element = m_oDrawBuilder.Build(strXmlNode);
if (element)
{
Style oStyle = m_oStyle;
FontStyle oFontStyle = m_oFontStyle;
CString css = oXml.GetAttribute(_T("style"));
if (css.GetLength())
{
oStyle.SetStyle(css, false, m_oUs, m_model, m_oColTable);
oFontStyle.SetStyle(css, false);
}
else
{
oStyle.UpdateStyle(oXml, m_oUs, m_model, m_oColTable);
oFontStyle.UpdateStyle(oXml);
}
m_oUs.SetFontSizeForEM(oFontStyle.DoubleAttribute(FontSize));
element->SetStyle(oStyle);
if (EText == element->nodeType())
{
Text* pText = static_cast<Text*>(element);
if (pText)
{
pText->m_oFontStyle = oFontStyle;
}
}
CString transform = oXml.GetAttribute(_T("transform"));
if (transform.GetLength())
{
m_transforms.Push(Matrix(transform, m_oUs));
element->SetTransform(m_transforms.GetTop());
m_transforms.Pop();
}
else
{
element->SetTransform(m_transforms.GetTop());
}
element->FromXml(oXml, m_oUs);
// ATLTRACE(L"GraphicsContainer : %ls - push : %ls\n", m_nodeId, oXmlNode.GetName());
if (bAddStorage)
m_arrGroup.push_back(element);
return element;
}
return NULL;
}
inline void UpdateMainTransform (XmlUtils::CXmlNode& oXml)
{
CString css = oXml.GetAttribute(_T("transform"));
if (css.GetLength())
{
Matrix oTransform(css, m_oUs);
m_transforms.Push(oTransform);
}
else
{
m_transforms.Push(Matrix());
}
}
inline void UpdateMainStyle (XmlUtils::CXmlNode& oXml)
{
CString css = oXml.GetAttribute(_T("style"));
if (css.GetLength())
{
m_oFontStyle.SetStyle(css, true);
m_oStyle.SetStyle(css, true, m_oUs, m_model, m_oColTable);
}
else
{
m_oFontStyle.UpdateStyle(oXml);
m_oStyle.UpdateStyle(oXml, m_oUs, m_model, m_oColTable);
}
}
inline void Clear()
{
if (!m_bRefMode)
{
for (long i = 0; i < (long)m_arrGroup.size(); ++i)
RELEASEOBJECT(m_arrGroup[i]);
}
m_arrGroup.clear();
}
//
inline void UpdateSymbol(RefElement* pReference, XmlUtils::CXmlNode& oXml)
{
if (ESymbol == pReference->nodeType())
{
//if (oXml.HasChildNodes())
{
//XML::IXMLDOMNodeListPtr pXmlNodes = NULL;
//if (oXml.GetNodes(pXmlNodes))
{
XmlUtils::CXmlNodes oXmlNodes;
if (oXml.GetNodes(_T("*"), oXmlNodes))
{
for (long i = 0; i < oXmlNodes.GetCount(); ++i)
{
XmlUtils::CXmlNode oXml2;
if (oXmlNodes.GetAt(i,oXml2))
{
((Symbol*)pReference)->AddContent(Create(oXml2, false));
}
}
}
}
}
}
}
private:
bool m_bRefMode;
bool m_bAddNormMM;
std::vector <ISvgRef*> m_arrGroup;
IRefStorage* m_model;
DrawBuilder m_oDrawBuilder;
DefsBuilder m_oDefsBuilder;
ViewBox m_oViewBox;
UnitSystem m_oUs;
ColorTable m_oColTable;
Style m_oStyle;
FontStyle m_oFontStyle;
MatrixStack m_transforms;
};
}
namespace SVG
{
class Storage : public IRefStorage
{
public:
Storage()
{
m_bAddNormMM = false;
}
virtual ~Storage ()
{
Clear ();
}
inline void Clear ()
{
for (size_t i = 0; i < m_arrGroup.size(); ++i)
{
RELEASEOBJECT(m_arrGroup[i]);
}
m_arrGroup.clear();
m_arrRef.clear();
for (size_t i = 0; i < m_arFlush.size(); ++i)
{
RELEASEOBJECT (m_arFlush[i]);
}
m_arFlush.clear();
}
inline bool JoinXLinkReference()
{
for (std::map<CString, ISvgRef*>::iterator pPair = m_arrRef.begin(); pPair != m_arrRef.end(); pPair++)
{
ISvgRef* pE = static_cast<ISvgRef*>(pPair->second);
if (pE)
{
pE->RefreshXLinkSource (this);
}
}
return true;
}
inline bool JoinClipPathLinks()
{
for (size_t i = 0; i < m_arrGroup.size(); ++i)
{
DrawElement* pRef = static_cast<DrawElement*>(m_arrGroup[i]);
if (pRef)
{
CString clipId = pRef->GetUrlClip();
if (clipId.GetLength())
{
ISvgRef* pClipRef = NULL;
if (GetRef(clipId, pClipRef))
{
pRef->AttachClip (pClipRef);
}
}
}
}
return true;
}
inline bool JoinStyleLinks()
{
for (size_t i = 0; i < m_arrGroup.size(); ++i)
{
DrawElement* pRef = static_cast<DrawElement*>(m_arrGroup[i]);
if (pRef)
{
const Style& style = pRef->GetStyle();
if (style.GetFillUrlRef().GetLength() && (NULL == style.GetFill()))
{
#if defined(_DEBUG) && (defined(_WIN32) || defined(_WIN64))
ATLTRACE (_T("[svg] NEED JOIN FILL STYLE : id - %ls"), pRef->nodeId());
#endif
}
}
}
return true;
}
// IRefStorage
virtual ISvgRef* Get (long index)
{
if (index > (long)m_arrGroup.size())
return NULL;
// ATLTRACE ( _T("get : %ls\n"), m_arrGroup [nIndex]->nodeId () );
return m_arrGroup [index];
}
virtual long GetSize ()
{
return (long)m_arrGroup.size();
}
virtual bool Push (ISvgRef* Elem)
{
// ATLTRACE ( _T("push : %ls\n"), Elem->nodeId () );
if (!Elem) return false;
m_arrGroup.push_back(Elem);
return true;
}
virtual bool HashRef (ISvgRef* element, bool bDef)
{
if (element)
{
if (element->nodeId().GetLength())
{
std::map<CString, ISvgRef*>::iterator pPair = m_arrRef.find(element->nodeId());
if (m_arrRef.end() == pPair)
{
ISvgRef* search = pPair->second;
//ATLTRACE(_T("IRefStorage - Hash : %ls, %d\n"), element->nodeId(), element->nodeType());
m_arrRef.insert(std::pair<CString, ISvgRef*>(element->nodeId(), element));
if (bDef)
{
m_arFlush.push_back (element);
}
// îáúåêòû ñ id ìîãóò áûòü èñïîëüçîâàíû âíå îïèñàíèÿ äðóãèìè ýëåìåíòàìè, ïîýòîìó èõ íàäî ó÷èòûâàòü
InternalHashElements(element);
return true;
}
}
}
return false;
}
virtual bool GetRef (const CString& sId, ISvgRef*& pRef)
{
std::map<CString, ISvgRef*>::iterator pPair = m_arrRef.find (sId);
if (m_arrRef.end() != pPair)
{
pRef = pPair->second;
return true;
}
return false;
}
virtual bool Normalize(const double& dAfX, const double& dAfY)
{
if ( false == m_bAddNormMM )
{
for ( long i = 0; i < (long)m_arrGroup.size(); ++i )
{
ISvgRef* pE = m_arrGroup [ i ];
if ( pE )
{
pE->Normalize(dAfX, dAfY);
}
}
for (std::map<CString, ISvgRef*>::iterator pPair = m_arrRef.begin(); pPair != m_arrRef.end(); pPair++)
{
ISvgRef* pE = static_cast<ISvgRef*>(pPair->second);
if (pE)
{
pE->Normalize(dAfX, dAfY);
}
}
}
m_bAddNormMM = true;
return true;
}
virtual bool RefreshXLinkSource(IRefStorage* pStorage)
{
return false;
}
//
inline void SetWorkingDirectory (const CString& sWorkingDirectory)
{
m_sWorkingDirectory = sWorkingDirectory;
}
private:
inline bool InternalHashElements (ISvgRef* element)
{
bool ret = false;
if (EClipPath == element->nodeType())
{
ClipPath* clip = static_cast<ClipPath*>(element);
if (clip)
{
if (clip->GetCount())
{
for (long i = 0; i < clip->GetCount(); ++i)
{
ISvgRef* ref = clip->GetAt(i);
if (ref)
{
if (ref->nodeId().GetLength())
{
m_arrRef.insert(std::pair<CString, ISvgRef*>(ref->nodeId(), ref));
ret = true;
}
}
}
}
}
}
return ret;
}
private:
bool m_bAddNormMM;
std::vector <ISvgRef*> m_arrGroup;
std::map <CString, ISvgRef*> m_arrRef; // èíäåêñàöèÿ (òîëüêî õðàíåíèÿ ññûëîê)
CString m_sWorkingDirectory;
std::vector<ISvgRef*> m_arFlush; // îáúåêòû êîòîðûå íóæíî óäàëÿòü
};
class Painter
{
public:
Painter()
{
m_pManager = NULL;
m_model = NULL;
m_render = NULL;
m_dpiX = 0.0;
m_dpiY = 0.0;
m_widthMM = 0.0;
m_heightMM = 0.0;
m_bEnableFonts = true;
m_CSS = NULL;
}
~Painter()
{
RELEASEOBJECT(m_pManager);
//POSITION pos = m_patterns.GetStartPosition();
//while (NULL != pos)
//{
// PatternImage* image = m_patterns.GetNextValue(pos);
// RELEASEOBJECT(image);
//}
}
inline void SetWorkingDirectory(const CString& sWorkingDirectory)
{
m_sWorkingDirectory = sWorkingDirectory;
}
inline const CString& GetWorkingDirectory() const
{
return m_sWorkingDirectory;
}
inline const UnitSystem& GetUs() const
{
return m_oUs;
}
inline void SetCSS(CStyleCSS* css)
{
m_CSS = css;
}
bool Draw(IRefStorage* model, IRenderer* render, const UnitSystem& oUs);
private:
bool DrawLine (Line* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawRectangle (Rectangle* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawCircle (Circle* element,const Style& oStyle, const CString& strClassName = _T(""));
bool DrawEllipse (Ellipse* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawPolyline (Polyline* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawPolygon (Polygon* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawPath (Path* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawText (Text* element, const Style& oStyle, const CString& strClassName = _T(""));
//bool DrawImage (Image* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawUse (Use* element, const Style& oStyle, const CString& strClassName = _T(""));
bool DrawStorage (IRefStorage* pStorage, const Matrix& parentTransform = Matrix(), const Point& off = Point());
bool DrawGraphicsContainer (GraphicsContainer* element, const Matrix& parentTransform = Matrix(), const Point& off = Point());
bool DrawInternal (DrawElement* pE, const Matrix& parentTransform, const Point& off, const Style& oMainStyle);
bool SetBrushStyle (const Style& style, const CString& strClassName = _T(""));
bool SetStrokeStyle (const Style& style, const CString& strClassName = _T(""));
// commands only
void DoRectangle(Rectangle* element, long type, bool clipMode = false);
void DoCircle(Circle* element, long type, bool clipMode = false);
void DoEllipse(Ellipse* element, long type, bool clipMode = false);
void DoPolyline(Polyline* element, long type, bool clipMode = false);
void DoPolygon(Polygon* element, long type, bool clipMode = false);
void DoPath(Path* element, long type, bool clipMode = false);
// clip
bool DoClip(ISvgRef* pRef, bool enable);
inline ISvgRef* FindEntry(Use* element)
{
if (element)
{
element->RefreshXLinkSource (m_model);
ISvgRef* refLink = element->GetRefLink();
if (refLink)
{
ENodeType code = refLink->nodeType();
if (EUse == refLink->nodeType())
return FindEntry(static_cast<Use*>(refLink));
return refLink;
}
}
return NULL;
}
// image
//bool DrawImageFromFile(Image* element, CString texturePath = L"");
//bool DoPattern(Pattern* element);
// path
bool PushPathCommands(Path* element, long PathType);
bool ClipPathCommands(Path* element, long PathType);
private:
// for arc render
inline bool RenderArcAppx(const double& dRotAngle, const Point& Center, Point Radi, const double& dStartAngle, const double& dSweep)
{
if (0.0 != dRotAngle)
{
Matrix rotate = Matrix::RotateAtPoint(Point(Center.X, Center.Y), -dRotAngle * M_PI / 180);
CArcToCubicBezier oSplitter(Center.X - Radi.X, Center.Y - Radi.Y, Radi.X * 2.0, Radi.Y * 2.0, dStartAngle - dRotAngle, dSweep);
for (int i = 0; i < oSplitter.GetCurves().size(); ++i)
{
CubicBezier oBezier = oSplitter.GetCurves()[i];
Point oPointU = rotate.TranformPoint(oBezier.m_Points[0]);
Point oPointV = rotate.TranformPoint(oBezier.m_Points[1]);
Point oPointE = rotate.TranformPoint(oBezier.m_Points[2]);
m_render->PathCommandCurveTo(oPointU.X, oPointU.Y, oPointV.X, oPointV.Y, oPointE.X, oPointE.Y);
}
}
else
{
m_render->PathCommandArcTo(Center.X - Radi.X, Center.Y - Radi.Y, Radi.X * 2.0, Radi.Y * 2.0, dStartAngle, dSweep);
}
return true;
}
inline bool ClipArcAppx(Aggplus::CGraphicsPathSimpleConverter& simplifier, const double& dRotAngle, const Point& Center, Point Radi, const double& dStartAngle, const double& dSweep)
{
if (0.0 != dRotAngle)
{
Matrix rotate = Matrix::RotateAtPoint(Point(Center.X, Center.Y), -dRotAngle * M_PI / 180);
CArcToCubicBezier oSplitter(Center.X - Radi.X, Center.Y - Radi.Y, Radi.X * 2.0, Radi.Y * 2.0, dStartAngle - dRotAngle, dSweep);
for (int i = 0; i < oSplitter.GetCurves().size(); ++i)
{
CubicBezier oBezier = oSplitter.GetCurves()[i];
Point oPointU = rotate.TranformPoint(oBezier.m_Points[0]);
Point oPointV = rotate.TranformPoint(oBezier.m_Points[1]);
Point oPointE = rotate.TranformPoint(oBezier.m_Points[2]);
simplifier.PathCommandCurveTo(oPointU.X, oPointU.Y, oPointV.X, oPointV.Y, oPointE.X, oPointE.Y);
}
}
else
{
simplifier.PathCommandArcTo(Center.X - Radi.X, Center.Y - Radi.Y, Radi.X * 2.0, Radi.Y * 2.0, dStartAngle, dSweep);
}
return true;
}
static double GetAngle(const double& CX, const double& CY, const double& X, const double& Y);
static Point GetCenter(int LargeFlag, int SweepFlag, Point Radi, Point P1, Point P2);
static bool GetArcAngles(int LargeFlag, int SweepFlag, const double& dStartAngle, const double& dEndAngle, double& dSweep);
inline CFontManager* GetFontManager()
{
if (m_pManager == NULL)
m_pManager = new CFontManager();
return m_pManager;
}
inline void UpdateClass(DrawElement* element)
{
if (element)
{
if (element->ClassName().GetLength ())
{
//m_render->SetAdditionalParam(L"AttributeClassName", vt);
}
}
}
inline Style ComposeStyles(DrawElement* element, const Style& style)
{
Style composeStyle = style;
if (m_CSS)
{
Style elementStyle;
if (m_CSS->GetStyleForType(element->nodeType(), elementStyle))
{
if (elementStyle.IsCSS())
{
Style::UpdateValidateAttributes(elementStyle, composeStyle);
}
}
Style classStyle;
if (m_CSS->GetClassStyle(element->ClassName(), classStyle))
{
Style::UpdateValidateAttributes(classStyle, composeStyle);
}
}
return composeStyle;
}
private:
IRenderer* m_render;
CFontManager* m_pManager;
IRefStorage* m_model;
UnitSystem m_oUs;
double m_dAddMX;
double m_dAddMY;
double m_dpiX;
double m_dpiY;
double m_widthMM;
double m_heightMM;
MatrixStack m_transforms;
bool m_bEnableFonts;
CString m_sWorkingDirectory;
//std::map<CString, PatternImage*> m_patterns;
CStyleCSS* m_CSS;
};
}
namespace SVG
{
class ENTITY
{
public:
ENTITY()
{
}
inline bool Read (const CString& sTag)
{
int at = sTag.Find(_T("\""));
int to = sTag.Find(_T("\""), at + 1);
if (-1 != at && -1 != to)
{
CString strTemp = sTag.Mid(at + 1, to - at - 1);
m_sValue = StrUtils::RemoveSpaces(strTemp);
strTemp = sTag.Mid(0, at - 1);
m_sName = StrUtils::RemoveSpaces(strTemp);
return true;
}
return false;
}
inline const CString& GetName() const
{
return m_sName;
}
inline const CString& GetValue() const
{
return m_sValue;
}
private:
CString m_sName;
CString m_sValue;
};
class DOCTYPE
{
public:
DOCTYPE()
{
}
inline bool Read (const CString& sTag)
{
if (sTag.GetLength())
{
// READ TAG - <!ENTITY
int at = sTag.Find(_T("<!ENTITY"));
if (-1 == at) return false;
int to = sTag.Find(_T(">"), at);
if (-1 == to) return false;
int length = CString("<!ENTITY").GetLength();
if (-1 != at)
{
ENTITY entity;
if (entity.Read(sTag.Mid(at + length, to - at - length)))
m_ENTITY.push_back(entity);
while(-1 != at)
{
at = sTag.Find(_T("<!ENTITY"), to);
if (-1 == at) break;
to = sTag.Find(_T(">"), at);
if (-1 == to) break;
ENTITY entity;
if (entity.Read(sTag.Mid(at + length, to - at - length)))
m_ENTITY.push_back(entity);
}
}
if (m_ENTITY.size())
return true;
}
return false;
}
template <typename T>
bool ConnectEntities(T & sXml)
{
if (m_ENTITY.size())
{
std::vector<T> subStrings;
T and1 = T(CString(L"&"));
T sem = T(CString(L";"));
int at = sXml.Find(and1);
if (-1 == at) return false;
int to = sXml.Find(sem, at);
if (-1 == to) return false;
while (-1 != at && -1 != to)
{
T replace = sXml.Mid(at + 1, to - at - 1);
subStrings.push_back(replace);
at = sXml.Find(and1, to);
if (-1 == at) break;
to = sXml.Find(sem, at);
if (-1 == to) break;
}
if (subStrings.size())
{
for (long i = (long)subStrings.size() - 1; i >= 0; --i)
{
T str = and1 + T(subStrings[i]) + sem;
sXml.Replace(str, GetVal(CString(subStrings[i])));
}
return true;
}
}
return false;
}
inline CString GetVal(const CString& sName) const
{
for (size_t i = 0; i < m_ENTITY.size(); ++i)
{
if (sName == m_ENTITY[i].GetName())
{
return m_ENTITY[i].GetValue();
}
}
return CString(_T(""));
}
inline CString GetAt(long index, long type = 0) const
{
if (index >= (long)m_ENTITY.size())
return CString(_T(""));
return m_ENTITY[index].GetValue();
}
//
inline void Clear()
{
m_ENTITY.clear();
}
private:
std::vector<ENTITY> m_ENTITY; // <!ENTITY
};
class Parser
{
public:
Parser ()
{
m_model = NULL;
m_nWidth = 0;
m_nHeight = 0;
m_nLayerLevel = 0;
m_bDefinesLayer = false;
m_nDefsLayer = 0;
m_nDefWidth = 800;
m_nDefHeight = 600;
}
~Parser ()
{
}
//inline bool LoadFromFile (const CString& strFile, Storage* model)
//{
// if (model)
// {
// m_model = model;
// CStringA sXmlA;
// if (StringHelpers::LoadXmlFile(strFile, sXmlA))
// {
// if (m_DOCTYPE.Read(CString(sXmlA)))
// {
// m_DOCTYPE.ConnectEntities<CStringA>(sXmlA);
// m_DOCTYPE.Clear();
// }
// if (sXmlA.GetLength())
// {
// StringHelpers::RemoveTagHTMLA (sXmlA, CStringA("<!ENTITY"), CStringA(">"));
// StringHelpers::RemoveTagHTMLA (sXmlA, CStringA("<!DOCTYPE"), CStringA(">"));
// StringHelpers::RemoveCommentsA (sXmlA);
// }
// CString sXml = XmlUtils::ConvertToUnicode(sXmlA);
// return LoadFromString(XmlUtils::ConvertToUnicode(sXmlA), model);
// }
// }
// return false;
//}
inline bool LoadFromString (const CString& strXml, SVG::Storage* model)
{
if (model)
{
m_model = model;
CString sXml = strXml;
if (m_DOCTYPE.Read(sXml))
{
m_DOCTYPE.ConnectEntities<CString>(sXml);
m_DOCTYPE.Clear();
}
if (sXml.GetLength())
{
StringHelpers::RemoveTagHTML (sXml, CString(L"<!ENTITY"), CString(L">"));
StringHelpers::RemoveTagHTML (sXml, CString(L"<!DOCTYPE"), CString(L">"));
StringHelpers::RemoveComments (sXml);
}
XmlUtils::CXmlNode oXml;
if (oXml.FromXmlString(sXml))
{
m_nLayerLevel = 0;
if (Explore(oXml))
{
m_model->JoinXLinkReference();
m_model->JoinClipPathLinks();
m_model->JoinStyleLinks();
return true;
}
}
}
return false;
}
inline bool Explore (XmlUtils::CXmlNode& oXml)
{
CString strXmlNode = oXml.GetName();
// ATLTRACE ( L"%ls\n", strXmlNode);
bool ExploreLayer = false;
bool readInnerNodes = true;
if (m_bDefinesLayer)
++m_nDefsLayer;
if (_T("svg") == strXmlNode)
{
m_oViewBox.FromXml (oXml);
m_Metrics = StrUtils::GetMetrics(oXml.GetAttribute(_T("width")));
if (PCT == m_Metrics && m_oViewBox.m_bInUse)
{
if (0 == (int)m_oViewBox.m_nWidth && 0 == (int)m_oViewBox.m_nHeight)
{
return false;
}
m_nWidth = m_oViewBox.m_nWidth;
m_nHeight = m_oViewBox.m_nHeight;
if (0 == (int)m_oViewBox.m_nWidth)
m_nWidth = (std::max) (m_oViewBox.m_nWidth, m_oViewBox.m_nHeight);
if (0 == (int)m_oViewBox.m_nHeight)
m_nHeight = (std::max) (m_oViewBox.m_nWidth, m_oViewBox.m_nHeight);
}
else
{
m_nWidth = static_cast<long>(m_oUs.GetPX(StrUtils::DoubleValue(oXml.GetAttribute(_T("width"))), m_Metrics));
m_nHeight = static_cast<long>(m_oUs.GetPX(StrUtils::DoubleValue(oXml.GetAttribute(_T("height"))), m_Metrics));
}
m_oUs.SetViewBox(m_nWidth, m_nHeight, m_oViewBox, m_Metrics);
SetDefaultSizes ();
}
else if (_T("g") == strXmlNode)
{
if (m_bDefinesLayer)
{
GraphicsContainer* pContainer = new GraphicsContainer ();
if (pContainer)
{
pContainer->FromXml(oXml, m_model, m_oViewBox, m_oUs, Matrix());
m_model->HashRef(pContainer, false);
}
--m_nDefsLayer;
if (0 == m_nDefsLayer)
m_bDefinesLayer = false;
return true;
}
// ATLTRACE ( L"Node : %ls\n", oXml.GetName() );
ExploreLayer = true;
++m_nLayerLevel;
CString ID = oXml.GetAttribute ( _T("id") );
CString XmlTransform = oXml.GetAttribute ( _T("transform") );
if (XmlTransform.GetLength ())
{
Matrix oTransform(XmlTransform, m_oUs);
m_transforms.Push(oTransform);
}
else
{
m_transforms.Push(Matrix());
}
// m_oStyle.SetDefault ();
m_oStyle.ClearFillColor();
CString css = oXml.GetAttribute(_T("style"));
if (css.GetLength())
{
m_oFontStyle.SetStyle (css, true);
m_oStyle.SetStyle (css, true, m_oUs, m_model, m_oColTable);
}
else
{
m_oFontStyle.UpdateStyle (oXml);
m_oStyle.UpdateStyle (oXml, m_oUs, m_model, m_oColTable);
}
m_oStyles.Push(m_oStyle);
m_transforms.Pop();
GraphicsContainer* pContainer = new GraphicsContainer();
if (pContainer)
{
pContainer->FromXml (oXml, m_model, m_oViewBox, m_oUs, m_transforms.GetFinal());
m_model->Push(pContainer);
return true;
}
}
else if (_T("xml") == strXmlNode)
{
XmlUtils::CXmlNode oXmlSub;
if (oXml.GetNode(_T("*"), oXmlSub))
{
if (false == Explore(oXmlSub))
return false;
}
}
else if ( _T("defs") == strXmlNode)
{
m_bDefinesLayer = true;
m_nDefsLayer++;
}
else if ( _T("style") == strXmlNode)
{
if (_T("text/css") == oXml.GetAttribute(_T("type")))
{
m_CSS.Read(oXml, m_oUs, m_model, m_oColTable);
}
}
else
{
LoadElement(oXml);
if (_T("clipPath") == strXmlNode && !m_bDefinesLayer)
return true;
if (_T("pattern") == strXmlNode && m_bDefinesLayer)
readInnerNodes = false;
if ( _T("symbol") == strXmlNode) // êîíòåíò õðàíèòñÿ â ñîîòâåòñòâóþùåì êëàññå
return true;
}
if (readInnerNodes/* && oXml.HasChildNodes()*/)
{
//XML::IXMLDOMNodeListPtr pXmlNodes = NULL;
//if (oXml.GetNodes(pXmlNodes))
{
XmlUtils::CXmlNodes oXmlNodes;
if (oXml.GetNodes(_T("*"), oXmlNodes))
{
for (long i = 0; i < oXmlNodes.GetCount(); ++i)
{
XmlUtils::CXmlNode oXmlNode2;
if (oXmlNodes.GetAt(i, oXmlNode2))
{
if (false == Explore(oXmlNode2))
{
if (m_bDefinesLayer)
{
--m_nDefsLayer;
if (0 == m_nDefsLayer)
m_bDefinesLayer = false;
}
return false;
}
}
}
}
}
}
if (ExploreLayer)
{
m_transforms.Pop ();
m_oStyles.Pop();
--m_nLayerLevel;
}
if (m_bDefinesLayer)
{
--m_nDefsLayer;
if ( 0 == m_nDefsLayer )
m_bDefinesLayer = false;
}
return true;
}
public:
inline long GetWidth() const
{
return m_nWidth;
}
inline long GetHeight() const
{
return m_nHeight;
}
inline Metrics GetMetics() const
{
return m_Metrics;
}
inline const UnitSystem& GetUnitSystem ()
{
return m_oUs;
}
inline CStyleCSS* GetCSS()
{
if (m_CSS.IsValid())
return &m_CSS;
return NULL;
}
//
inline void SetDefaultWidth(const long& Width)
{
m_nDefWidth = Width;
}
inline void SetDefaultHeight(const long& Height)
{
m_nDefHeight = Height;
}
inline void SetWorkingDirectory(const CString& sWorkingDirectory)
{
m_sWorkingDirectory = sWorkingDirectory;
}
private:
inline bool LoadElement(XmlUtils::CXmlNode& oXml, bool Defines = false)
{
CString strXmlNode = oXml.GetName();
if (strXmlNode.GetLength())
{
if (L'#' == strXmlNode[0])
return false;
}
// ATLTRACE ( L"LoadElement : %ls\n", strXmlNode );
if (m_model)
{
RefElement* pReference = m_oDefsBuilder.Build (strXmlNode);
if (pReference)
{
if (EPattern == pReference->nodeType())
{
((Pattern*)pReference)->FromXml (oXml, m_model, m_oUs);
}
else
{
pReference->FromXml (oXml, m_model, m_oUs);
}
if (m_model->HashRef (pReference, true))
UpdateSymbol (pReference, oXml);
return true;
}
if (m_bDefinesLayer)
{
DrawElement* paintElem = Create (oXml, false);
if (paintElem)
{
if (m_model->HashRef (paintElem, false))
{
}
}
return true;
}
Create (oXml);
}
return false;
}
inline DrawElement* Create(XmlUtils::CXmlNode& oXmlNode, bool bAddStorage = true)
{
CString strXmlNode = oXmlNode.GetName();
if (strXmlNode.GetLength())
{
if (L'#' == strXmlNode[0])
return false;
}
#if defined(_DEBUG) && (defined(_WIN32) || defined(_WIN64))
ATLTRACE (L"[svg] render element : %ls\n", strXmlNode);
#endif
DrawElement* element = m_oDrawBuilder.Build (strXmlNode);
if (element)
{
Style oTopStyle = m_oStyles.GetTop();
Style oStyle = m_oStyle;
oStyle.ClearOpacity ();
FontStyle oFontStyle = m_oFontStyle;
CString css = oXmlNode.GetAttribute (_T("style"));
if (css.GetLength())
{
oStyle.UpdateStyle(oXmlNode, m_oUs, m_model, m_oColTable);
oStyle.SetStyle(css, false, m_oUs, m_model, m_oColTable);
oFontStyle.SetStyle(css, false);
}
else
{
oStyle.UpdateStyle(oXmlNode, m_oUs, m_model, m_oColTable);
oFontStyle.UpdateStyle(oXmlNode);
}
m_oUs.SetFontSizeForEM(oFontStyle.DoubleAttribute(FontSize));
oStyle.Combine(oTopStyle);
element->SetStyle(oStyle);
if (EText == element->nodeType())
{
Text* pText = static_cast<Text*>(element);
if (pText)
pText->m_oFontStyle = oFontStyle;
}
CString transforms = oXmlNode.GetAttribute(_T("transform"));
if (transforms.GetLength())
{
Matrix transform(transforms, m_oUs);
m_transforms.Push(transform);
element->SetTransform(m_transforms.GetTop());
m_transforms.Pop ();
}
else
{
element->SetTransform(m_transforms.GetTop());
}
element->FromXml(oXmlNode, m_oUs);
if (bAddStorage)
m_model->Push(element);
return element;
}
return NULL;
}
inline void UpdateSymbol(RefElement* pReference, XmlUtils::CXmlNode& oXml)
{
if (ESymbol == pReference->nodeType())
{
//if (oXml.HasChildNodes())
{
//XML::IXMLDOMNodeListPtr pXmlNodes = NULL;
//if (oXml.GetNodes(pXmlNodes))
{
XmlUtils::CXmlNodes oXmlNodes;
if (oXml.GetNodes(_T("*"), oXmlNodes))
{
for (long i = 0; i < oXmlNodes.GetCount(); ++i)
{
XmlUtils::CXmlNode oXml2;
if (oXmlNodes.GetAt(i,oXml2))
{
((Symbol*)pReference)->AddContent(Create(oXml2, false));
}
}
}
}
}
}
}
inline bool SetDefaultSizes()
{
if ((0 == m_nWidth)||(0 == m_nHeight))
{
if ((0 == (int)m_oViewBox.m_nWidth) || (0 == (int)m_oViewBox.m_nHeight))
{
m_oViewBox.m_nWidth = m_nDefWidth;
m_oViewBox.m_nHeight = m_nDefHeight;
}
m_Metrics = PX;
m_nWidth = m_oViewBox.m_nWidth;
m_nHeight = m_oViewBox.m_nHeight;
if (0 == m_oViewBox.m_nWidth)
m_nWidth = (std::max) (m_oViewBox.m_nWidth, m_oViewBox.m_nHeight);
if (0 == m_oViewBox.m_nHeight)
m_nHeight = (std::max) (m_oViewBox.m_nWidth, m_oViewBox.m_nHeight);
m_oUs.SetViewBox (m_nWidth, m_nHeight, m_oViewBox, m_Metrics);
return true;
}
return false;
}
private:
DOCTYPE m_DOCTYPE;
Metrics m_Metrics;
LONG m_nWidth;
LONG m_nHeight;
LONG m_nDefsLayer;
bool m_bDefinesLayer;
Storage* m_model;
DrawBuilder m_oDrawBuilder;
DefsBuilder m_oDefsBuilder;
ColorTable m_oColTable;
Style m_oStyle;
FontStyle m_oFontStyle;
StyleStack m_oStyles;
MatrixStack m_transforms;
long m_nLayerLevel; // for transforms
ViewBox m_oViewBox;
UnitSystem m_oUs;
long m_nDefWidth;
long m_nDefHeight;
CString m_sWorkingDirectory;
CStyleCSS m_CSS;
};
}