#include "StdAfx.h"
#include "SVGFramework.h"

#include "..\..\..\Interfaces\ASCGraphicsRenderer.h"
#include "..\..\..\..\..\Common\MediaFormatDefine.h"

#define ADD_COLOR( COLOR, R, G, B ) m_Table.Add( _T(##COLOR), ( ##R << 16 ) | ( ##G << 8 ) | ##B );

namespace SVG
{
	ColorTable ColorParser::m_oTable;
	BOOL ColorTable::InitClrTable()
	{
		if (m_Table.GetSize())
			return TRUE;

		ADD_COLOR("aliceblue", 240, 248, 255);
		ADD_COLOR("antiquewhite", 250, 235, 215); 
		ADD_COLOR("aqua",  0, 255, 255); 
		ADD_COLOR("aquamarine", 127, 255, 212); 
		ADD_COLOR("azure", 240, 255, 255); 
		ADD_COLOR("beige", 245, 245, 220); 
		ADD_COLOR("bisque", 255, 228, 196); 
		ADD_COLOR("black",  0, 0, 0); 
		ADD_COLOR("blanchedalmond", 255, 235, 205); 
		ADD_COLOR("blue",  0, 0, 255); 
		ADD_COLOR("blueviolet", 138, 43, 226); 
		ADD_COLOR("brown", 165, 42, 42); 
		ADD_COLOR("burlywood", 222, 184, 135); 
		ADD_COLOR("cadetblue",  95, 158, 160); 
		ADD_COLOR("chartreuse", 127, 255, 0); 
		ADD_COLOR("chocolate", 210, 105, 30); 
		ADD_COLOR("coral", 255, 127, 80); 
		ADD_COLOR("cornflowerblue", 100, 149, 237); 
		ADD_COLOR("cornsilk", 255, 248, 220); 
		ADD_COLOR("crimson", 220, 20, 60); 
		ADD_COLOR("cyan",  0, 255, 255); 
		ADD_COLOR("darkblue",  0, 0, 139); 
		ADD_COLOR("darkcyan",  0, 139, 139); 
		ADD_COLOR("darkgoldenrod", 184, 134, 11); 
		ADD_COLOR("darkgray", 169, 169, 169); 
		ADD_COLOR("darkgreen",  0, 100, 0); 
		ADD_COLOR("darkgrey", 169, 169, 169); 
		ADD_COLOR("darkkhaki", 189, 183, 107); 
		ADD_COLOR("darkmagenta", 139, 0, 139); 
		ADD_COLOR("darkolivegreen",  85, 107, 47); 
		ADD_COLOR("darkorange", 255, 140, 0); 
		ADD_COLOR("darkorchid", 153, 50, 204); 
		ADD_COLOR("darkred", 139, 0, 0); 
		ADD_COLOR("darksalmon", 233, 150, 122); 
		ADD_COLOR("darkseagreen", 143, 188, 143); 
		ADD_COLOR("darkslateblue",  72, 61, 139); 
		ADD_COLOR("darkslategray",  47, 79, 79); 
		ADD_COLOR("darkslategrey",  47, 79, 79); 
		ADD_COLOR("darkturquoise",  0, 206, 209); 
		ADD_COLOR("darkviolet", 148, 0, 211); 
		ADD_COLOR("deeppink", 255, 20, 147); 
		ADD_COLOR("deepskyblue",  0, 191, 255); 
		ADD_COLOR("dimgray", 105, 105, 105); 
		ADD_COLOR("dimgrey", 105, 105, 105); 
		ADD_COLOR("dodgerblue",  30, 144, 255); 
		ADD_COLOR("firebrick", 178, 34, 34); 
		ADD_COLOR("floralwhite", 255, 250, 240); 
		ADD_COLOR("forestgreen",  34, 139, 34); 
		ADD_COLOR("fuchsia", 255, 0, 255); 
		ADD_COLOR("gainsboro", 220, 220, 220); 
		ADD_COLOR("ghostwhite", 248, 248, 255); 
		ADD_COLOR("gold", 255, 215, 0); 
		ADD_COLOR("goldenrod", 218, 165, 32); 
		ADD_COLOR("gray", 128, 128, 128); 
		ADD_COLOR("grey", 128, 128, 128); 
		ADD_COLOR("green",  0, 128, 0); 
		ADD_COLOR("greenyellow", 173, 255, 47); 
		ADD_COLOR("honeydew", 240, 255, 240); 
		ADD_COLOR("hotpink", 255, 105, 180); 
		ADD_COLOR("indianred", 205, 92, 92); 
		ADD_COLOR("indigo",  75, 0, 130); 
		ADD_COLOR("ivory", 255, 255, 240); 
		ADD_COLOR("khaki", 240, 230, 140); 
		ADD_COLOR("lavender", 230, 230, 250); 
		ADD_COLOR("lavenderblush", 255, 240, 245); 
		ADD_COLOR("lawngreen", 124, 252, 0); 
		ADD_COLOR("lemonchiffon", 255, 250, 205); 
		ADD_COLOR("lightblue", 173, 216, 230); 
		ADD_COLOR("lightcoral", 240, 128, 128); 
		ADD_COLOR("lightcyan", 224, 255, 255); 
		ADD_COLOR("lightgoldenrodyellow", 250, 250, 210); 
		ADD_COLOR("lightgray", 211, 211, 211); 
		ADD_COLOR("lightgreen", 144, 238, 144); 
		ADD_COLOR("lightgrey", 211, 211, 211); 
		ADD_COLOR("lightpink", 255, 182, 193); 
		ADD_COLOR("lightsalmon", 255, 160, 122); 
		ADD_COLOR("lightseagreen",  32, 178, 170); 
		ADD_COLOR("lightskyblue", 135, 206, 250); 
		ADD_COLOR("lightslategray", 119, 136, 153); 
		ADD_COLOR("lightslategrey", 119, 136, 153); 
		ADD_COLOR("lightsteelblue", 176, 196, 222); 
		ADD_COLOR("lightyellow", 255, 255, 224); 
		ADD_COLOR("lime",  0, 255, 0); 
		ADD_COLOR("limegreen",  50, 205, 50); 
		ADD_COLOR("linen", 250, 240, 230); 
		ADD_COLOR("magenta", 255, 0, 255); 
		ADD_COLOR("maroon", 128, 0, 0); 
		ADD_COLOR("mediumaquamarine", 102, 205, 170); 
		ADD_COLOR("mediumblue",  0, 0, 205); 
		ADD_COLOR("mediumorchid", 186, 85, 211); 
		ADD_COLOR("mediumpurple", 147, 112, 219); 
		ADD_COLOR("mediumseagreen",  60, 179, 113); 
		ADD_COLOR("mediumslateblue", 123, 104, 238); 
		ADD_COLOR("mediumspringgreen",  0, 250, 154); 
		ADD_COLOR("mediumturquoise",  72, 209, 204); 
		ADD_COLOR("mediumvioletred", 199, 21, 133); 
		ADD_COLOR("midnightblue",  25, 25, 112); 
		ADD_COLOR("mintcream", 245, 255, 250); 
		ADD_COLOR("mistyrose", 255, 228, 225); 
		ADD_COLOR("moccasin", 255, 228, 181); 
		ADD_COLOR("navajowhite", 255, 222, 173); 
		ADD_COLOR("navy",  0, 0, 128); 
		ADD_COLOR("oldlace", 253, 245, 230); 
		ADD_COLOR("olive", 128, 128, 0); 
		ADD_COLOR("olivedrab", 107, 142, 35); 
		ADD_COLOR("orange", 255, 165, 0); 
		ADD_COLOR("orangered", 255, 69, 0); 
		ADD_COLOR("orchid", 218, 112, 214); 
		ADD_COLOR("palegoldenrod", 238, 232, 170); 
		ADD_COLOR("palegreen", 152, 251, 152); 
		ADD_COLOR("paleturquoise", 175, 238, 238); 
		ADD_COLOR("palevioletred", 219, 112, 147); 
		ADD_COLOR("papayawhip", 255, 239, 213); 
		ADD_COLOR("peachpuff", 255, 218, 185); 
		ADD_COLOR("peru", 205, 133, 63); 
		ADD_COLOR("pink", 255, 192, 203); 
		ADD_COLOR("plum", 221, 160, 221); 
		ADD_COLOR("powderblue", 176, 224, 230); 
		ADD_COLOR("purple", 128, 0, 128); 
		ADD_COLOR("red", 255, 0, 0); 
		ADD_COLOR("rosybrown", 188, 143, 143); 
		ADD_COLOR("royalblue",  65, 105, 225); 
		ADD_COLOR("paddlebrown", 139, 69, 19); 
		ADD_COLOR("palmon", 250, 128, 114); 
		ADD_COLOR("pandybrown", 244, 164, 96); 
		ADD_COLOR("peagreen",  46, 139, 87); 
		ADD_COLOR("peashell", 255, 245, 238); 
		ADD_COLOR("pienna", 160, 82, 45); 
		ADD_COLOR("pilver", 192, 192, 192); 
		ADD_COLOR("pkyblue", 135, 206, 235); 
		ADD_COLOR("plateblue", 106, 90, 205); 
		ADD_COLOR("plategray", 112, 128, 144); 
		ADD_COLOR("plategrey", 112, 128, 144); 
		ADD_COLOR("pnow", 255, 250, 250); 
		ADD_COLOR("ppringgreen",  0, 255, 127); 
		ADD_COLOR("pteelblue",  70, 130, 180); 
		ADD_COLOR("tan", 210, 180, 140); 
		ADD_COLOR("teal",  0, 128, 128); 
		ADD_COLOR("thistle", 216, 191, 216); 
		ADD_COLOR("tomato", 255, 99, 71); 
		ADD_COLOR("turquoise",  64, 224, 208); 
		ADD_COLOR("violet", 238, 130, 238); 
		ADD_COLOR("wheat", 245, 222, 179); 
		ADD_COLOR("white", 255, 255, 255); 
		ADD_COLOR("whitesmoke", 245, 245, 245); 
		ADD_COLOR("yellow", 255, 255, 0); 
		ADD_COLOR("yellowgreen", 154, 205, 50); 

		return TRUE;
	}

	long ColorParser::ColorFromString(const CString& sColor)
	{
		// HEX VALUE

		int index = sColor.Find(_T('#'));
		if (-1 != index)
		{
			CString OnlyColor = _T("");
			for ( int i = index; i < sColor.GetLength (); ++i)
			{
				if (_T(' ') == sColor[i])
				{
					return ColorFromHexString(sColor.Mid(index, i - index));
				}
			}

			return ColorFromHexString(sColor.Mid(index, sColor.GetLength() - index));
		}

		if (CString(_T("none")) == sColor)
			return -2;

		// 'rgb(x,x,x)' 
		if ((sColor[0] == _T('r')) && (sColor[1] == _T('g')) && (sColor[2] == _T('b')))
			return ColorFromRgbString(sColor);

		// COLOR TABLE
		return m_oTable.Find(sColor);
	}
	long ColorParser::ColorFromRgbString(const CString& Rgb)
	{
		BOOL PCT	=	FALSE;
		double Color [ 4 ]	=	{ 0.0, 0.0, 0.0, 255 };

		BOOL Begin	=	FALSE;	
		int	IndS	=	0;
		int IndCol	=	0;

		for ( int i = 0; i < (int)Rgb.GetLength (); ++i )
		{
			if ( isdigit ( Rgb [ i ] ) )
			{
				if ( FALSE == Begin )
				{
					Begin	=	TRUE;
					IndS	=	i;
				}
			}
			else
			{	
				if ( Begin )
				{
					if ( i - IndS >= 1 )
					{
						Color [ IndCol++ ]	=	_tstof ( Rgb.Mid ( IndS, i - IndS ) );
					}
				}

				Begin	=	FALSE;
			}

			if ( _T('%') == Rgb [ i ] )
			{
				PCT	=	TRUE;
			}
		}

		if ( PCT )
		{
			Color [ 0 ] *= 255.0 * 0.01;
			Color [ 1 ] *= 255.0 * 0.01;
			Color [ 2 ] *= 255.0 * 0.01;
		}

		if (0 == Color[3])
			return -2;

		return ( ( (int) (Color [ 2 ]) << 16 ) | ( (int) (Color [ 1 ]) << 8 ) | (int) (Color [ 0 ]) );			
	}
	long ColorParser::ColorFromHexString(const CString& Hex)
	{
		CString value	=	Hex.Mid ( 1, Hex.GetLength () - 1 );
		if ( 3 == value.GetLength () )	//	for ex ~ #fb0 expands to #ffbb00
		{
			value.Insert ( 0, value [ 0 ] );
			value.Insert ( 2, value [ 2 ] );
			value.Insert ( 4, value [ 4 ] );
		}

		for ( int i = 0; i < value.GetLength (); ++i )
		{
			if ( isdigit ( value [ i ] ) || ( value [ i ] >= L'a' ) || ( value [ i ] >= L'f' ) || ( value [ i ] >= L'A' ) || ( value [ i ] >= L'F' ) )
				continue;

			long InvCol = wcstol ( value.Mid ( 0, i ), NULL, 16 );
			return ( ( InvCol & 0xFF ) << 16 ) | ( ( InvCol & 0xFF00 ) ) | ( ( InvCol & 0xFF0000 ) >> 16 );
		}

		long InvCol = wcstol( value, NULL, 16 );
		return ( ( InvCol & 0xFF ) << 16 ) | ( ( InvCol & 0xFF00 ) ) | ( ( InvCol & 0xFF0000 ) >> 16 );
	}
}

namespace SVG
{
	BOOL ImageBase64::CreateImage (BYTE* pBuffer, unsigned long Length, int ImageEncoder)
	{
		if (NULL == pBuffer || Length < 1)
			return FALSE;

		m_nBufferSize	=	Base64::Base64DecodeGetRequiredLength (Length);
		m_pBuffer		=	new BYTE [m_nBufferSize];

		if (m_pBuffer)
		{
			if (ImageBase64::Base64Decode ( (LPTSTR) pBuffer, Length, m_pBuffer, &m_nBufferSize))
			{
				/*

				CAtlFile oFile;

				if ( ImageEncoder == JPG_ENCODER )
				{
				if ( SUCCEEDED ( oFile.Create ( _T("C:\\test.jpg"), GENERIC_WRITE, FILE_SHARE_WRITE, CREATE_NEW ) ) )
				{
				DWORD nFileBuff	=	0L;
				oFile.Write ( m_pBuffer, m_nBufferSize, &nFileBuff );
				oFile.Close ();
				}
				}

				*/

				return TRUE;
			}

			delete [] m_pBuffer;
		}

		return FALSE;
	}
	BOOL ImageBase64::EncodeBufferToImageCOM (const BYTE* pBuffer, const unsigned long& ImageSize, IUnknown*& pImage)
	{
		if ( NULL == pBuffer || ImageSize < 41 )
			return FALSE;

		HGLOBAL	hMem	=	::GlobalAlloc ( GMEM_FIXED, ImageSize );
		LPVOID	pSImage	=	::GlobalLock ( hMem );

		CopyMemory ( pSImage, pBuffer, ImageSize );

		IStream* pStream = NULL;
		if ( SUCCEEDED ( CreateStreamOnHGlobal ( hMem, FALSE, &pStream ) ) )
		{
			Gdiplus::Bitmap* pBitmap	= Gdiplus::Bitmap::FromStream ( pStream );
			if ( Gdiplus::Ok == pBitmap->GetLastStatus () )
			{
				BOOL Status	=	ImageBase64::GdiImageToImageCOM ( pBitmap, pImage );

				delete pBitmap;

				pStream->Release();

				GlobalUnlock ( hMem );
				GlobalFree ( hMem );

				return Status;
			}

			delete pBitmap;

			pStream->Release();
		}

		GlobalUnlock ( hMem );
		GlobalFree ( hMem );

		return FALSE;
	}
	BOOL ImageBase64::GdiImageToImageCOM (Gdiplus::Bitmap* pBitmap, IUnknown*& pImage)
	{
		MediaCore::IAVSUncompressedVideoFrame* pFrame = NULL;
		if ( SUCCEEDED ( CoCreateInstance ( MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)&pFrame ) ) )
		{
			pFrame->put_Height ( pBitmap->GetHeight () );
			pFrame->put_Width ( pBitmap->GetWidth () );

			pFrame->put_AspectRatioX ( 0 );
			pFrame->put_AspectRatioY ( 0 );

#define CSP_BGRA     (1<< 6) /* 32-bit bgra packed */

			//pFrame->put_ColorSpace ( CSP_BGRA | CSP_VFLIP );
			pFrame->put_ColorSpace	( CSP_BGRA );

			pFrame->SetDefaultStrides ();
			pFrame->AllocateBuffer	( -1 );

			LONG PlaneSize = 0;		pFrame->get_BufferSize ( &PlaneSize );
			BYTE* pPlane = NULL;	pFrame->get_Plane ( 0, &pPlane );

			if ( NULL != pPlane )
			{
				// memset ( pPlane, 0xFFFFFF00, PlaneSize );

				BitmapData data; 
				if ( Gdiplus::Ok == pBitmap->LockBits ( NULL, ImageLockModeRead, PixelFormat32bppARGB, &data ) )
				{
					memcpy ( pPlane, data.Scan0, PlaneSize );
					pBitmap->UnlockBits ( &data );
				}

				pFrame->QueryInterface ( __uuidof(IUnknown), (void**)&pImage );
				pFrame->Release ();

				return TRUE;
			}

			pFrame->Release ();
		}

		return FALSE;
	}
	BOOL ImageBase64::Base64Decode(LPTSTR szSrc, int nSrcLen, BYTE *pbDest, int *pnDestLen) throw()
	{
		// walk the source buffer
		// each four character sequence is converted to 3 bytes
		// CRLFs and =, and any characters not in the encoding table
		// are skiped

		if (szSrc == NULL || pnDestLen == NULL)
			return FALSE;

		LPTSTR szSrcEnd = szSrc + nSrcLen;
		int nWritten = 0;

		BOOL bOverflow = (pbDest == NULL) ? TRUE : FALSE;

		while (szSrc < szSrcEnd &&(*szSrc) != 0)
		{
			DWORD dwCurr = 0;
			int i;
			int nBits = 0;
			for (i=0; i<4; i++)
			{
				if (szSrc >= szSrcEnd)
					break;
				int nCh = DecodeBase64Char(*szSrc);
				szSrc++;
				if (nCh == -1)
				{
					// skip this char
					i--;
					continue;
				}
				dwCurr <<= 6;
				dwCurr |= nCh;
				nBits += 6;
			}

			if(!bOverflow && nWritten + (nBits/8) > (*pnDestLen))
				bOverflow = TRUE;

			// dwCurr has the 3 bytes to write to the output buffer
			// left to right
			dwCurr <<= 24-nBits;
			for (i=0; i<nBits/8; i++)
			{
				if(!bOverflow)
				{
					*pbDest = (BYTE) ((dwCurr & 0x00ff0000) >> 16);
					pbDest++;
				}
				dwCurr <<= 8;
				nWritten++;
			}

		}

		*pnDestLen = nWritten;

		if(bOverflow)
		{
			// if (pbDest != NULL) ATLASSERT(FALSE);

			return FALSE;
		}

		return TRUE;
	}
}

namespace SVG
{
	BOOL Painter::Draw(IRefStorage* model, IASCRenderer* render, const UnitSystem& oUs)
	{
		if (NULL == model || NULL == render)
			return FALSE;

		m_model		=	model;
		m_render	=	render;
		m_oUs		=	oUs;

		m_render->get_DpiX(&m_dpiX);
		m_render->get_DpiY(&m_dpiY);
		m_render->get_Width(&m_widthMM);
		m_render->get_Height(&m_heightMM);

		if ((fabs(m_dpiX) < 0.000001) || (fabs(m_dpiY) < 0.000001))
		{
			m_dpiX	=	m_oUs.GetWidth() / m_widthMM * 25.4;
			m_dpiY	=	m_oUs.GetHeight() / m_heightMM * 25.4;
		}

		m_dAddMX	=	25.4 / m_dpiX;
		m_dAddMY	=	25.4 / m_dpiY;

		m_model->Normalize(m_dAddMX, m_dAddMY);

		VARIANT var;
		if (SUCCEEDED(m_render->GetAdditionalParam(L"FontManager", &var)))
		{
			if (var.vt == VT_UNKNOWN && NULL == var.punkVal)
			{
				m_bEnableFonts = FALSE;					
#ifndef _DEBUG
				var.punkVal = GetFontManager();
				m_render->SetAdditionalParam(L"FontManager", var);
#endif
			}
		}

		return DrawStorage(m_model);
	}
	BOOL Painter::DrawLine (Line* element, const Style& oStyle, const CString& strClassName)
	{
		LONG type = 0;
		if (SetStrokeStyle(oStyle, strClassName))
			type += c_nStroke;

		if (0 != type)	
		{
			m_render->PathCommandStart();
			m_render->BeginCommand (c_nPathType);

			m_render->PathCommandStart ();

			m_render->PathCommandMoveTo (element->GetFrom().X, element->GetFrom().Y);
			m_render->PathCommandLineTo (element->GetTo().X, element->GetTo().Y);

			m_render->DrawPath (type);
			m_render->EndCommand (c_nPathType);
			m_render->PathCommandEnd ();
		}	

		return TRUE;
	}
	BOOL Painter::DrawRectangle (Rectangle* element, const Style& oStyle, const CString& strClassName)
	{
		DoClip (element->GetClip(), TRUE);	

		LONG type = 0;
		if (SetBrushStyle(oStyle, strClassName))
			type += c_nWindingFillMode;
		if (SetStrokeStyle(oStyle, strClassName))
			type += c_nStroke;

		if (0 != type)
			DoRectangle (element, type);

		DoClip (element, FALSE);

		return TRUE;
	}
	BOOL Painter::DrawCircle (Circle* element,const Style& oStyle, const CString& strClassName)
	{
		DoClip (element->GetClip(), TRUE);			

		LONG type = 0;
		if (SetBrushStyle(oStyle, strClassName))
			type += c_nWindingFillMode;
		if (SetStrokeStyle(oStyle, strClassName))
			type += c_nStroke;

		if (0 != type)	
			DoCircle (element, type);

		DoClip (element->GetClip(), FALSE);

		return TRUE;
	}
	BOOL Painter::DrawEllipse (Ellipse* element, const Style& oStyle, const CString& strClassName)
	{
		DoClip (element->GetClip(), TRUE);			

		LONG type = 0;
		if (SetBrushStyle(oStyle, strClassName))
			type += c_nWindingFillMode;
		if (SetStrokeStyle(oStyle, strClassName))
			type += c_nStroke;

		if (0 != type)	
			DoEllipse (element, type);

		DoClip (element->GetClip(), FALSE);

		return TRUE;
	}
	BOOL Painter::DrawPolyline (Polyline* element, const Style& oStyle, const CString& strClassName)
	{
		DoClip (element->GetClip(), TRUE);			

		LONG type = 0;
		if (SetBrushStyle(oStyle, strClassName))
			type += c_nWindingFillMode;
		if (SetStrokeStyle(oStyle, strClassName))
			type += c_nStroke;

		if (0 != type)	
		{
			DoPolyline (element, type);
		}

		DoClip (element->GetClip(), FALSE);

		return TRUE;
	}
	BOOL Painter::DrawPolygon (Polygon* element, const Style& oStyle, const CString& strClassName)
	{
		DoClip (element->GetClip(), TRUE);			

		LONG type = 0;
		if (SetBrushStyle(oStyle, strClassName))
			type += c_nWindingFillMode;
		if (SetStrokeStyle(oStyle, strClassName))
			type += c_nStroke;

		if (0 != type)	
		{
			DoPolygon (element, type);
		}

		DoClip (element->GetClip(), FALSE);

		return TRUE;
	}		
	BOOL Painter::DrawPath (Path* element, const Style& oStyle, const CString& strClassName)
	{
		DoClip (element->GetClip(), TRUE);			

		LONG lType = 0;
		if (SetBrushStyle(oStyle, strClassName))
			lType += c_nWindingFillMode;
		if (SetStrokeStyle(oStyle, strClassName))
			lType += c_nStroke;

		if (0 != lType)
			PushPathCommands (element, lType);

		DoClip (element->GetClip(), FALSE);

		return TRUE;
	}
	BOOL Painter::DrawText (Text* element, const Style& oStyle, const CString& strClassName)
	{
		if (!m_bEnableFonts)
			return FALSE;

		IASCFontManager* fontManager = GetFontManager();
		if (NULL == fontManager)
			return FALSE;

		BOOL clipOn = DoClip (element->GetClip(), TRUE);			

		SetBrushStyle (oStyle, strClassName);

		double dpiX = 0.0f;	m_render->get_DpiX ( &dpiX );
		double dpiY = 0.0f;	m_render->get_DpiY ( &dpiY );

		if ( 0.0 == dpiX || 0.0 == dpiY )
		{
			double dWidthMM = 0; m_render->get_Width(&dWidthMM);
			double dHeightMM = 0; m_render->get_Height(&dHeightMM);

			double dWidthPix = m_oUs.GetWidth();
			double dHeightPix = m_oUs.GetHeight();

			dpiX = dWidthPix / dWidthMM * 25.4;
			dpiY = dHeightPix / dHeightMM * 25.4;
		}

		double dFontSize	=	element->GetFontStyle ().DoubleAttribute ( FontSize ) * 72.0f / dpiX * element->m_oUs.GetFactorFontSize ();
		if (dFontSize <= 0.0)	//	for geicha_6000px.svg 
		{
			if (clipOn)
				DoClip (element->GetClip(), FALSE);

			return FALSE;
		}

		BSTR bsFontFamily	=	element->GetFontStyle ().GetAttribute ( FontFamily ).AllocSysString();
		BSTR bsText			=	element->GetText ().AllocSysString ();

		float X			=	0.0;
		float Y			=	0.0;
		float BoundX	=	0.0;
		float BoundY	=	0.0;

		m_render->put_FontSize ( dFontSize );
		m_render->put_FontName ( bsFontFamily );

		LONG Style	= 0L;
		if ( FontWeightBold == element->GetFontStyle ().LongAttribute ( FontWeight ) )
		{
			Style |= 0x01;
		}

		if ( FontStyleItalic == element->GetFontStyle ().LongAttribute ( FontStyleAttr ) )
		{
			Style |= 0x02;
		}

		m_render->put_FontStyle (Style);

		fontManager->LoadFontByName ( bsFontFamily, (float)dFontSize, 0, 72.0, 72.0 );
		fontManager->LoadString2 ( bsText, 0, 0 );
		fontManager->MeasureString ( &X, &Y, &BoundX, &BoundY );

		BoundX *= (25.4f / 72.0f);
		BoundY *= (25.4f / 72.0f);

		float m_fLineSpacing;
		float m_fEmHeight;
		float m_fAscent;
		float m_fDescent;

		unsigned short iTemp = 0;

		GetFontManager ()->GetCellAscent(&iTemp);
		m_fAscent = iTemp;
		GetFontManager ()->GetCellDescent(&iTemp);
		m_fDescent = iTemp;
		GetFontManager ()->GetLineSpacing(&iTemp);
		m_fLineSpacing = iTemp;
		GetFontManager ()->GetEmHeight(&iTemp);
		m_fEmHeight = iTemp;

		double OffSetY = 3 * (m_fLineSpacing - m_fDescent) - m_fAscent;
		OffSetY /= 2.0;
		OffSetY *= (dFontSize / m_fEmHeight);
		//OffSetY *= dpiY / 72.0;
		OffSetY *= (25.4 / 72.0);

		if ( FontTextAnchorStart == element->GetFontStyle().LongAttribute(FontTextAnchor))
		{
			m_render->CommandDrawText ( bsText, element->m_Pos.X, element->m_Pos.Y, BoundX, 0.0, OffSetY ); 
		}

		if ( FontTextAnchorMiddle == element->GetFontStyle().LongAttribute(FontTextAnchor))
		{
			m_render->CommandDrawText ( bsText, element->m_Pos.X - BoundX * 0.5, element->m_Pos.Y, BoundX, 0.0, OffSetY );
		}

		if (FontTextAnchorEnd == element->GetFontStyle ().LongAttribute(FontTextAnchor))
		{
			m_render->CommandDrawText ( bsText, element->m_Pos.X - BoundX, element->m_Pos.Y, BoundX, 0.0, OffSetY ); 
		}

		SysFreeString(bsFontFamily);
		SysFreeString(bsText);	

		DoClip (element->GetClip(), FALSE);

		return TRUE;
	}
	BOOL Painter::DrawImage (Image* element, const Style& oStyle, const CString& strClassName)
	{
		if (element->GetXLink().GetLength())
		{	
			DrawImageFromFile (element, element->LivePath(m_sWorkingDirectory));					
		}
		else if (element->m_ImagePath.GetLength())
		{
			DrawImageFromFile (element);			
		}
		else
		{
			// TODO : save images

			IUnknown* pImage = NULL;
			if (element->m_bin64Image.GetImage(pImage))
			{
				m_render->DrawImage(pImage, element->m_Or.X, element->m_Or.Y, element->m_Size.X, element->m_Size.Y);
				RELEASEINTERFACE(pImage);
			}
		}

		return TRUE;
	}
	BOOL Painter::DrawUse (Use* element, const Style& oStyle, const CString& strClassName)
	{
		BOOL retVal = FALSE;

		element->RefreshXLinkSource (m_model);

		if (element->GetRefLink())
		{
			ENodeType code = element->GetRefLink ()->nodeType();
			ISvgRef* refLink = element->GetRefLink();

			if (EGraphicsContainer == code)
			{
				IRefStorage* pStorage = dynamic_cast<IRefStorage*>(refLink);
				if (pStorage) 
				{
					retVal = DrawStorage (pStorage, element->GetTransform(), element->GetFrom());
				}
			}
			else if (ESymbol == code)
			{
				Symbol* pSymbol = dynamic_cast<Symbol*>(refLink);
				if (pSymbol)
				{
					BOOL bStatus = FALSE;
					for (long i = 0; i < pSymbol->GetCount(); ++i)
					{
						DrawElement* pContent = pSymbol->GetAt(i);
						if (pContent)
						{
							retVal = DrawInternal (pContent, element->GetTransform(), Point(), element->GetStyle());
						}
					}
				}
			}
			else
			{
				DrawElement* drawElement = dynamic_cast<DrawElement*>(refLink);
				if (drawElement)
				{					
					m_transforms.Push(element->GetTransform(), FALSE);

					Matrix local = m_transforms.GetFinal();
					retVal = DrawInternal (drawElement, local, element->GetFrom(), element->GetStyle());

					m_transforms.Pop();
				}
			}
		}

		return retVal;
	}

	//
	BOOL Painter::DrawStorage (IRefStorage* pStorage, const Matrix& parentTransform, const Point& off)
	{
		if (pStorage)
		{
			int count = pStorage->GetSize();
			if (0 == count)
				return FALSE;

			m_transforms.Push(parentTransform.Copy().Move(off.X, off.Y), FALSE);
			for (int i = 0; i < count; ++i)
			{
				DrawElement* pE = static_cast<DrawElement*>(pStorage->Get(i));
				if (pE)
				{	
					const ENodeType code	=	pE->nodeType();
					if (EClipPath == code)
						continue;

					const CString& css		=	pE->ClassName();
					Style oStyle			=	pE->GetStyle();						
					oStyle					=	ComposeStyles(pE, oStyle);

					Matrix mat = parentTransform;						
					mat *= Matrix::TranslateTransform(off.X, off.Y);
					mat *= pE->GetTransform();

					m_render->SetTransform(mat[0], mat[3], mat[1], mat[4], (mat[2] + m_oUs.OffSetX()) * m_dAddMX, (mat[5] + m_oUs.OffSetY()) * m_dAddMY);

					UpdateClass(pE);

					switch (code)
					{
					case ERectangle:			DrawRectangle(static_cast<Rectangle*>(pE),oStyle,css);								continue;	break;
					case ELine:					DrawLine(static_cast<Line*>(pE),oStyle,css);										continue;	break;
					case EEllipse:				DrawEllipse(static_cast<Ellipse*>(pE),oStyle,css);									continue;	break;
					case ECircle:				DrawCircle(static_cast<Circle*>(pE),oStyle,css);									continue;	break;
					case EPath:					DrawPath(static_cast<Path*>(pE),oStyle,css);										continue;	break;
					case EPolyline:				DrawPolyline(static_cast<Polyline*>(pE),oStyle,css);								continue;	break;
					case EPolygon:				DrawPolygon(static_cast<Polygon*>(pE),oStyle,css);									continue;	break;
					case EText:					DrawText(static_cast<Text*>(pE),oStyle,css);										continue;	break;
					case EImage:				DrawImage(static_cast<Image*>(pE),oStyle,css);										continue;	break;
					case EUse:					DrawUse(static_cast<Use*>(pE),oStyle,css);											continue;	break;
					case EGraphicsContainer:	DrawGraphicsContainer(static_cast<GraphicsContainer*>(pE), parentTransform, off);	continue;	break;
					}
				}
			}

			m_transforms.Pop();
		}

		return TRUE;
	}
	BOOL Painter::DrawGraphicsContainer (GraphicsContainer* element, const Matrix& parentTransform, const Point& off)
	{
		DoClip (element->GetClip(), TRUE);			

		BOOL ret = DrawStorage (element, parentTransform, off);

		DoClip (element->GetClip(), FALSE);

		return ret;
	}
	BOOL Painter::DrawInternal (DrawElement* pE, const Matrix& parentTransform, const Point& off, const Style& oMainStyle)
	{
		Matrix mat = parentTransform;						
		mat *=	Matrix::TranslateTransform(off.X, off.Y);
		mat *=	pE->GetTransform();

		m_render->SetTransform (mat[0],	mat[3], mat[1], mat[4], (mat[2] + m_oUs.OffSetX()) * m_dAddMX,	(mat[5] + m_oUs.OffSetY()) * m_dAddMY);

		UpdateClass(pE);

		Style oStyle	=	pE->GetStyle();
		Style::UpdateValidateAttributes (oMainStyle, oStyle);
		oStyle			=	ComposeStyles(pE, oStyle);

		const CString& strClass = pE->ClassName();
		ENodeType code	=	pE->nodeType();

		if (ERectangle == code)
		{
			DrawRectangle(static_cast<Rectangle*>(pE),oStyle,strClass);			return TRUE;
		}
		else if (ELine == code)
		{
			DrawLine(static_cast<Line*>(pE),oStyle,strClass);					return TRUE;
		}
		else if (EEllipse == code)
		{
			DrawEllipse(static_cast<Ellipse*>(pE),oStyle,strClass);				return TRUE;
		}
		else if (ECircle == code)
		{
			DrawCircle(static_cast<Circle*>(pE),oStyle,strClass);				return TRUE;
		}
		else if (EPath == code)
		{
			DrawPath(static_cast<Path*>(pE),oStyle,strClass);					return TRUE;
		}
		else if (EPolyline == code)
		{
			DrawPolyline(static_cast<Polyline*>(pE),oStyle,strClass);			return TRUE;
		}
		else if (EPolygon == code)
		{
			DrawPolygon(static_cast<Polygon*>(pE),oStyle,strClass);				return TRUE;
		}
		else if (EText == code)
		{
			DrawText(static_cast<Text*>(pE),oStyle,strClass);					return TRUE;
		}
		else if (EImage == code)
		{
			DrawUse(static_cast<Use*>(pE),oStyle,strClass);						return TRUE;
		}
		else if (EUse == code)
		{
			DrawUse(static_cast<Use*>(pE),oStyle,strClass);						return TRUE;
		}

		return FALSE;
	}

	BOOL Painter::PushPathCommands (Path* element, long PathType)
	{
		m_render->PathCommandStart();
		m_render->BeginCommand ( c_nPathType );

		BOOL SegmentEnd	=	TRUE;
		Point lastMove;

		Point LastPoint;
		PathParser& oPath	=	element->GetPath ();
		for (long i = 0; i < (long)element->GetSize (); ++i)
		{
#ifdef _DEBUG
			WCHAR Code = element->GetCode(i);
#endif
			if (_T('Z') == element->GetCode(i) || _T('z') == element->GetCode(i))
			{
				m_render->PathCommandClose();

				SegmentEnd	=	TRUE;
			}
			else if (_T('m') == element->GetCode(i))
			{
				if (0 == i)
				{					
					m_render->PathCommandMoveTo(element->GetX(i), element->GetY(i));
					LastPoint	=	element->Get(i);

					lastMove	=	LastPoint;
				}
				else
				{
					LastPoint.X	=	lastMove.X;
					LastPoint.Y	=	lastMove.Y;

					m_render->PathCommandMoveTo(element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y);
					LastPoint	+=	element->Get(i);

					lastMove	=	LastPoint;
				}
			}
			else if (_T('M') == element->GetCode(i))
			{
				m_render->PathCommandMoveTo(element->GetX(i), element->GetY(i));
				LastPoint	=	element->Get(i);

				lastMove	=	LastPoint;
			}
			// lines
			else if (_T('l') == element->GetCode(i))
			{
				m_render->PathCommandLineTo(element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y);
				LastPoint	+=	element->Get(i);
			}
			else if (_T('L') == element->GetCode(i))
			{
				m_render->PathCommandLineTo(element->GetX(i), element->GetY(i));
				LastPoint	=	element->Get(i);
			}
			// Horizontal
			else if (_T('h') == element->GetCode(i))
			{
				m_render->PathCommandLineTo(element->GetX(i) + LastPoint.X, LastPoint.Y);
				LastPoint.X	+=	element->Get(i).X;
			}
			else if (_T('H') == element->GetCode(i))
			{
				m_render->PathCommandLineTo(element->GetX(i), LastPoint.Y);
				LastPoint.X	=	element->Get(i).X;
			}
			// Vertical
			else if (_T('v') == element->GetCode(i))
			{
				m_render->PathCommandLineTo(LastPoint.X, element->GetY(i) + LastPoint.Y);
				LastPoint.Y	+=	element->Get(i).Y;
			}
			else if (_T('V') == element->GetCode(i))
			{
				m_render->PathCommandLineTo(LastPoint.X, element->GetY(i));
				LastPoint.Y	=	element->Get(i).Y;
			}
			// elliptical arc curve
			else if (_T('a') == element->GetCode(i))
			{
				int	LargeFlag		=	static_cast<int> ( element->GetY ( i + 1 ) );
				int	SweepFlag		=	static_cast<int> ( element->GetX ( i + 2 ) );					

				double RX			=	element->GetX ( i );
				double RY			=	element->GetY ( i );

				Point End			=	LastPoint + element->Get ( i + 3 ); 

				Point Center		=	GetCenter ( LargeFlag, SweepFlag, Point ( element->GetX ( i ), element->GetY ( i ) ), LastPoint, End );

				double dStartAngle	=	GetAngle ( Center.X, Center.Y, LastPoint.X, LastPoint.Y );
				double dEndAngle	=	GetAngle ( Center.X, Center.Y, End.X, End.Y ); 

				double dSweep		=	0.0;

				if ( GetArcAngles ( LargeFlag, SweepFlag, dStartAngle, dEndAngle, dSweep ) )
				{
					RenderArcAppx (element->GetX ( i + 1 ), Center, Point ( element->GetX ( i ), element->GetY ( i ) ), dStartAngle, dSweep);

					LastPoint	+=	element->Get ( i + 3 );

					i += 3;
				}
			}
			else if ( _T('A') == element->GetCode (i) )
			{
				int	LargeFlag		=	static_cast<int> ( element->GetY ( i + 1 ) );
				int	SweepFlag		=	static_cast<int> ( element->GetX ( i + 2 ) );					

				double RX			=	element->GetX ( i );
				double RY			=	element->GetY ( i );

				Point End			=	element->Get ( i + 3 ); 

				Point Center		=	GetCenter ( LargeFlag, SweepFlag, Point ( element->GetX ( i ), element->GetY ( i ) ), LastPoint, End );

				double dStartAngle	=	GetAngle ( Center.X, Center.Y, LastPoint.X, LastPoint.Y );
				double dEndAngle	=	GetAngle ( Center.X, Center.Y, End.X, End.Y ); 

				double dSweep	=	0.0;

				if ( GetArcAngles ( LargeFlag, SweepFlag, dStartAngle, dEndAngle, dSweep ) )
				{					
					RenderArcAppx (element->GetX ( i + 1 ), Center, Point ( element->GetX ( i ), element->GetY ( i ) ), dStartAngle, dSweep);
				}

				LastPoint	=	element->Get ( i + 3 );

				i += 3;
			}
			// cubic bezier
			else  if ( _T('C') == element->GetCode (i) )
			{
				m_render->PathCommandCurveTo ( element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1), 
					element->GetX(i+2), element->GetY(i+2) );

				LastPoint	=	element->Get ( i + 2 );

				++i;
				++i;
			}
			else if ( _T('c') == element->GetCode (i) )
			{
				m_render->PathCommandCurveTo ( element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y,
					element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y,
					element->GetX(i+2) + LastPoint.X, element->GetY(i+2) + LastPoint.Y );

				LastPoint	+=	element->Get(i+2);

				++i;
				++i;
			}
			else if ( _T('S') == element->GetCode (i) )
			{
				if ( _T('C') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else if ( _T('c') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else if ( _T('S') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else if ( _T('s') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else
				{
					m_render->PathCommandLineTo ( element->GetX(i+1), element->GetY(i+1) );
				}

				LastPoint	=	element->Get(i+1);							
				++i;
			}
			else if ( _T('s') == element->GetCode (i) )
			{
				if ( _T('C') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if ( _T('c') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if ( _T('S') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if ( _T('s') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					m_render->PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if (_T('m') == element->GetCode(i - 1) 
					|| _T('l') == element->GetCode(i - 1)
					|| _T('v') == element->GetCode(i - 1)
					||_T('h') == element->GetCode(i - 1))
				{
					m_render->PathCommandCurveTo(LastPoint.X, LastPoint.Y,
						element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y,
						element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y);
				}
				else
				{
					m_render->PathCommandLineTo(element->GetX(i+1), element->GetY(i+1));
				}

				LastPoint	+=	element->Get(i+1);							
				++i;
			}
			// quadratic bezier
			else if ( _T('q') == element->GetCode(i))
			{
				m_render->PathCommandCurveTo ( element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y,
					element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y,
					element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );

				LastPoint	+=	element->Get(i+1);

				++i;
			}
			else if ( _T('Q') == element->GetCode (i) )
			{
				m_render->PathCommandCurveTo ( element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1), element->GetX(i+1), element->GetY(i+1) );

				LastPoint	=	element->Get(i+1);

				++i;
			}
			else if ( _T('t') == element->GetCode (i) )
			{
				Point p1 = oPath.GetPoints()[ i - 1 ].oPoint;
				Point p2 = oPath.GetPoints()[ i - 2 ].oPoint;
				Point p3 = oPath.GetPoints()[ i	+ 0	].oPoint;

				if ( _T('Q') == element->GetCode ( i - 1 ) )
				{
					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					m_render->PathCommandCurveTo ( dX, dY, p3.X + LastPoint.X, p3.Y + LastPoint.Y, p3.X + LastPoint.X, p3.Y + LastPoint.Y );
				}
				else if ( _T('q') == element->GetCode ( i - 1 ) )
				{
					p1 = Point ( LastPoint.X, LastPoint.Y );
					p2 = Point ( p1.X - element->GetX(i-1) + element->GetX(i-2), p1.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					m_render->PathCommandCurveTo ( dX, dY, p3.X + LastPoint.X, p3.Y + LastPoint.Y, p3.X + LastPoint.X, p3.Y + LastPoint.Y );
				}
				else
				{
					m_render->PathCommandLineTo ( element->GetX(i), element->GetY(i) );
				}

				LastPoint	+=	element->Get(i);							
			}
			else if ( _T('T') == element->GetCode (i) )
			{
				Point p1 = oPath.GetPoints()[ i - 1 ].oPoint;
				Point p2 = oPath.GetPoints()[ i - 2 ].oPoint;
				Point p3 = oPath.GetPoints()[ i + 0 ].oPoint;

				if ( _T('Q') == element->GetCode ( i - 1 ) )
				{
					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					m_render->PathCommandCurveTo ( dX, dY, p3.X, p3.Y, p3.X, p3.Y );
				}
				else if ( _T('q') == element->GetCode ( i - 1 ) )
				{
					p1 = Point ( LastPoint.X, LastPoint.Y );
					p2 = Point ( p1.X - element->GetX(i-1) + element->GetX(i-2), p1.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					m_render->PathCommandCurveTo ( dX, dY, p3.X, p3.Y, p3.X, p3.Y );
				}
				else
				{
					m_render->PathCommandLineTo ( element->GetX(i), element->GetY(i) );
				}

				LastPoint	+=	element->Get(i);							
			}
		}

		m_render->DrawPath(PathType);

		m_render->EndCommand(c_nPathType);
		m_render->PathCommandEnd();

		return TRUE;
	}
	BOOL Painter::ClipPathCommands (Path* element, long PathType)
	{
		Aggplus::CGraphicsPathSimpleConverter simplifier;
		simplifier.SetRenderer(m_render);

		BOOL SegmentEnd	=	TRUE;
		Point lastMove;

		Point LastPoint;
		PathParser& oPath = element->GetPath ();

		for (long i = 0; i < (long)element->GetSize (); ++i)
		{
#ifdef _DEBUG
			WCHAR Code = element->GetCode (i);
#endif
			if ( _T('Z') == element->GetCode (i) || _T('z') == element->GetCode (i) )
			{
				simplifier.PathCommandClose ();

				SegmentEnd	=	TRUE;
			}
			else if ( _T('m') == element->GetCode (i) )
			{
				if (0 == i)
				{					
					simplifier.PathCommandMoveTo(element->GetX(i), element->GetY(i));
					LastPoint	=	element->Get(i);

					lastMove	=	LastPoint;
				}
				else
				{
					LastPoint.X	=	lastMove.X;
					LastPoint.Y	=	lastMove.Y;

					simplifier.PathCommandMoveTo(element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y);
					LastPoint	+=	element->Get(i);

					lastMove	=	LastPoint;
				}
			}
			else if ( _T('M') == element->GetCode (i) )
			{
				simplifier.PathCommandMoveTo ( element->GetX(i), element->GetY(i) );

				LastPoint	=	element->Get(i);

				lastMove	=	LastPoint;
			}
			// lines
			else if ( _T('l') == element->GetCode (i) )
			{
				double X = element->GetX(i);
				double Y = element->GetY(i);

				simplifier.PathCommandLineTo ( element->GetX(i) +  LastPoint.X, element->GetY(i) + LastPoint.Y );

				LastPoint	+=	element->Get(i);
			}
			else if ( _T('L') == element->GetCode (i) )
			{
				simplifier.PathCommandLineTo ( element->GetX(i), element->GetY(i) );

				LastPoint	=	element->Get(i);
			}
			// Horizontal
			else if ( _T('h') == element->GetCode (i) )
			{
				simplifier.PathCommandLineTo ( element->GetX(i) + LastPoint.X, LastPoint.Y );

				LastPoint.X	+=	element->Get(i).X;
			}
			else if ( _T('H') == element->GetCode (i) )
			{
				simplifier.PathCommandLineTo ( element->GetX(i), LastPoint.Y );

				LastPoint.X	=	element->Get(i).X;
			}
			// Vertical
			else if ( _T('v') == element->GetCode (i) )
			{
				simplifier.PathCommandLineTo ( LastPoint.X, element->GetY(i) + LastPoint.Y );

				LastPoint.Y	+=	element->Get(i).Y;
			}
			else if ( _T('V') == element->GetCode (i) )
			{
				simplifier.PathCommandLineTo ( LastPoint.X, element->GetY(i) );

				LastPoint.Y	=	element->Get(i).Y;
			}
			// elliptical arc curve
			else if ( _T('a') == element->GetCode (i) )
			{
				int	LargeFlag		=	static_cast<int> ( element->GetY ( i + 1 ) );
				int	SweepFlag		=	static_cast<int> ( element->GetX ( i + 2 ) );					

				double RX			=	element->GetX ( i );
				double RY			=	element->GetY ( i );

				Point End			=	LastPoint + element->Get ( i + 3 ); 

				Point Center		=	GetCenter ( LargeFlag, SweepFlag, Point ( element->GetX ( i ), element->GetY ( i ) ), LastPoint, End );

				double dStartAngle	=	GetAngle ( Center.X, Center.Y, LastPoint.X, LastPoint.Y );
				double dEndAngle	=	GetAngle ( Center.X, Center.Y, End.X, End.Y ); 

				double dSweep		=	0.0;

				if ( GetArcAngles ( LargeFlag, SweepFlag, dStartAngle, dEndAngle, dSweep ) )
				{
					ClipArcAppx (simplifier, element->GetX ( i + 1 ), Center, Point ( element->GetX ( i ), element->GetY ( i ) ), dStartAngle, dSweep);

					LastPoint	+=	element->Get ( i + 3 );

					i += 3;
				}
			}
			else if ( _T('A') == element->GetCode (i) )
			{
				int	LargeFlag		=	static_cast<int> ( element->GetY ( i + 1 ) );
				int	SweepFlag		=	static_cast<int> ( element->GetX ( i + 2 ) );					

				double RX			=	element->GetX ( i );
				double RY			=	element->GetY ( i );

				Point End			=	element->Get ( i + 3 ); 

				Point Center		=	GetCenter ( LargeFlag, SweepFlag, Point ( element->GetX ( i ), element->GetY ( i ) ), LastPoint, End );

				double dStartAngle	=	GetAngle ( Center.X, Center.Y, LastPoint.X, LastPoint.Y );
				double dEndAngle	=	GetAngle ( Center.X, Center.Y, End.X, End.Y ); 

				double dSweep	=	0.0;

				if ( GetArcAngles ( LargeFlag, SweepFlag, dStartAngle, dEndAngle, dSweep ) )
				{					
					ClipArcAppx (simplifier, element->GetX ( i + 1 ), Center, Point ( element->GetX ( i ), element->GetY ( i ) ), dStartAngle, dSweep);
				}

				LastPoint	=	element->Get ( i + 3 );

				i += 3;
			}
			// cubic bezier
			else if ( _T('C') == element->GetCode (i) )
			{
				simplifier.PathCommandCurveTo ( element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1), 
					element->GetX(i+2), element->GetY(i+2) );

				LastPoint	=	element->Get ( i + 2 );

				++i;
				++i;
			}
			else if ( _T('c') == element->GetCode (i) )
			{
				simplifier.PathCommandCurveTo ( element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y,
					element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y,
					element->GetX(i+2) + LastPoint.X, element->GetY(i+2) + LastPoint.Y );

				LastPoint	+=	element->Get(i+2);

				++i;
				++i;
			}
			else if ( _T('S') == element->GetCode (i) )
			{
				if ( _T('C') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else if ( _T('c') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else if ( _T('S') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else if ( _T('s') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1) );
				}
				else
				{
					simplifier.PathCommandLineTo ( element->GetX(i+1), element->GetY(i+1) );
				}

				LastPoint	=	element->Get(i+1);							
				++i;
			}
			else if ( _T('s') == element->GetCode (i) )
			{
				if ( _T('C') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if ( _T('c') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if ( _T('S') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	element->Get ( i - 1 );
					Point pReflect	=	element->Get ( i - 2 );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if ( _T('s') == element->GetCode ( i - 1 ) )
				{
					Point pAt		=	Point ( LastPoint.X, LastPoint.Y );
					Point pReflect	=	Point ( pAt.X - element->GetX(i-1) + element->GetX(i-2), pAt.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX		=	pAt.X - ( pReflect.X - pAt.X );
					double dY		=	pAt.Y - ( pReflect.Y - pAt.Y );

					simplifier.PathCommandCurveTo ( dX, dY, element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y, element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );
				}
				else if (_T('m') == element->GetCode(i - 1) 
					|| _T('l') == element->GetCode(i - 1)
					|| _T('v') == element->GetCode(i - 1)
					||_T('h') == element->GetCode(i - 1))
				{
					simplifier.PathCommandCurveTo(LastPoint.X, LastPoint.Y,
						element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y,
						element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y);
				}
				else
				{
					simplifier.PathCommandLineTo(element->GetX(i+1), element->GetY(i+1));
				}

				LastPoint	+=	element->Get(i+1);							
				++i;
			}
			// quadratic bezier
			else if ( _T('q') == element->GetCode (i) )
			{
				simplifier.PathCommandCurveTo ( element->GetX(i) + LastPoint.X, element->GetY(i) + LastPoint.Y,
					element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y,
					element->GetX(i+1) + LastPoint.X, element->GetY(i+1) + LastPoint.Y );

				LastPoint	+=	element->Get(i+1);

				++i;
			}
			else if ( _T('Q') == element->GetCode (i) )
			{
				simplifier.PathCommandCurveTo ( element->GetX(i), element->GetY(i), element->GetX(i+1), element->GetY(i+1), element->GetX(i+1), element->GetY(i+1) );

				LastPoint	=	element->Get(i+1);

				++i;
			}
			else if ( _T('t') == element->GetCode(i))
			{
				Point p1 = oPath.GetPoints()[ i - 1 ].oPoint;
				Point p2 = oPath.GetPoints()[ i - 2 ].oPoint;
				Point p3 = oPath.GetPoints()[ i	+ 0	].oPoint;

				if ( _T('Q') == element->GetCode ( i - 1 ) )
				{
					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					simplifier.PathCommandCurveTo ( dX, dY, p3.X + LastPoint.X, p3.Y + LastPoint.Y, p3.X + LastPoint.X, p3.Y + LastPoint.Y );
				}
				else if ( _T('q') == element->GetCode ( i - 1 ) )
				{
					p1 = Point ( LastPoint.X, LastPoint.Y );
					p2 = Point ( p1.X - element->GetX(i-1) + element->GetX(i-2), p1.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					simplifier.PathCommandCurveTo ( dX, dY, p3.X + LastPoint.X, p3.Y + LastPoint.Y, p3.X + LastPoint.X, p3.Y + LastPoint.Y );
				}
				else
				{
					simplifier.PathCommandLineTo ( element->GetX(i), element->GetY(i) );
				}

				LastPoint	+=	element->Get(i);							
			}
			else if (_T('T') == element->GetCode(i))
			{
				Point p1 = oPath.GetPoints()[ i - 1 ].oPoint;
				Point p2 = oPath.GetPoints()[ i - 2 ].oPoint;
				Point p3 = oPath.GetPoints()[ i + 0 ].oPoint;

				if ( _T('Q') == element->GetCode ( i - 1 ) )
				{
					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					simplifier.PathCommandCurveTo ( dX, dY, p3.X, p3.Y, p3.X, p3.Y );
				}
				else if ( _T('q') == element->GetCode ( i - 1 ) )
				{
					p1 = Point ( LastPoint.X, LastPoint.Y );
					p2 = Point ( p1.X - element->GetX(i-1) + element->GetX(i-2), p1.Y - element->GetY(i-1) + element->GetY(i-2) );

					double dX	=	p1.X - ( p2.X - p1.X );
					double dY	=	p1.Y - ( p2.Y - p1.Y );

					simplifier.PathCommandCurveTo ( dX, dY, p3.X, p3.Y, p3.X, p3.Y );
				}
				else
				{
					simplifier.PathCommandLineTo ( element->GetX(i), element->GetY(i) );
				}

				LastPoint	+=	element->Get(i);							
			}
		}

		return TRUE;
	}

	BOOL Painter::SetBrushStyle (const Style& style, const CString& strClassName)
	{
		double alpha	=	style.DoubleAttribute(Opacity);

		m_render->put_BrushType(c_BrushTypeSolid);

		ISvgRef* pFill	=	style.GetFill();
		if (pFill)
		{
			if (ELinearGradient == pFill->nodeType())
			{
				LinearGradient* gradient = static_cast<LinearGradient*>(pFill);
				if (gradient)
				{
					if (gradient->GetColors().Count())
					{
						m_render->put_BrushColor1(gradient->GetColors().Get(0).m_nColor);
						m_render->put_BrushAlpha1((long)(gradient->GetColors().Get(0).m_fOpacity * 255.0 * alpha));

						VARIANT oVar;
						oVar.vt			=	VT_BSTR;
						oVar.bstrVal	=	CComBSTR(gradient->GetXml());
						m_render->SetAdditionalParam(L"Fill-LinearGradient", oVar);
					}
				}
			}
			else if (ERadialGradient == pFill->nodeType())
			{
				RadialGradient* gradient = static_cast<RadialGradient*>(pFill);
				if (gradient)
				{
					if (gradient->GetColors().Count())
					{
						m_render->put_BrushColor1(gradient->GetColors().Get(0).m_nColor);
						m_render->put_BrushAlpha1((long)(gradient->GetColors().Get(0).m_fOpacity * 255.0 * alpha));

						VARIANT oVar;
						oVar.vt			=	VT_BSTR;
						oVar.bstrVal	=	CComBSTR(gradient->GetXml());
						m_render->SetAdditionalParam(L"Fill-RadialGradient", oVar);
					}
				}
			}
			else if (EPattern == pFill->nodeType())
			{
				DoPattern (static_cast<Pattern*>(pFill));
			}

			return TRUE;
		}

		long lLongAttribute =	style.LongAttribute(FillColor);
		double dAlplaFill	=	style.DoubleAttribute(FillOpacity);

		if (-3 == lLongAttribute)
		{
			int nFound = strClassName.Find(_T("fill"));

			LONG lRendererType = 0;
			m_render->get_Type(&lRendererType);
			if ((c_nSVGConverter != lRendererType) || (nFound == -1))
			{
				m_render->put_BrushColor1 ( 0 );
			}
			m_render->put_BrushAlpha1 ( (LONG)( dAlplaFill * 255.0 * alpha) );
			return TRUE;
		}

		if (-2 == lLongAttribute)
			return FALSE;

		if (dAlplaFill > 0.0 && (-1 != lLongAttribute) && (alpha > 0.0))
		{
			if (!style.ValidAttribute(FillColor))
			{
				LONG lRendererType = 0;
				m_render->get_Type(&lRendererType);
				if (c_nSVGConverter == lRendererType)
				{
					int nFound = strClassName.Find(_T("fill"));
					
					if (-1 == nFound)
						m_render->put_BrushColor1 ( 0 );					

					m_render->put_BrushAlpha1 ( (LONG)( dAlplaFill * 255.0 * alpha) );
					return TRUE;
				}
			}

			m_render->put_BrushColor1 ( lLongAttribute );
			m_render->put_BrushAlpha1 ( (LONG)( dAlplaFill * 255.0 * alpha) );

			return TRUE;
		}

		if ((strClassName.GetLength () > 1) && (-1 == lLongAttribute ) && (alpha > 0.0))
		{
			m_render->put_BrushColor1 (0);
			m_render->put_BrushAlpha1 ((LONG)( dAlplaFill * 255.0 * alpha));

			return TRUE;
		}

		return FALSE;
	}
	BOOL Painter::SetStrokeStyle (const Style& style, const CString& strClassName)
	{
		double alpha			=	style.DoubleAttribute(Opacity);
		double dAlplaStroke		=	style.DoubleAttribute (StrokeOpacity);
		long lColor				=	style.LongAttribute (StrokeColor);
		double dWidth			=	style.DoubleAttribute(StrokeWidth);

		ISvgRef* pStroke		=	style.GetStroke();
		if ((NULL != pStroke) && (dWidth > 0.0))
		{
			m_render->put_PenSize(dWidth * m_dAddMX);

			long nStrokeLineCap		=	style.LongAttribute(StrokeLineCap);
			long nStrokeLineJoin	=	style.LongAttribute(StrokeLineJoin);

			m_render->put_PenLineJoin((unsigned char)(style.LongAttribute(StrokeLineJoin)));

			if (-1 == nStrokeLineCap)
			{
				if (c_ag_LineJoinRound == nStrokeLineJoin)
					m_render->put_PenLineStartCap(c_ag_LineCapRoundAnchor);

				if (c_ag_LineJoinBevel == nStrokeLineJoin)
					m_render->put_PenLineStartCap(c_ag_LineCapTriangle);	//	видимо на строне рендера есть проблема с таким стилем

				if (c_ag_LineJoinMiter == nStrokeLineJoin)
					m_render->put_PenLineStartCap(c_ag_LineCapSquare);
			}
			else
			{
				m_render->put_PenLineStartCap((unsigned char)nStrokeLineCap);
			}

			if (ELinearGradient == pStroke->nodeType())
			{
				LinearGradient* gradient = static_cast<LinearGradient*>(pStroke);
				if (gradient)
				{
					if (gradient->GetColors().Count())
					{
						m_render->put_BrushColor1(gradient->GetColors().Get(0).m_nColor);
						m_render->put_BrushAlpha1((long)(gradient->GetColors().Get(0).m_fOpacity * 255.0 * alpha));

						VARIANT oVar;
						oVar.vt			=	VT_BSTR;
						oVar.bstrVal	=	CComBSTR(gradient->GetXml());
						m_render->SetAdditionalParam(L"Stroke-LinearGradient", oVar);
					}
				}
			}
			else if (ERadialGradient == pStroke->nodeType())
			{
				RadialGradient* gradient = static_cast<RadialGradient*>(pStroke);
				if (gradient)
				{
					if (gradient->GetColors().Count())
					{
						m_render->put_BrushColor1(gradient->GetColors().Get(0).m_nColor);
						m_render->put_BrushAlpha1((long)(gradient->GetColors().Get(0).m_fOpacity * 255.0 * alpha));

						VARIANT oVar;
						oVar.vt			=	VT_BSTR;
						oVar.bstrVal	=	CComBSTR(gradient->GetXml());
						m_render->SetAdditionalParam(L"Stroke-RadialGradient", oVar);
					}
				}
			}

			return TRUE;
		}

		if (dAlplaStroke > 0.0 && dWidth > 0.0 && ( 0 <= lColor ) && alpha > 0.0)
		{
			m_render->put_PenColor(lColor);
			m_render->put_PenSize(dWidth * m_dAddMX);
			m_render->put_PenAlpha((LONG)(dAlplaStroke * 255.0 * alpha));

			long nStrokeLineCap		=	style.LongAttribute(StrokeLineCap);
			long nStrokeLineJoin	=	style.LongAttribute(StrokeLineJoin);

			m_render->put_PenLineJoin((unsigned char)(style.LongAttribute(StrokeLineJoin)));

			if (-1 == nStrokeLineCap)
			{
				if (c_ag_LineJoinRound == nStrokeLineJoin)
					m_render->put_PenLineStartCap(c_ag_LineCapRoundAnchor);

				if (c_ag_LineJoinBevel == nStrokeLineJoin)
					m_render->put_PenLineStartCap(c_ag_LineCapTriangle);	//	видимо на строне рендера есть проблема с таким стилем

				if (c_ag_LineJoinMiter == nStrokeLineJoin)
					m_render->put_PenLineStartCap(c_ag_LineCapSquare);
			}
			else
			{
				m_render->put_PenLineStartCap((unsigned char)nStrokeLineCap);
			}

			return TRUE;
		}

		long lLongAttribute = lColor;
		if (-2 == lLongAttribute)
			return FALSE;

		if (strClassName.GetLength () > 1 && (-1 == lLongAttribute))
		{
			m_render->put_PenColor	(0);
			m_render->put_PenSize	(dWidth);
			m_render->put_PenAlpha	((LONG)(dAlplaStroke * 255.0 * alpha));

			return TRUE;
		}

		return FALSE;
	}

	void Painter::DoRectangle(Rectangle* element, long type, BOOL clipMode)
	{
		if (!clipMode)
		{
			if ((fabs(element->GetArc().X) < 0.000001) && (fabs(element->GetArc().Y) < 0.000001))
			{
				m_render->PathCommandStart();
				m_render->BeginCommand(c_nPathType);

				m_render->PathCommandStart();

				m_render->PathCommandMoveTo(element->GetFrom().X, element->GetFrom().Y);
				m_render->PathCommandLineTo(element->GetTo().X, element->GetFrom().Y);
				m_render->PathCommandLineTo(element->GetTo().X, element->GetTo().Y);
				m_render->PathCommandLineTo(element->GetFrom().X, element->GetTo().Y);
				m_render->PathCommandLineTo(element->GetFrom().X, element->GetFrom().Y);

				m_render->DrawPath(type);
				m_render->EndCommand(c_nPathType);
				m_render->PathCommandEnd();
			}
			else
			{
				m_render->PathCommandStart();
				m_render->BeginCommand(c_nPathType);

				m_render->PathCommandStart();

				m_render->PathCommandMoveTo(element->GetFrom().X + element->GetArc().X, element->GetFrom().Y);

				m_render->PathCommandLineTo(element->GetTo().X - element->GetArc().X, element->GetFrom().Y);
				m_render->PathCommandArcTo(element->GetTo().X - element->GetArc().X * 2.0, element->GetFrom().Y, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 270.0, 90.0);

				m_render->PathCommandLineTo(element->GetTo().X, element->GetTo().Y - element->GetArc().Y);
				m_render->PathCommandArcTo(element->GetTo().X - element->GetArc().X * 2.0, element->GetTo().Y - element->GetArc().Y * 2.0, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 0.0, 90.0);

				m_render->PathCommandLineTo(element->GetFrom().X + element->GetArc().X, element->GetTo().Y);
				m_render->PathCommandArcTo(element->GetFrom().X, element->GetTo().Y - element->GetArc().Y * 2.0, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 90.0, 90.0);

				m_render->PathCommandLineTo(element->GetFrom().X, element->GetFrom().Y + element->GetArc().Y);
				m_render->PathCommandArcTo(element->GetFrom().X, element->GetFrom().Y, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 180.0, 90.0);

				m_render->DrawPath(type);
				m_render->EndCommand(c_nPathType);
				m_render->PathCommandEnd ();
			}
		}
		else
		{
			if ((fabs(element->GetArc().X) < 0.000001) && (fabs(element->GetArc().Y) < 0.000001))
			{
				m_render->PathCommandMoveTo(element->GetFrom().X, element->GetFrom().Y);
				m_render->PathCommandLineTo(element->GetTo().X, element->GetFrom().Y);
				m_render->PathCommandLineTo(element->GetTo().X, element->GetTo().Y);
				m_render->PathCommandLineTo(element->GetFrom().X, element->GetTo().Y);
				m_render->PathCommandLineTo(element->GetFrom().X, element->GetFrom().Y);
			}
			else
			{
				Aggplus::CGraphicsPathSimpleConverter simplifier;
				simplifier.SetRenderer(m_render);

				m_render->PathCommandMoveTo(element->GetFrom().X + element->GetArc().X, element->GetFrom().Y);

				m_render->PathCommandLineTo(element->GetTo().X - element->GetArc().X, element->GetFrom().Y);
				simplifier.PathCommandArcTo(element->GetTo().X - element->GetArc().X * 2.0, element->GetFrom().Y, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 270.0, 90.0);

				m_render->PathCommandLineTo(element->GetTo().X, element->GetTo().Y - element->GetArc().Y);
				simplifier.PathCommandArcTo(element->GetTo().X - element->GetArc().X * 2.0, element->GetTo().Y - element->GetArc().Y * 2.0, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 0.0, 90.0);

				m_render->PathCommandLineTo(element->GetFrom().X + element->GetArc().X, element->GetTo().Y);
				simplifier.PathCommandArcTo(element->GetFrom().X, element->GetTo().Y - element->GetArc().Y * 2.0, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 90.0, 90.0);

				m_render->PathCommandLineTo(element->GetFrom().X, element->GetFrom().Y + element->GetArc().Y);
				simplifier.PathCommandArcTo(element->GetFrom().X, element->GetFrom().Y, element->GetArc().X * 2.0, element->GetArc().Y * 2.0, 180.0, 90.0);
			}
		}
	}
	void Painter::DoCircle(Circle* element, long type, BOOL clipMode)
	{
		if (!clipMode)
		{
			m_render->PathCommandStart();
			m_render->BeginCommand (c_nPathType);

			m_render->PathCommandStart ();

			m_render->PathCommandMoveTo(element->m_C.X + element->m_R.X, element->m_C.Y);
			m_render->PathCommandArcTo(element->m_C.X - element->m_R.X, element->m_C.Y - element->m_R.Y, element->m_R.X * 2.0, element->m_R.Y * 2.0, 0, 359.9999);

			m_render->DrawPath (type);
			m_render->EndCommand (c_nPathType);

			m_render->PathCommandEnd ();
		}
		else
		{
			Aggplus::CGraphicsPathSimpleConverter simplifier;
			simplifier.SetRenderer(m_render);

			simplifier.PathCommandMoveTo(element->m_C.X + element->m_R.X, element->m_C.Y);
			simplifier.PathCommandArcTo(element->m_C.X - element->m_R.X, element->m_C.Y - element->m_R.Y, element->m_R.X * 2.0, element->m_R.Y * 2.0, 0, 359.9999);
		}
	}
	void Painter::DoEllipse(Ellipse* element, long type, BOOL clipMode)
	{
		if (!clipMode)
		{
			m_render->PathCommandStart();
			m_render->BeginCommand (c_nPathType);

			m_render->PathCommandStart();

			m_render->PathCommandMoveTo(element->m_C.X + element->m_R.X, element->m_C.Y);
			m_render->PathCommandArcTo(element->m_C.X - element->m_R.X, element->m_C.Y - element->m_R.Y, element->m_R.X * 2.0, element->m_R.Y * 2.0, 0, 359.9999);

			m_render->DrawPath (type);
			m_render->EndCommand (c_nPathType);
			m_render->PathCommandEnd ();
		}
		else
		{
			Aggplus::CGraphicsPathSimpleConverter simplifier;
			simplifier.SetRenderer(m_render);

			simplifier.PathCommandMoveTo(element->m_C.X + element->m_R.X, element->m_C.Y);
			simplifier.PathCommandArcTo(element->m_C.X - element->m_R.X, element->m_C.Y - element->m_R.Y, element->m_R.X * 2.0, element->m_R.Y * 2.0, 0, 359.9999);
		}
	}
	void Painter::DoPolyline(Polyline* element, long type, BOOL clipMode)
	{
		if (!clipMode)
		{
			if (element->GetSize())
			{
				m_render->PathCommandStart();
				m_render->BeginCommand (c_nPathType);

				m_render->PathCommandStart();

				m_render->PathCommandMoveTo (element->GetX(0), element->GetY(0));

				for (long i = 1; i < element->GetSize (); ++i)
					m_render->PathCommandLineTo (element->GetX(i), element->GetY(i));

				m_render->PathCommandLineTo (element->GetX(0), element->GetY(0));

				m_render->DrawPath (type);
				m_render->EndCommand (c_nPathType);
				m_render->PathCommandEnd ();
			}
		}
		else
		{
			m_render->PathCommandMoveTo (element->GetX(0), element->GetY(0));

			for (long i = 1; i < element->GetSize (); ++i)
				m_render->PathCommandLineTo (element->GetX(i), element->GetY(i));

			m_render->PathCommandLineTo (element->GetX(0), element->GetY(0));
		}
	}
	void Painter::DoPolygon(Polygon* element, long type, BOOL clipMode)
	{
		if (!clipMode)
		{
			if (element->GetSize())
			{
				m_render->PathCommandStart();
				m_render->BeginCommand (c_nPathType);

				m_render->PathCommandStart ();

				m_render->PathCommandMoveTo (element->GetX(0), element->GetY(0));

				for (long i = 1; i < element->GetSize (); ++i)
					m_render->PathCommandLineTo (element->GetX(i), element->GetY(i));

				m_render->PathCommandLineTo (element->GetX(0), element->GetY(0));

				m_render->DrawPath (type);
				m_render->EndCommand (c_nPathType);
				m_render->PathCommandEnd ();
			}
		}
		else
		{
			m_render->PathCommandMoveTo (element->GetX(0), element->GetY(0));

			for (long i = 1; i < element->GetSize (); ++i)
				m_render->PathCommandLineTo (element->GetX(i), element->GetY(i));

			m_render->PathCommandLineTo (element->GetX(0), element->GetY(0));
		}
	}
	void Painter::DoPath(Path* element, long type, BOOL clipMode)
	{
		if (!clipMode)
		{
			PushPathCommands (element, type);
		}
		else
		{
			ClipPathCommands (element, type);
		}
	}

	// clip 

	BOOL Painter::DoClip(ISvgRef* pRef, BOOL enable)
	{
		if (NULL == pRef)
			return FALSE;

		if (EClipPath == pRef->nodeType())
		{
			ClipPath* pClip = static_cast<ClipPath*>(pRef);
			if (pClip)
			{
				if (enable)
				{
					if (pClip->GetCount())
					{
						m_render->BeginCommand(c_nClipType);
						m_render->BeginCommand(c_nPathType);

						for (long i = 0; i < pClip->GetCount(); ++i)
						{
							ISvgRef* drawElement = pClip->GetAt(i);
							ENodeType code = drawElement->nodeType();
							if (EUse == code)
							{
								drawElement = FindEntry(static_cast<Use*>(drawElement));
								if (NULL == drawElement)
									continue;

								code = drawElement->nodeType();
							}

							switch (code)
							{
							case ECircle:		DoCircle(static_cast<Circle*>(drawElement), 0, TRUE);		break;
							case ERectangle:	DoRectangle(static_cast<Rectangle*>(drawElement), 0, TRUE);	break;
							case EEllipse:		DoEllipse(static_cast<Ellipse*>(drawElement), 0, TRUE);		break;
							case EPolyline:		DoPolyline(static_cast<Polyline*>(drawElement), 0, TRUE);	break;
							case EPolygon:		DoPolygon(static_cast<Polygon*>(drawElement), 0, TRUE);		break;
							case EPath:			DoPath(static_cast<Path*>(drawElement), 0, TRUE);			break;
							}

							m_render->PathCommandClose ();
						}

						m_render->EndCommand(c_nPathType);
						m_render->EndCommand(c_nClipType);
						m_render->PathCommandEnd();

						return TRUE;
					}

					return FALSE;
				}				
				else 
				{
					m_render->BeginCommand(c_nResetClipType);
					m_render->EndCommand(c_nResetClipType);
				}
			}
		}

		return FALSE;
	}

	// image

	BOOL Painter::DrawImageFromFile(Image* element, CString texturePath)
	{
		if (0 == texturePath.GetLength())
			texturePath = element->m_ImagePath;

		if (0 == texturePath.GetLength())
			return FALSE;

		DoClip (element->GetClip(), TRUE);

		BSTR filePath = texturePath.AllocSysString();

		LONG type = 0;
		type += c_nWindingFillMode;

		m_render->put_BrushType(c_BrushTypeTexture);
		m_render->put_BrushTexturePath(filePath);
		m_render->put_BrushTextureMode(0);

		m_render->PathCommandStart();
		m_render->BeginCommand(c_nPathType);

		m_render->PathCommandStart();

		m_render->PathCommandMoveTo(element->GetFrom().X, element->GetFrom().Y);
		m_render->PathCommandLineTo(element->GetFrom().X + element->GetSize().X, element->GetFrom().Y);
		m_render->PathCommandLineTo(element->GetFrom().X + element->GetSize().X, element->GetFrom().Y + element->GetSize().Y);
		m_render->PathCommandLineTo(element->GetFrom().X, element->GetFrom().Y + element->GetSize().Y);
		m_render->PathCommandLineTo(element->GetFrom().X, element->GetFrom().Y);

		m_render->DrawPath(type);
		m_render->EndCommand(c_nPathType);
		m_render->PathCommandEnd();

		SysFreeString (filePath);

		DoClip (element->GetClip(), FALSE);

		return TRUE;
	}
	BOOL Painter::DoPattern(Pattern* element)
	{
		if (NULL == element)
			return FALSE;

		if (0 == element->GetSize() || 0 == element->nodeId().GetLength())
			return FALSE;

		PatternImage* patternImage = NULL;
		CAtlMap<CString, PatternImage*>::CPair* cp = m_patterns.Lookup(element->nodeId());
		if (NULL == cp)
		{
			patternImage = new PatternImage(element, m_render, this);
			if (patternImage)
			{
				m_patterns.SetAt(element->nodeId(), patternImage);
			}
		}
		else
		{
			patternImage = cp->m_value;
		}

		if (NULL == patternImage)
			return FALSE;

		m_render->put_BrushType(c_BrushTypeTexture);
		m_render->put_BrushTexturePath(CComBSTR(patternImage->LivePath()));
		m_render->put_BrushTextureMode(c_BrushTextureModeTile);

		return TRUE;

		for (long i = 0; i < element->GetSize(); ++i)
		{
			ISvgRef* drawElement = element->Get(i);
			ENodeType code = drawElement->nodeType();

			if (EImage == code)
			{
				Image* imageElement = static_cast<Image*>(drawElement);
				if (imageElement)
				{
					CString path = imageElement->LivePath(m_sWorkingDirectory);
					if (path.GetLength())
					{
						m_render->put_BrushType(c_BrushTypeTexture);
						m_render->put_BrushTexturePath(CComBSTR(path));
						m_render->put_BrushTextureMode(c_BrushTextureModeTile);
					}
				}
			}	
		}

		return TRUE;
	}

	// arc

	double Painter::GetAngle(const double& CX, const double& CY, const double& X, const double& Y)
	{
		double dAngle = 0.0;

		if ( (X - CX) == 0.0 && 0.0 == (Y - CY) )	//	
			return 0.0;

		if ( (X - CX) > 0.0 && 0.0 == (Y - CY) )
			return 0.0;
		if ( (X - CX) < 0.0 && 0.0 == (Y - CY) )
			return 180.0;
		if ( (X - CX) == 0.0 && 0.0 > (Y - CY) )
			return 270.0;
		if ( (X - CX) == 0.0 && 0.0 < (Y - CY) )
			return 90.0;

		dAngle	=	atan ( abs ( X - CX ) / abs ( Y - CY ) ) * 180.0 / M_PI;

		if ( (X - CX) > 0.0 && (Y - CY) > 0.0 )			//	1
		{
			dAngle	=	90.0 - dAngle;
		}

		if ( (X - CX) < 0.0 && (Y - CY) > 0.0 )			//	2
		{
			dAngle	+=	90.0;
		}

		if ( ( (X - CX) < 0.0) && ((Y - CY) < 0.0) )	//	3
		{
			dAngle	=	( 90.0 - dAngle ) + 180.0;
		}

		if ( (X - CX) > 0.0 && (Y - CY) < 0.0 )			//	4
		{
			dAngle	+=	270.0;
		}

		return dAngle;
	}
	Point Painter::GetCenter(int LargeFlag, int SweepFlag, Point Radi, Point P1, Point P2)
	{
		double RadF	=	Radi.Y / Radi.X;

		Point Begin	=	Point ( P1.X * RadF, P1.Y );
		Point End	=	Point ( P2.X * RadF, P2.Y );

		Point Mid	=	Point ( ( Begin.X + End.X ) * 0.5, ( Begin.Y + End.Y ) * 0.5 );
		Point Vec	=	Point ( Begin.X - End.X, Begin.Y - End.Y );

		double HChord	=  sqrt ( Vec.X * Vec.X + Vec.Y * Vec.Y ) * 0.5;

		Point Rot;

		if ( LargeFlag == SweepFlag )
			Rot		=	Point ( -Vec.Y, Vec.X );
		else
			Rot		=	Point ( Vec.Y, -Vec.X );

		Rot.X		/=	( HChord * 2.0 );
		Rot.Y		/=	( HChord * 2.0 );

		double Ch	=	sqrt ( abs ( Radi.Y * Radi.Y - HChord * HChord ) );

		return Point ( ( Mid.X + Ch * Rot.X ) / RadF, Mid.Y + Ch * Rot.Y );
	}
	BOOL Painter::GetArcAngles(int LargeFlag, int SweepFlag, const double& dStartAngle, const double& dEndAngle, double& dSweep)	
	{
		dSweep		=	0.0;

		if ( 1 == LargeFlag && 0 == SweepFlag )
		{
			if ( abs ( dEndAngle - dStartAngle ) > 180 )
				dSweep	=	dEndAngle - dStartAngle;
			else
				dSweep	=	- ( 360 - abs ( dEndAngle - dStartAngle ) );

			if ( SweepFlag ) 
				dSweep	=	abs ( dSweep );
			else
				dSweep	=	-abs ( dSweep );
		}
		else if ( 0 == LargeFlag && 1 == SweepFlag )	
		{
			if ( abs ( dEndAngle - dStartAngle ) < 180 )
				dSweep	=	dEndAngle - dStartAngle;
			else
				dSweep	=	360 - abs ( dEndAngle - dStartAngle );

			if ( SweepFlag ) 
				dSweep	=	abs ( dSweep );
			else
				dSweep	=	-abs ( dSweep );
		}
		else if ( 0 == LargeFlag && 0 == SweepFlag )
		{
			if ( abs ( dEndAngle - dStartAngle ) > 180 )
				dSweep	=	dEndAngle - dStartAngle;
			else
				dSweep	=	- ( 360 - abs ( dEndAngle - dStartAngle ) );

			if ( SweepFlag ) 
				dSweep	=	abs ( dEndAngle - dStartAngle );
			else
				dSweep	=	-abs ( dEndAngle - dStartAngle );
		}
		else if ( 1 == LargeFlag && 1 == SweepFlag )
		{
			if ( abs ( dEndAngle - dStartAngle ) > 180 )
				dSweep	=	dEndAngle - dStartAngle;
			else
				dSweep	=	- ( 360 - abs ( dEndAngle - dStartAngle ) );

			if ( SweepFlag ) 
				dSweep	=	abs ( dSweep );
			else
				dSweep	=	-abs ( dSweep );
		}

		return TRUE;
	}
}

namespace SVG
{
	BOOL PatternImage::Build()
	{
		if (NULL == m_pattern)
			return FALSE;

		if (NULL == m_pFrame && NULL == m_render)
		{
			if (InitFrame() && InitPatternFrame())
			{
				if (InitRender(m_pFrame, m_pattern->GetBox().GetWidth(), m_pattern->GetBox().GetHeight()))
				{
					return Render();
				}
			}
		}

		return FALSE;
	}
	BOOL PatternImage::InitFrame()
	{
		if (m_pFrame)
			return TRUE;

		if (SUCCEEDED(CoCreateInstance(MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)&m_pFrame)))
		{
			int Width		=	m_pattern->GetBox().GetWidth();
			int Height		=	m_pattern->GetBox().GetHeight();

			m_pFrame->put_Width(Width);
			m_pFrame->put_Height(Height);
			m_pFrame->put_Stride(0, 4 * Width);

			m_pFrame->put_AspectRatioX(Width);
			m_pFrame->put_AspectRatioY(Height);

			m_pFrame->put_ColorSpace(CSP_BGRA);
			m_pFrame->AllocateBuffer(-1);

			BYTE* pBuffer = NULL;
			m_pFrame->get_Buffer(&pBuffer);

			if (pBuffer)
			{
				memset (pBuffer, 0, 4 * Width * Height);
			}
		}

		return (NULL != m_pFrame);
	}
	BOOL PatternImage::InitPatternFrame()
	{
		if (m_pPatternFrame)
			return TRUE;

		if (SUCCEEDED(CoCreateInstance(MediaCore::CLSID_CAVSUncompressedVideoFrame, NULL, CLSCTX_ALL, MediaCore::IID_IAVSUncompressedVideoFrame, (void**)&m_pPatternFrame)))
		{
			m_pPatternFrame->put_Width(m_pattern->GetBound().GetWidth());
			m_pPatternFrame->put_Height(m_pattern->GetBound().GetHeight());
			m_pPatternFrame->put_Stride(0, 4 * m_pattern->GetBound().GetWidth());

			m_pPatternFrame->put_AspectRatioX(m_pattern->GetBound().GetWidth());
			m_pPatternFrame->put_AspectRatioY(m_pattern->GetBound().GetHeight());

			m_pPatternFrame->put_ColorSpace(CSP_BGRA);
			m_pPatternFrame->AllocateBuffer(-1);

			BYTE* pBuffer = NULL;
			m_pPatternFrame->get_Buffer(&pBuffer);

			if (pBuffer)
			{
				memset (pBuffer, 0, 4 * m_pattern->GetBound().GetWidth() * m_pattern->GetBound().GetHeight());
			}
		}

		return (NULL != m_pFrame);
	}
	BOOL PatternImage::InitRender(IUnknown* frame, int frameWidth, int frameHeight)
	{
		if (m_render)
			return TRUE;

		if (SUCCEEDED(CoCreateInstance(__uuidof(CASCGraphicsRenderer), NULL, CLSCTX_ALL, __uuidof(IASCGraphicsRenderer), (void**)&m_render)))
		{
			m_render->CreateFromMediaData(frame, 0, 0, frameWidth, frameHeight);

			if (m_baseRender)
			{
				VARIANT vt;
				if (SUCCEEDED(m_baseRender->GetAdditionalParam(L"FontManager", &vt)))
				{
					if (vt.vt == VT_UNKNOWN && NULL != vt.punkVal)
					{
						m_render->SetAdditionalParam(L"FontManager", vt);
					}
				}
			}
		}

		return (NULL != m_render);
	}
	BOOL PatternImage::Render()
	{
		Point factor = GetNormalizeFactor();
		m_pattern->NormalizeEx(factor.X, factor.Y);

		Painter painter;
		painter.SetWorkingDirectory(m_basePainter->GetWorkingDirectory());
		painter.Draw(m_pattern, m_render, m_basePainter->GetUs());

		RELEASEINTERFACE(m_render);
		if (InitRender(m_pPatternFrame, m_pattern->GetBound().GetWidth(), m_pattern->GetBound().GetHeight()))
		{
			Point dpi;
			
			m_render->get_DpiX(&dpi.X);
			m_render->get_DpiY(&dpi.Y);

			Point sizes;

			m_render->get_Width(&sizes.X);
			m_render->get_Height(&sizes.Y);

			if ((fabs(dpi.X) < 0.000001) || (fabs(dpi.Y) < 0.000001))
			{
				dpi.X = m_basePainter->GetUs().GetWidth() / sizes.X * 25.4;
				dpi.Y = m_basePainter->GetUs().GetHeight() / sizes.Y * 25.4;

				if ((fabs(dpi.X) < 0.000001) || (fabs(dpi.Y) < 0.000001))
				{
					return FALSE;
				}
			}

			Point mul			=	Point(25.4 / dpi.X, 25.4 / dpi.Y);

			int Width			=	m_pattern->GetBound().GetWidth();
			int Height			=	m_pattern->GetBound().GetHeight();

			if (_T("none") != m_pattern->PreserveAspectRatio())			//	TODO: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
			{
				if (0 == m_pattern->PreserveAspectRatio().GetLength())	 
				{
					double dfX	=	(double)m_pattern->GetBox().GetWidth() / (double)m_pattern->GetBound().GetWidth();
					double dfY	=	(double)m_pattern->GetBox().GetHeight() / (double)m_pattern->GetBound().GetHeight();

					double dF	=	dfX / dfY - 1.0;
					if (!(fabs(dF) < 0.000001))
					{
						dfY		/=	__min(dfY, dfX);
						dfX		/=	__min(dfY, dfX);

						Width	/=	dfY;
						Height	/=	dfX;
					}
				}
			}

			if (0 == (int)m_pattern->GetBound().GetX() && 0 == (int)m_pattern->GetBound().GetY())
			{
				m_render->DrawImage(m_pFrame, 0, 0, Width * mul.X, Height * mul.Y);
			}
			else
			{
				// сдвинутый тайл

				Point move	=	Point (m_pattern->GetBound().GetX(), m_pattern->GetBound().GetY());

				if (m_pattern->GetBound().GetX() > m_pattern->GetBound().GetWidth())
					move.X	=	(double) ( (int)m_pattern->GetBound().GetX() % (int)m_pattern->GetBound().GetWidth());

				if (m_pattern->GetBound().GetY() > m_pattern->GetBound().GetHeight())
					move.Y	=	(double) ( (int)m_pattern->GetBound().GetY() % (int)m_pattern->GetBound().GetHeight());

				Point t		=	Point (move.X * mul.X, move.Y * mul.Y);

				m_render->DrawImage(m_pFrame, t.X,					t.Y,					Width * mul.X, Height * mul.Y);
				m_render->DrawImage(m_pFrame, t.X - Width * mul.X,	t.Y - Height * mul.Y,	Width * mul.X, Height * mul.Y);
				m_render->DrawImage(m_pFrame, t.X,					t.Y - Height * mul.Y,	Width * mul.X, Height * mul.Y);
				m_render->DrawImage(m_pFrame, t.X - Width * mul.X,	t.Y,					Width * mul.X, Height * mul.Y);
			}

			m_sLivePath.Format (_T("%s\\%s.png"), FileUtils::GetTempFolder(), m_pattern->nodeId());
			SaveImage(m_pPatternFrame, m_sLivePath);
		}

		// освободим память

		RELEASEINTERFACE(m_render);
		RELEASEINTERFACE(m_pFrame);
		RELEASEINTERFACE(m_pPatternFrame);

		return TRUE;
	}
	BOOL PatternImage::SaveImage(IUnknown* punkFrame, CString file)
	{
		return ImageStudio::SaveImageAsPNG(punkFrame, file);		
	}
	Point PatternImage::GetNormalizeFactor()
	{
		if (m_render)
		{
			Point dpi;
			
			m_render->get_DpiX(&dpi.X);
			m_render->get_DpiY(&dpi.Y);

			Point sizes;

			m_render->get_Width(&sizes.X);
			m_render->get_Height(&sizes.Y);

			if ((fabs(dpi.X) < 0.000001) || (fabs(dpi.Y) < 0.000001))
			{
				dpi.X		=	m_basePainter->GetUs().GetWidth() / sizes.X * 25.4;
				dpi.Y		=	m_basePainter->GetUs().GetHeight() / sizes.Y * 25.4;
			}

			return Point(25.4 / dpi.X, 25.4 / dpi.Y);
		}

		return Point(1.0, 1.0);
	}
}
