/*************************************************************************************************/
/*!
   	@file		LoaderVectorfile_svg.h
	@author 	Fanzo
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files
#include	"iFace/iLoaderVectorfile.h"
#include	<stdio.h>

#pragma pack( push , 8 )		//set align

namespace icubic
{
using namespace XERCES_CPP_NAMESPACE;

///////////////////////////////////////////////////////////////////////////////////////////////////
// preprocessor deifne


///////////////////////////////////////////////////////////////////////////////////////////////////
// type define

///////////////////////////////////////////////////////////////////////////////////////////////////
// classes define

/**************************************************************************************************
"LoaderVectorfile_svg" class 
**************************************************************************************************/
class LoaderVectorfile_svg : 
	virtual public object_base , 
	public ILoaderVectorfile
{
// query
	query_begin();
	iface_hook( ILoaderVectorfile , ILoaderVectorfile_IID )
	query_end( object_base );

// member class
private:
	class Idlist
	{
		class IdData
		{
		public:
			IdData*	m_next;
			wstring	m_id;
			IdData() : m_next( 0 ){}
		};
		IdData*		m_first;
	public:
		//=================================================================================================
		Idlist() : m_first( 0 )
		{
		}
		//=================================================================================================
		~Idlist()
		{
			cb_assert( m_first == 0 , L"Idlist algorithm error." );
			IdData*	p = m_first;
			while( p != 0 )
			{
				IdData*	n = p->m_next;
				delete p;
				p	= n;
			}
			m_first	= 0;
		}
		//=================================================================================================
		void Push
				(
				const wstring&	id
				)
		{
			IdData*	d	= new IdData();
			d->m_id		= id;
			d->m_next	= m_first;
			m_first	= d;
		}
		//=================================================================================================
		void Pop()
		{
			cb_assert( m_first != 0 , L"Idlist Pop error." );
			IdData*	d = m_first;
			m_first	= d->m_next;
			delete	d;
		}
		//=================================================================================================
		bool Search
				(
				const wstring&	id
				)
		{
			IdData*	p = m_first;
			while( p != 0 )
			{
				if( p->m_id == id )
					return true;
				p	= p->m_next;
			}
			return false;
		}
	};
	class SearchFolders
	{
		Array<wstring>		m_folders;
	public:
		//=================================================================================================
		void ToAbs
				(
				const wstring&		path , 
				Array<wstring>&		abs
				)
		{
			int		pos = 0;
			if( true == MatchString( path , &pos , L"[a-zA-Z]+:[/]+" , 0 ) )
			{
				abs[abs.Add()]	= path;
				return;
			}
			int		off , num = m_folders.GetDatanum();
			for( off = 0 ; off < num ; off++ )
				abs[abs.Add()]	= m_folders[off] + L"/" + path;
		}
		//=================================================================================================
		void AddFolder
				(
				const wchar_t*		folder
				)
		{
			m_folders[m_folders.Add()]	= folder;
		}
	};
	class Imagelist
	{
		class ImageData
		{
		public:
			wstring			m_path;
			iSurfaceSource	m_image;
		};
		Array<ImageData>	m_imagelist;
	private:
		//=================================================================================================
		iSurfaceSource LoadImage
				(
				const wstring&		path , 
				iLoaderImagefile&	loader
				)
		{
			instance< FileReader >			file;
			if( false == file->Open( path.c_str() ) )
				return iSurfaceSource();
			if( false == loader->Load( ( iFileStreamRead )file ) )
				return iSurfaceSource();

			iSurface	surface	= CreateSurface( loader->GetImageSize( 0 ) , rgba_pixelformat , loader->GetImageDPI( 0 ) );
			if( surface->GetDestAvailableArea() == irect( ivector2( 0 , 0 ) , loader->GetImageSize( 0 ) ) )
			{
				int		pitchbyte;
				void	*p = surface->GetDestPixelPtr( &pitchbyte );
				loader->GetImage( 0 , surface->GetDestFormat() , p , pitchbyte );
				return (iSurfaceSource)surface;
			}	
			return iSurfaceSource();
		}
	public:	
		//=================================================================================================
		void Reset()
		{
			m_imagelist.Resize( 0 );
		}
		//=================================================================================================
		iSurfaceSource GetImage
				(
				const wstring&	path
				)
		{
			int		off , num = m_imagelist.GetDatanum();
			for( off = 0 ; off < num ; off++ )
			{
				if( m_imagelist[off].m_path == path )
					return m_imagelist[off].m_image;
			}
			instance< LoaderImagefile >	loader;
			iSurfaceSource	img = LoadImage( path , (iLoaderImagefile)loader );
			if( img == true )
			{
				int	off = m_imagelist.Add();
				m_imagelist[off].m_path	= path;
				m_imagelist[off].m_image= img;
				return img;
			}
			return iSurfaceSource();
		}
	};
	class Attr
	{
	public:
		class PaintAttr
		{
		public:
			enum Type
			{
				None , 
				SolidColor , 
				GradLinear , 
				GradRadial , 
			};
		public:
			Type			m_type;
			rgba			m_color;
			PaintUnit		m_unit;
			point_ipr		m_start_vec;
			point_ipr		m_target_vec;
			point_ipr		m_center_vec;
			value_ipr		m_radius;
			Array<float>	m_rate_tbl;
			Array<rgba>		m_color_tbl;
			faffine			m_transform;
			PaintAttr
					(
					Type	type = SolidColor
					) : 
				m_type( type ) , 
				m_color( 0 , 0 , 0 , 255 ) , 
				m_unit( BoundBox_PaintUnit ) , 
				m_start_vec( value_ipr::ratio , fvector2( 0.0f , 0.0f ) ) , 
				m_target_vec( value_ipr::ratio , fvector2( 1.0f , 0.0f ) ) , 
				m_center_vec( value_ipr::ratio , fvector2( 0.5f , 0.5f ) ) , 
				m_radius( value_ipr::ratio , 0.5f )
			{
			}
		};
	public:
		enum StrokeLineCap
		{
			butt_cap , 
			round_cap , 
			square_cap , 
		};
		enum StrokeLineJoin
		{
			miter_join , 
			round_join , 
			bevel_join , 
		};
		enum FontStyle
		{
			normal_fontstyle , 
			italic_fontstyle , 
			oblique_fontstyle , 
		};
		enum FontVariant
		{
			normal_fontvariant , 
			small_caps_fontvariant , 
		};
		enum ImageQuarity
		{
			Nearest_imagequarity , 
			Linear_imagequarity , 
			Bicubic_imagequarity , 
		};
	public:
		Coord_view::AspectRatio	m_aspect; 
		Coord_view::Align		m_align_h;
		Coord_view::Align		m_align_v;
		PaintAttr				m_fill;
		float					m_fill_opacity;
		PathFillRule			m_fill_rule;
		PaintAttr				m_stroke;
		float					m_stroke_opacity;
		value_ipr				m_stroke_width;
		Array<value_ipr>		m_stroke_dash_array;
		value_ipr				m_stroke_dash_offset;
		StrokeLineCap			m_stroke_cap;
		StrokeLineJoin			m_stroke_join;
		Array<wstring>			m_font_family;
		value_ip				m_font_size;
		FontStyle				m_font_style;
		int						m_font_weight;
		rgba					m_stop_color;
		float					m_stop_opacity;
		rgba					m_color;
		float					m_opacity;
		iPathLogic				m_clippath;
		PathFillRule			m_clipfillrule;
		ImageQuarity			m_image_rendering;
		
	// public functions
	public:
		//=================================================================================================
		Attr()
		{
		}
		//=================================================================================================
		void Initialize()
		{
			m_aspect			= Coord_view::AspectMin;
			m_align_h			= Coord_view::MinAlign;
			m_align_h			= Coord_view::MaxAlign;
			m_fill				= PaintAttr();
			m_fill_opacity		= 1.0f;
			m_fill_rule			= Winding_PathFillRule;
			m_stroke			= PaintAttr( PaintAttr::None );
			m_stroke_opacity	= 1.0f;
			m_stroke_width		= value_ipr( value_ipr::px , 1.0f );
			m_stroke_dash_array.Resize( 0 );
			m_stroke_dash_offset= value_ipr( value_ipr::px , 0.0f );
			m_stroke_cap		= butt_cap;
			m_stroke_join		= miter_join;
			m_font_family.Resize( 0 );
			m_font_size			= value_ip( value_ip::inch , 10.0f / 72.0f );
			m_font_style		= normal_fontstyle;
			m_font_weight		= 400;
			m_stop_color		= rgb( 0 , 0 , 0 );
			m_stop_opacity		= 1.0f;
			m_color				= rgb( 0 , 0 , 0 );
			m_opacity			= 1.0f;
			m_clippath.release();
			m_clipfillrule		= Winding_PathFillRule;
			m_image_rendering	= Linear_imagequarity;
		}
	};
	class FillRefArgs
	{
	public:
		enum Type
		{
			Pre , 
			Post
		};
		Type					m_type;
		iElement_svg			m_root;
		iElement_svg			m_tag;
		Attr::PaintAttr*		m_attr;
	};
	class ClipRefArgs
	{
	public:
		enum Type
		{
			Pre , 
			Post
		};
		Type					m_type;
		IClip_clipcmds*			m_clip;
		iElement_svg			m_root;
		iElement_svg			m_tag;
	};
	class TagArgs
	{
	public:
		enum Type
		{
			Pre , 
			Post
		};
		Type					m_type;
		IGraphicsCmds*			m_cmds;
		iElement_svg			m_root;
		iElement_svg			m_tag;
	};	
// variable member
private:
	Stackdata<Attr>					m_stack;
	Imagelist						m_imagelist;
	Idlist							m_idlist;
	SearchFolders					m_search_folders;
	
	Stackdata<iElement_svg>			m_id_stack;
	Stackdata<FillRefArgs>			m_fillref_stack;
	Stackdata<ClipRefArgs>			m_clipref_stack;
	Stackdata<TagArgs>				m_tag_stack;
	
// private functions
private:
//=================================================================================================
void InitializeLoad()
{
	m_stack.Reset();
	m_stack.Push();
	m_stack->Initialize();
	m_imagelist.Reset();
}
//=================================================================================================
void FinalizeLoad()
{
	cb_assert( m_stack.GetDatanum() == 1 , L"stack algorithm error." );
	m_stack.Reset();
	m_imagelist.Reset();
}
//=================================================================================================
void PushStack()
{
	Attr*	prev = &( *m_stack );
	m_stack.Push();
	( *m_stack ) = ( *prev );
}
//=================================================================================================
void PopStack()
{
	if( m_stack.GetDatanum() <= 1 )
		return;
	m_stack.Pop();
}
//=================================================================================================
void PushId
		(
		iElement_svg&	tag
		)
{
	istdAttrs_svga	id = (istdAttrs_svga)tag;
	if( id == true && id->m_id == true )
		m_idlist.Push( id->m_id->m_value );
	else
		m_idlist.Push( L"" );
}
//=================================================================================================
void PopId()
{
	m_idlist.Pop();
}
//=================================================================================================
void Push
		(
		IGraphicsCmds*	cmds
		)
{
	PushStack();
	instance<PushAttr_cmd>	obj;
	cmds->AddCmd( (iGraphicsCmd)obj );
}
//=================================================================================================
void Pop
		(
		IGraphicsCmds*	cmds
		)
{
	instance<PopAttr_cmd>	obj;
	cmds->AddCmd( (iGraphicsCmd)obj );
	PopStack();
}
//=================================================================================================
iFont CreateFont()
{
	int		off , num = m_stack->m_font_family.GetDatanum();
	for( off = 0 ; off < num ; off++ )
	{
		instance<Font>	font;
		if( true == font->Create
				( 
				fsize( 0.0f , 10.0f ) , 
				m_stack->m_font_family[off] , 
				Unicode_FontCharsetType , 
				m_stack->m_font_weight < 600 ? FW_NORMAL : FW_BOLD , 
				( m_stack->m_font_style == Attr::normal_fontstyle ) ? false : true
				) )
				return (iFont)font;
	}
	{
		FontManager_bs		fm;
		FontsetInfo			fi	= fm.GetDefaultFontsetInfo();
		instance<Font>	font;
		if( true == font->Create
				( 
				fsize( 0.0f , 10.0f ) , 
				fi.m_facename , 
				fi.m_charset , 
				m_stack->m_font_weight < 600 ? FW_NORMAL : FW_BOLD , 
				( m_stack->m_font_style == Attr::normal_fontstyle ) ? false : true
				) )
				return (iFont)font;
	}
	return iFont();
}
//=================================================================================================
iPaint_ipr CreatePaint
		(
		Attr::PaintAttr&		attr , 
		const rgba&				stop_color , 
		float					stop_opacity
		)
{
	if( attr.m_type == Attr::PaintAttr::SolidColor )
	{
		instance<PaintSolidColor_ipr>	paint;
		paint->SetColor( attr.m_color.MulAlpha( ( uint8 )( 255 * m_stack->m_opacity * m_stack->m_fill_opacity ) ) );
		return (iPaint_ipr)paint;
	}
	else if( attr.m_type == Attr::PaintAttr::GradLinear )
	{
		if( attr.m_rate_tbl.GetDatanum() == 0 )
			return iPaint_ipr();
		if( attr.m_rate_tbl.GetDatanum() == 1 )
		{
			instance<PaintSolidColor_ipr>	paint;
			if( attr.m_color_tbl.GetDatanum() >= 1 )
				paint->SetColor( attr.m_color_tbl[0] );
			else
				paint->SetColor( rgba(0,0,0,255) );
			return (iPaint_ipr)paint;
		}	
		else
		{
			instance<PaintGradLinear_ipr>	paint;
			paint->SetPaintUnit( attr.m_unit );
			paint->SetTransform( attr.m_transform );
			paint->SetGradationVector( attr.m_start_vec , attr.m_target_vec );
			paint->SetColorTable( attr.m_rate_tbl.GetDatanum() , attr.m_rate_tbl.GetConstPtr() , attr.m_color_tbl.GetConstPtr() );
			return (iPaint_ipr)paint;
		}
	}
	else if( attr.m_type == Attr::PaintAttr::GradRadial )
	{
		if( attr.m_rate_tbl.GetDatanum() == 0 )
			return iPaint_ipr();
		if( attr.m_rate_tbl.GetDatanum() == 1 )
		{
			instance<PaintSolidColor_ipr>	paint;
			if( attr.m_color_tbl.GetDatanum() >= 1 )
				paint->SetColor( attr.m_color_tbl[0] );
			else
				paint->SetColor( rgba(0,0,0,255) );
			return (iPaint_ipr)paint;
		}	
		else
		{
			instance<PaintGradRadial_ipr>	paint;
			paint->SetPaintUnit( attr.m_unit );
			paint->SetTransform( attr.m_transform );
			paint->SetGradationVector( attr.m_center_vec , attr.m_radius );		
			paint->SetColorTable( attr.m_rate_tbl.GetDatanum() , attr.m_rate_tbl.GetConstPtr() , attr.m_color_tbl.GetConstPtr() );
			return (iPaint_ipr)paint;
		}
	}
	return iPaint_ipr();
}
//=================================================================================================
iCap CreateCap()
{
	if( m_stack->m_stroke_cap == Attr::round_cap )
		return (iCap)instance<CapRound>();
	else if( m_stack->m_stroke_cap == Attr::square_cap )
		return (iCap)instance<CapFlat>();
	else
		return (iCap)instance<CapFlat>();
}
//=================================================================================================
iJoint CreateJoint()
{
	if( m_stack->m_stroke_join == Attr::miter_join )
		return (iJoint)instance<JointMiter>();
	else if( m_stack->m_stroke_join == Attr::round_join )
		return (iJoint)instance<JointRound>();
	else
		return (iJoint)instance<JointBevel>();
}
//=================================================================================================
iPen_ipr CreatePen()
{
	if( m_stack->m_stroke_dash_array.GetDatanum() == 0 )
	{
		instance<Pen_ipr>	pen;
		pen->SetJoint( CreateJoint() );
		pen->SetCap( CreateCap() , CreateCap() );
		pen->SetWidth( m_stack->m_stroke_width );
		return (iPen_ipr)pen;
	}
	else
	{
		instance<PenDash_ipr>	pen;
		pen->SetJoint( CreateJoint() );
		pen->SetCap( CreateCap() , CreateCap() , CreateCap() );
		pen->SetWidth( m_stack->m_stroke_width );
		pen->SetDash( m_stack->m_stroke_dash_array.GetConstPtr() , m_stack->m_stroke_dash_array.GetDatanum() , m_stack->m_stroke_dash_offset );
		return (iPen_ipr)pen;
	}
}
//=================================================================================================
iTexture CreateTexture
		(
		const wstring&	path , 
		Wraptype		wrap
		)
{
	iSurfaceSource	img;
	{
		Array<wstring>	paths;
		m_search_folders.ToAbs( path , paths );
		int		off , num = paths.GetDatanum();
		for( off = 0 ; off < num ; off++ )
		{
			img =m_imagelist.GetImage( paths[off] );
			if( img == true )
				break;
		}
	}
	if( img == false )
		return iTexture();
	
	if( m_stack->m_image_rendering == Attr::Nearest_imagequarity )
	{	
		instance<TextureImageNearest>	texture;
		texture->SetTexture( img );
		texture->SetWraptype( wrap );
		return (iTexture)texture;
	}
	else if( m_stack->m_image_rendering == Attr::Bicubic_imagequarity )
	{	
		instance<TextureImageWeight16>	texture;
		texture->SetTexture( img );
		texture->SetWraptype( wrap );
		return (iTexture)texture;
	}
	else
	{	
		instance<TextureImageWeight4>	texture;
		texture->SetTexture( img );
		texture->SetWraptype( wrap );
		return (iTexture)texture;
	}
}
//=================================================================================================
iBlender CreateBlender()
{
	return (iBlender)instance<BlenderOverlap>();
}
//=================================================================================================
wstring GetText
		(
		iElement_svg&	elem
		)
{
	if( elem == false )
		return wstring();
	wstring		text;
	int		c_off , c_num = elem->GetChildnum();
	for( c_off = 0 ; c_off < c_num ; c_off++ )
	{
		iElement_svg	child = elem->GetChild( c_off );
		if( child->GetTagName() == L"#PCDATA" )
		{
			iPCDATA_svge	tag = (iPCDATA_svge)child;
			if( tag == true )
				text += tag->m_text;
		}
	}
	return text;
}
//=================================================================================================
iElement_svg SearchId
		(
		iElement_svg&	root , 
		const wstring&	id
		)
{
	if( true == m_idlist.Search( id ) )
		return iElement_svg();
	if( false == root )
		return iElement_svg();
		
	m_id_stack.Push( root );
	
	while( m_id_stack.GetDatanum() != 0 )
	{
		iElement_svg	current = *m_id_stack;
		m_id_stack.Pop();
	
		istdAttrs_svga		tag = (istdAttrs_svga)current;
		if( tag == true && tag->m_id == true && tag->m_id->m_value == id )
			return current;
		
		int	c_off , c_num = current->GetChildnum();
		for( c_off = c_num - 1 ; c_off >= 0  ; c_off-- )
		{	
			iElement_svg	child = current->GetChild( c_off );
			if( child == true )
				m_id_stack.Push( child );
		}
	}
	return iElement_svg();
}
// attr functions
private:
//=================================================================================================
void View
		(
		IGraphicsCmds*					cmds , 
		att_element<Coordinate_svgv>&	x , 
		att_element<Coordinate_svgv>&	y , 
		att_element<Coordinate_svgv>&	w , 
		att_element<Coordinate_svgv>&	h
		)
{
	instance<View_cmd>	cmd;
	if( x == true )
	{
		cmd->m_x_f = true;
		Length( *x , &cmd->m_x );
	}
	if( y == true )
	{
		cmd->m_y_f = true;
		Length( *y , &cmd->m_y );
	}
	if( w == true )
	{
		cmd->m_w_f = true;
		Length( *w , &cmd->m_w );
	}
	if( h == true )
	{
		cmd->m_h_f = true;
		Length( *h , &cmd->m_h );
	}
	cmds->AddCmd( (iGraphicsCmd)cmd );
}
//=================================================================================================
void Length
		(
		Length_svgv&	v , 
		value_ipr*		s
		)
{
	if( v.m_type == Length_svgv::px )
		*s	= value_ipr( value_ipr::px , (float)v.m_value );
	else if( v.m_type == Length_svgv::pt )
		*s	= value_ipr( value_ipr::inch , (float)v.m_value / 72.0f );
	else if( v.m_type == Length_svgv::pc )
		*s	= value_ipr( value_ipr::inch , (float)v.m_value / 6.0f );
	else if( v.m_type == Length_svgv::mm )
		*s	= value_ipr( value_ipr::inch , (float)v.m_value / 25.4f );
	else if( v.m_type == Length_svgv::cm )
		*s	= value_ipr( value_ipr::inch , (float)v.m_value / 2.54f );
	else if( v.m_type == Length_svgv::in )
		*s	= value_ipr( value_ipr::inch , (float)v.m_value );
	else if( v.m_type == Length_svgv::percentage )
		*s	= value_ipr( value_ipr::ratio , (float)v.m_value / 100.0f );
	else
		*s	= value_ipr( value_ipr::px , (float)v.m_value );
}
//=================================================================================================
void Length
		(
		Length_svgv&	v , 
		value_ip*		s
		)
{
	if( v.m_type == Length_svgv::px )
		*s	= value_ip( value_ip::px , (float)v.m_value );
	else if( v.m_type == Length_svgv::pt )
		*s	= value_ip( value_ip::inch , (float)v.m_value / 72.0f );
	else if( v.m_type == Length_svgv::pc )
		*s	= value_ip( value_ip::inch , (float)v.m_value / 6.0f );
	else if( v.m_type == Length_svgv::mm )
		*s	= value_ip( value_ip::inch , (float)v.m_value / 25.4f );
	else if( v.m_type == Length_svgv::cm )
		*s	= value_ip( value_ip::inch , (float)v.m_value / 2.54f );
	else if( v.m_type == Length_svgv::in )
		*s	= value_ip( value_ip::inch , (float)v.m_value );
	else if( v.m_type == Length_svgv::percentage )
		s->m_value *= (float)v.m_value / 100.0f;
	else
		*s	= value_ip( value_ip::px , (float)v.m_value );
}
//=================================================================================================
void Units_svgv
		(
		Units_svgv&		v , 
		PaintUnit*		s
		)
{
	if( v.m_type == Units_svgv::userSpaceOnUse )
		*s	= ViewSpace_PaintUnit;
	else if( v.m_type == Units_svgv::objectBoundingBox )
		*s	= BoundBox_PaintUnit;
}
//=================================================================================================
void Transform_svgv
		(
		Transform_svgv&	v , 
		faffine*		s
		)
{

	*s	= v.m_value;
}
//=================================================================================================
void TransformList
		(
		TransformList_svgv&	v , 
		faffine*			s
		)
{
	faffine		r;
	int		off , num = v.m_list.GetDatanum();
	for( off = 0 ; off < num ; off++ )
	{
		faffine	a;
		Transform_svgv( v.m_list[off] , &a );
		r	= r * a;
	}
	*s	= r;
}
//=================================================================================================
void TransformList
		(
		IGraphicsCmds*		cmd , 
		TransformList_svgv&	v
		)
{
	faffine		transform;
	TransformList( v , &transform );

	instance<Transform_cmd>	obj;
	obj->m_transform	= transform;
	cmd->AddCmd( (iGraphicsCmd)obj );
}
//=================================================================================================
void Opacity_svgv
		(
		Opacity_svgv&	v , 
		float*			s
		)
{
	if( v.m_type == Opacity_svgv::value )
		(*s) *= (float)v.m_value;
}
//=================================================================================================
void ClipFillRule_svgv
		(
		ClipFillRule_svgv&	v , 
		PathFillRule*		s
		)
{
	if( v.m_type == ClipFillRule_svgv::nonzero )
		*s	= Winding_PathFillRule;
	else
		*s	= EvenOdd_PathFillRule;
}
//=================================================================================================
void StrokeDashArray_svgv
		(
		StrokeDashArray_svgv&	v , 
		Array<value_ipr>*		s
		)
{
	if( v.m_type == StrokeDashArray_svgv::none )
		s->Resize( 0 );
	else if( v.m_type == StrokeDashArray_svgv::dasharray )
	{
		int		off , num = v.m_dasharray.m_list.GetDatanum();
		s->Resize( num );
		for( off = 0 ; off < num ; off++ )
			Length( v.m_dasharray.m_list[off] , &(*s)[off] );
	}
}
//=================================================================================================
void StrokeDashOffset_svgv
		(
		StrokeDashOffset_svgv&	v , 
		value_ipr*				s
		)
{
	if( v.m_type == StrokeDashOffset_svgv::length )
		Length( v.m_length , s );
}
//=================================================================================================
void StrokeLinecap_svgv
		(
		StrokeLinecap_svgv&		v , 
		Attr::StrokeLineCap*	s
		)
{
	if( v.m_type == StrokeLinecap_svgv::butt )
		*s	= Attr::butt_cap;
	else if( v.m_type == StrokeLinecap_svgv::round )
		*s	= Attr::round_cap;
	else if( v.m_type == StrokeLinecap_svgv::square )
		*s	= Attr::square_cap;
}
//=================================================================================================
void StrokeLinejoin_svgv
		(
		StrokeLinejoin_svgv&	v , 
		Attr::StrokeLineJoin*	s
		)
{
	if( v.m_type == StrokeLinejoin_svgv::miter )
		*s	= Attr::miter_join;
	else if( v.m_type == StrokeLinejoin_svgv::round )
		*s	= Attr::round_join;
	else if( v.m_type == StrokeLinejoin_svgv::bevel )
		*s	= Attr::bevel_join;
}
//=================================================================================================
void StrokeMiterlimit_svgv
		(
		StrokeMiterlimit_svgv&	v , 
		float*					s
		)
{
	if( v.m_type == StrokeMiterlimit_svgv::miterlimit )
		*s	= (float)v.m_miterlimit.m_value;
}
//=================================================================================================
void StrokeWidth_svgv
		(
		StrokeWidth_svgv&	v , 
		value_ipr*			s
		)
{
	if( v.m_type == StrokeWidth_svgv::length )
		Length( v.m_length , s );		
}
//=================================================================================================
void ColorType_svgv
		(
		ColorType_svgv&	v , 
		rgba*			s
		)
{
	*s	= v.GetColor();
}
//=================================================================================================
void Color_svgv
		(
		Color_svgv&	v , 
		rgba*		s
		)
{
	if( v.m_type == Color_svgv::color )
		*s	= rgba( v.r , v.g , v.b , 255 );
	else if( v.m_type == Color_svgv::colortype )
		ColorType_svgv( v.m_colortype , s );
}
//=================================================================================================
void Paint_svgv
		(
		iElement_svg&		root , 
		Paint_svgv&			v , 
		Attr::PaintAttr*	s
		)
{
	if( v.m_type == Paint_svgv::none )
		s->m_type	= Attr::PaintAttr::None;
	else if( v.m_type == Paint_svgv::currentColor )
	{
		s->m_type	= Attr::PaintAttr::SolidColor;
		s->m_color	= m_stack->m_color;
	}
	else if( v.m_type == Paint_svgv::color )
	{
		s->m_type	= Attr::PaintAttr::SolidColor;
		Color_svgv( v.m_color , &s->m_color );
	}
	else if( v.m_type == Paint_svgv::uri )
	{
		if( v.m_uri.m_type == Uri_svgv::id )
			FillRefTag( root , SearchId( root , v.m_uri.m_id.m_value ) , s );
	}
}
//=================================================================================================
void linearGradient_svg
		(
		ilinearGradient_svg&	v , 
		Attr::PaintAttr*		s
		)
{
	s->m_type = Attr::PaintAttr::GradLinear;
	if( v->m_gradientUnits == true )
		Units_svgv( *(v->m_gradientUnits) , &s->m_unit );
	if( v->m_gradientTransform == true )
		TransformList( *(v->m_gradientTransform) , &s->m_transform );
	if( v->m_x1 == true )
		Length( *(v->m_x1) , &s->m_start_vec.x );
	if( v->m_y1 == true )
		Length( *(v->m_y1) , &s->m_start_vec.y );
	if( v->m_x2 == true )
		Length( *(v->m_x2) , &s->m_target_vec.x );
	if( v->m_y2 == true )
		Length( *(v->m_y2) , &s->m_target_vec.y );
}
//=================================================================================================
void radialGradient_svg
		(
		iradialGradient_svg&	v , 
		Attr::PaintAttr*		s
		)
{
	s->m_type = Attr::PaintAttr::GradRadial;
	if( v->m_gradientUnits == true )
		Units_svgv( *(v->m_gradientUnits) , &s->m_unit );
	if( v->m_gradientTransform == true )
		TransformList( *(v->m_gradientTransform) , &s->m_transform );
	if( v->m_cx == true )
		Length( *(v->m_cx) , &s->m_center_vec.x );
	if( v->m_cy == true )
		Length( *(v->m_cy) , &s->m_center_vec.y );
	if( v->m_r == true )
		Length( *(v->m_r) , &s->m_radius );
}
//=================================================================================================
void FontFamily_svgv
		(
		FontFamily_svgv&		v , 
		Array<wstring>*			s
		)
{
	if( v.m_type == FontFamily_svgv::familynamelist )
	{
		int		off , num = v.m_familynamelist.m_list.GetDatanum();
		s->Resize( num );
		for( off = 0 ; off < num ; off++ )
			(*s)[off]	= v.m_familynamelist.m_list[off].m_value;
	}
}
//=================================================================================================
void AbsoluteSize_svgv
		(
		AbsoluteSize_svgv&	v , 
		value_ip*			s
		)
{
	if( v.m_type == AbsoluteSize_svgv::xx_small )
		*s	= value_ip( value_ip::inch , 4.0f / 72.0f );
	else if( v.m_type == AbsoluteSize_svgv::x_small )
		*s	= value_ip( value_ip::inch , 6.0f / 72.0f );
	else if( v.m_type == AbsoluteSize_svgv::_small )
		*s	= value_ip( value_ip::inch , 8.0f / 72.0f );
	else if( v.m_type == AbsoluteSize_svgv::medium )
		*s	= value_ip( value_ip::inch , 10.0f / 72.0f );
	else if( v.m_type == AbsoluteSize_svgv::large )
		*s	= value_ip( value_ip::inch , 12.0f / 72.0f );
	else if( v.m_type == AbsoluteSize_svgv::x_large )
		*s	= value_ip( value_ip::inch , 14.0f / 72.0f );
	else if( v.m_type == AbsoluteSize_svgv::xx_large )
		*s	= value_ip( value_ip::inch , 16.0f / 72.0f );
}
//=================================================================================================
void RelativeSize_svgv
		(
		RelativeSize_svgv&	v , 
		value_ip*			s
		)
{
	if( v.m_type == RelativeSize_svgv::smaller )
		s->m_value -= ((s->m_value - 1.0f) <= 0.0f) ? 0.0f : 1.0f;
	else if( v.m_type == RelativeSize_svgv::larger )
		s->m_value += 1.0f;
}
//=================================================================================================
void FontSize_svgv
		(
		FontSize_svgv&		v , 
		value_ip*			s
		)
{
	if( v.m_type == FontSize_svgv::absolute_size )
		AbsoluteSize_svgv( v.m_absolute_size , s );
	else if( v.m_type == FontSize_svgv::relative_size )
		RelativeSize_svgv( v.m_relative_size , s );
	else if( v.m_type == FontSize_svgv::length )
		Length( v.m_length , s );
}
//=================================================================================================
void FontStyle_svgv
		(
		FontStyle_svgv&		v , 
		Attr::FontStyle*	s
		)
{
	if( v.m_type == FontStyle_svgv::normal )
		*s	= Attr::normal_fontstyle;
	else if( v.m_type == FontStyle_svgv::italic )
		*s	= Attr::italic_fontstyle;
	else if( v.m_type == FontStyle_svgv::oblique )
		*s	= Attr::oblique_fontstyle;
}
//=================================================================================================
void FontWeight_svgv
		(
		FontWeight_svgv&	v , 
		int*				s
		)
{
	if( v.m_type == FontWeight_svgv::normal )
		*s	= 400;
	else if( v.m_type == FontWeight_svgv::bold )
		*s	= 600;
	else if( v.m_type == FontWeight_svgv::bolder )
		*s	+= 100;
	else if( v.m_type == FontWeight_svgv::lighter )
		*s	= ( *s - 100 ) < 100 ? *s : (*s+100);
	else if( v.m_type == FontWeight_svgv::_100 )
		*s	= 100;
	else if( v.m_type == FontWeight_svgv::_200 )
		*s	= 200;
	else if( v.m_type == FontWeight_svgv::_300 )
		*s	= 300;
	else if( v.m_type == FontWeight_svgv::_400 )
		*s	= 400;
	else if( v.m_type == FontWeight_svgv::_500 )
		*s	= 500;
	else if( v.m_type == FontWeight_svgv::_600 )
		*s	= 600;
	else if( v.m_type == FontWeight_svgv::_700 )
		*s	= 700;
	else if( v.m_type == FontWeight_svgv::_800 )
		*s	= 800;
	else if( v.m_type == FontWeight_svgv::_900 )
		*s	= 900;
}
//=================================================================================================
iPathLogic PathData_svgv
		(
		PathData_svgv&		v
		)
{
	instance<PathLogic>	path;
	int		off , num = v.m_list.GetDatanum();
	fvector2				start;
	fvector2				prev;
	fvector2				last;
	fvector2				w[2];
	for( off = 0 ; off < num ; off++ )
	{
		PathData_svgv::Seg*	seg = &v.m_list[off];
		switch( v.m_list[off].m_type )
		{
		case PathData_svgv::moveto_abs:
			{
				bool	close	= false;
				int		soff;
				for( soff = off + 1 ; soff < num ; soff++ )
				{
					if( v.m_list[soff].m_type == PathData_svgv::moveto_abs
					||  v.m_list[soff].m_type == PathData_svgv::moveto_rel )
						break;
					if( v.m_list[soff].m_type == PathData_svgv::close_abs
					||  v.m_list[soff].m_type == PathData_svgv::close_rel )
						close	= true;
				}
				prev	= last;
				last	= fvector2( seg->m_value.m_moveto_abs.x , seg->m_value.m_moveto_abs.y );
				start	= last;
				path->Move( start , faffine() , close );
			}
			break;
		case PathData_svgv::moveto_rel:
			{
				bool	close	= false;
				int		soff;
				for( soff = off + 1 ; soff < num ; soff++ )
				{
					if( v.m_list[soff].m_type == PathData_svgv::moveto_abs
					||  v.m_list[soff].m_type == PathData_svgv::moveto_rel )
						break;
					if( v.m_list[soff].m_type == PathData_svgv::close_abs
					||  v.m_list[soff].m_type == PathData_svgv::close_rel )
						close	= true;
				}
				prev	= last;
				last	= fvector2( seg->m_value.m_moveto_rel.x , seg->m_value.m_moveto_rel.y ) + last;
				start	= last;
				path->Move( start , faffine() , close );
			}
			break;
		case PathData_svgv::close_abs:
		case PathData_svgv::close_rel:
			{
				bool	close	= false;
				int		soff;
				for( soff = off + 1 ; soff < num ; soff++ )
				{
					if( v.m_list[soff].m_type == PathData_svgv::moveto_abs
					||  v.m_list[soff].m_type == PathData_svgv::moveto_rel )
						break;
					if( v.m_list[soff].m_type == PathData_svgv::close_abs
					||  v.m_list[soff].m_type == PathData_svgv::close_rel )
						close	= true;
				}
				prev	= last;
				last	= start;
				path->Move( start , faffine() , close );
			}
			break;
		case PathData_svgv::lineto_abs:
			prev	= last;
			last	= fvector2( seg->m_value.m_lineto_abs.x , seg->m_value.m_lineto_abs.y );
			path->Line( last );
			break;
		case PathData_svgv::lineto_rel:
			prev	= last;
			last	= fvector2( seg->m_value.m_lineto_rel.x , seg->m_value.m_lineto_rel.y ) + last;
			path->Line( last );
			break;
		case PathData_svgv::lineto_horizontal_abs:
			prev	= last;
			last	= fvector2( (float)seg->m_value.m_lineto_horizontal_abs.x , last.y );
			path->Line( last );
			break;
		case PathData_svgv::lineto_horizontal_rel:
			prev	= last;
			last	= fvector2( (float)seg->m_value.m_lineto_horizontal_rel.x + last.x , last.y );
			path->Line( last );
			break;
		case PathData_svgv::lineto_vertical_abs:
			prev	= last;
			last	= fvector2( last.x , (float)seg->m_value.m_lineto_vertical_abs.y );
			path->Line( last );
			break;
		case PathData_svgv::lineto_vertical_rel:
			prev	= last;
			last	= fvector2( last.x , (float)seg->m_value.m_lineto_vertical_rel.y + last.y );
			path->Line( last );
			break;
		case PathData_svgv::curveto_cubic_abs:
			w[0]	= fvector2( (float)seg->m_value.m_curveto_cubic_abs.x1 , (float)seg->m_value.m_curveto_cubic_abs.y1 );
			prev	= fvector2( (float)seg->m_value.m_curveto_cubic_abs.x2 , (float)seg->m_value.m_curveto_cubic_abs.y2 );
			last	= fvector2( (float)seg->m_value.m_curveto_cubic_abs.x , (float)seg->m_value.m_curveto_cubic_abs.y );
			path->BezierC
					(
					w[0] , 
					prev , 
					last 
					);
			break;
		case PathData_svgv::curveto_cubic_rel:
			w[0]	= fvector2( (float)seg->m_value.m_curveto_cubic_rel.x1 , (float)seg->m_value.m_curveto_cubic_rel.y1 ) + last;
			prev	= fvector2( (float)seg->m_value.m_curveto_cubic_rel.x2 , (float)seg->m_value.m_curveto_cubic_rel.y2 ) + last;
			last	= fvector2( (float)seg->m_value.m_curveto_cubic_rel.x , (float)seg->m_value.m_curveto_cubic_rel.y ) + last;
			path->BezierC
					( 
					w[0] , 
					prev , 
					last 
					);
			break;
		case PathData_svgv::curveto_quadratic_abs:
			prev	= fvector2( (float)seg->m_value.m_curveto_quadratic_abs.x1 , (float)seg->m_value.m_curveto_quadratic_abs.y1 );
			last	= fvector2( (float)seg->m_value.m_curveto_quadratic_abs.x , (float)seg->m_value.m_curveto_quadratic_abs.y );
			path->BezierQ
					(
					prev , 
					last
					);
			break;
		case PathData_svgv::curveto_quadratic_rel:
			prev	= fvector2( (float)seg->m_value.m_curveto_quadratic_rel.x1 , (float)seg->m_value.m_curveto_quadratic_rel.y1 ) + last;
			last	= fvector2( (float)seg->m_value.m_curveto_quadratic_rel.x , (float)seg->m_value.m_curveto_quadratic_rel.y ) + last;
			path->BezierQ
					( 
					prev , 
					last 
					);
			break;
		case PathData_svgv::curveto_cubic_smooth_abs:
			w[0]	= (last - prev) + last;
			prev	= fvector2( (float)seg->m_value.m_curveto_cubic_smooth_abs.x2 , (float)seg->m_value.m_curveto_cubic_smooth_abs.y2 );
			last	= fvector2( (float)seg->m_value.m_curveto_cubic_smooth_abs.x , (float)seg->m_value.m_curveto_cubic_smooth_abs.y );
			path->BezierC
					( 
					w[0] , 
					prev , 
					last 
					);
			break;
		case PathData_svgv::curveto_cubic_smooth_rel:
			w[0]	= (last - prev) + last;
			prev	= fvector2( (float)seg->m_value.m_curveto_cubic_smooth_rel.x2 , (float)seg->m_value.m_curveto_cubic_smooth_rel.y2 ) + last;
			last	= fvector2( (float)seg->m_value.m_curveto_cubic_smooth_rel.x , (float)seg->m_value.m_curveto_cubic_smooth_rel.y ) + last;
			path->BezierC
					( 
					w[0] , 
					prev , 
					last 
					);
			break;
		case PathData_svgv::curveto_quadratic_smooth_abs:
			prev	= (last - prev) + last;
			last	= fvector2( (float)seg->m_value.m_curveto_quadratic_smooth_abs.x , (float)seg->m_value.m_curveto_quadratic_smooth_abs.y );
			path->BezierQ
					( 
					prev , 
					last 
					);
			break;
		case PathData_svgv::curveto_quadratic_smooth_rel:
			prev	= (last - prev) + last;
			last	= fvector2( (float)seg->m_value.m_curveto_quadratic_smooth_rel.x , (float)seg->m_value.m_curveto_quadratic_smooth_rel.y ) + last;
			path->BezierQ
					( 
					prev , 
					last 
					);
			break;
		case PathData_svgv::arc_abs:
			{
				float		rx	= fabs( (float)seg->m_value.m_arc_abs.rx );
				float		ry	= fabs( (float)seg->m_value.m_arc_abs.ry );
				prev	= last;
				last	= fvector2( (float)seg->m_value.m_arc_abs.x , (float)seg->m_value.m_arc_abs.y );
				path->Arc
						(
						rx , 
						ry , 
						PI_f * (float)seg->m_value.m_arc_abs.x_axis_rotation / 180.0f , 
						seg->m_value.m_arc_abs.large_arc_flag , 
						seg->m_value.m_arc_abs.sweep_flag , 
						last
						);
			}
			break;
		case PathData_svgv::arc_rel:
			{
				float		rx	= fabs( (float)seg->m_value.m_arc_rel.rx );
				float		ry	= fabs( (float)seg->m_value.m_arc_rel.ry );
				prev	= last;
				last	= fvector2( (float)seg->m_value.m_arc_rel.x , (float)seg->m_value.m_arc_rel.y ) + last;
				path->Arc
						(
						rx , 
						ry , 
						PI_f * (float)seg->m_value.m_arc_rel.x_axis_rotation / 180.0f , 
						seg->m_value.m_arc_rel.large_arc_flag , 
						seg->m_value.m_arc_rel.sweep_flag , 
						last
						);
			}
			break;
		}
	}
	return (iPathLogic)path;
}
//=================================================================================================
void PreserveAspectRatio_svgv
		(
		PreserveAspectRatio_svgv&		v , 
		Coord_view::AspectRatio*		aspect , 
		Coord_view::Align*				align_h , 
		Coord_view::Align*				align_v
		)
{
	if( v.m_align.m_type == Align_svgv::none )
		*aspect	= Coord_view::Adjust;
	else if( v.m_align.m_type == Align_svgv::xMinYMin )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MinAlign;
		*align_v	= Coord_view::MinAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMidYMin )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MidAlign;
		*align_v	= Coord_view::MinAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMaxYMin )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MaxAlign;
		*align_v	= Coord_view::MinAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMinYMid )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MinAlign;
		*align_v	= Coord_view::MidAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMidYMid )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MidAlign;
		*align_v	= Coord_view::MidAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMaxYMid )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MaxAlign;
		*align_v	= Coord_view::MidAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMinYMax )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MinAlign;
		*align_v	= Coord_view::MaxAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMidYMax )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MidAlign;
		*align_v	= Coord_view::MaxAlign;
	}
	else if( v.m_align.m_type == Align_svgv::xMaxYMax )
	{
		*aspect		= Coord_view::AspectMin;
		*align_h	= Coord_view::MaxAlign;
		*align_v	= Coord_view::MaxAlign;
	}
	if( v.m_align.m_type != Align_svgv::none && v.m_meet_or_slice_f == true )
	{
		if( v.m_meet_or_slice.m_type == MeetOrSlice_svgv::meet )
			*aspect	= Coord_view::AspectMin;
		else if( v.m_meet_or_slice.m_type == MeetOrSlice_svgv::slice ) 
			*aspect	= Coord_view::AspectMax;
	}
}
//=================================================================================================
void ViewBox_svgv
		(
		IGraphicsCmds*		cmds , 
		ViewBox_svgv&		v
		)
{
	instance<ViewBox_cmd>	cmd;
	cmd->m_ratio	= m_stack->m_aspect;
	cmd->m_align_h	= m_stack->m_align_h;
	cmd->m_align_v	= m_stack->m_align_v;
	Length( v.m_x , &cmd->m_x );
	Length( v.m_y , &cmd->m_y );
	Length( v.m_width , &cmd->m_w );
	Length( v.m_height , &cmd->m_h );
	cmds->AddCmd( (iGraphicsCmd)cmd );
}
//=================================================================================================
void ImageRendering_svgv
		(
		ImageRendering_svgv&	v , 
		Attr::ImageQuarity*		s
		)
{
	if( v.m_type == ImageRendering_svgv::_auto )
		*s	= Attr::Linear_imagequarity;
	else if( v.m_type == ImageRendering_svgv::optimizeSpeed )
		*s	= Attr::Nearest_imagequarity;
	else if( v.m_type == ImageRendering_svgv::optimizeQuality )
		*s	= Attr::Bicubic_imagequarity;
}
// attr_svga
public:
//=================================================================================================
void stdAttrs_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void testAttrs_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void langSpaceAttrs_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void graphicsElementEvents_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_Markers_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_TextContentElements_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_TextElements_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_Containers_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_feFlood_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_LightingEffects_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_Viewports_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void documentEvents_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void xlinkRefAttrs_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_Images_svga
		(
		iElement_svg&		tag
		)
{
}
//=================================================================================================
void PresentationAttributes_Gradients_svga
		(
		iElement_svg&		tag
		)
{
	iPresentationAttributes_Gradients_svga		v = (iPresentationAttributes_Gradients_svga)tag;
	if( v == false )
		return;
	if( v->m_stop_color == true )
		Color_svgv( *(v->m_stop_color) , &m_stack->m_stop_color );
	if( v->m_stop_opacity == true )
		Opacity_svgv( *(v->m_stop_opacity) , &m_stack->m_stop_opacity );
}
//=================================================================================================
void PresentationAttributes_FillStroke_svga
		(
		iElement_svg&		root , 
		iElement_svg&		tag
		)
{
	iPresentationAttributes_FillStroke_svga		v = (iPresentationAttributes_FillStroke_svga)tag;
	if( v == false )
		return;
	if( v->m_fill == true )
		Paint_svgv( root , *v->m_fill , &m_stack->m_fill );
	if( v->m_fill_opacity == true )
		Opacity_svgv( *v->m_fill_opacity , &m_stack->m_fill_opacity );
	if( v->m_fill_rule == true )
		ClipFillRule_svgv( *v->m_fill_rule , &m_stack->m_fill_rule );
	if( v->m_stroke == true )
		Paint_svgv( root , *v->m_stroke , &m_stack->m_stroke );
	if( v->m_stroke_dasharray == true )
		StrokeDashArray_svgv( *v->m_stroke_dasharray , &m_stack->m_stroke_dash_array );
	if( v->m_stroke_dashoffset == true )
		StrokeDashOffset_svgv( *v->m_stroke_dashoffset , &m_stack->m_stroke_dash_offset );
	if( v->m_stroke_linecap == true )
		StrokeLinecap_svgv( *v->m_stroke_linecap , &m_stack->m_stroke_cap );
	if( v->m_stroke_linejoin == true )
		StrokeLinejoin_svgv( *v->m_stroke_linejoin , &m_stack->m_stroke_join );
	if( v->m_stroke_opacity == true )
		Opacity_svgv( *v->m_stroke_opacity , &m_stack->m_stroke_opacity );
	if( v->m_stroke_width == true )
		StrokeWidth_svgv( *v->m_stroke_width , &m_stack->m_stroke_width );
}
//=================================================================================================
void PresentationAttributes_FontSpecification_svga
		(
		iElement_svg&		tag
		)
{
	iPresentationAttributes_FontSpecification_svga	v	= (iPresentationAttributes_FontSpecification_svga)tag;
	if( v == false )
		return;
	if( v->m_fontfamily == true )
		FontFamily_svgv( *v->m_fontfamily , &m_stack->m_font_family );
	if( v->m_font_size == true )
		FontSize_svgv( *v->m_font_size , &m_stack->m_font_size );
	if( v->m_font_style == true )
		FontStyle_svgv( *v->m_font_style , &m_stack->m_font_style );
	if( v->m_font_weight == true )
		FontWeight_svgv( *v->m_font_weight , &m_stack->m_font_weight );
}
//=================================================================================================
void PresentationAttributes_Graphics_svga
		(
		IClip_clipcmds*		clip , 
		iElement_svg&		root , 
		iElement_svg&		tag
		)
{
	iPresentationAttributes_Graphics_svga	v	= (iPresentationAttributes_Graphics_svga)tag;
	if( v == false )
		return;
	if( v->m_clip_path == true && clip != 0 )
	{
		if( v->m_clip_path->m_type == ClipPath_svgv::none )
			clip->AddCmd( (iClip_clipcmd)instance<ClipRelease_clipcmd>() );
		else if( v->m_clip_path->m_type == ClipPath_svgv::uri && v->m_clip_path->m_uri.m_type == Uri_svgv::id )
			ClipRefTag( clip , root , SearchId( root , v->m_clip_path->m_uri.m_id.m_value ) );
	}
	if( v->m_color == true )
		Color_svgv( *v->m_color , &m_stack->m_color );
	if( v->m_opacity == true )
		Opacity_svgv( *v->m_opacity , &m_stack->m_opacity );
	if( v->m_image_rendering == true )
		ImageRendering_svgv( *v->m_image_rendering , &m_stack->m_image_rendering );
}
//=================================================================================================
void Attribute_svga
		(
		IClip_clipcmds*		clip , 
		iElement_svg&		root , 
		iElement_svg&		tag
		)
{
	stdAttrs_svga( tag );
	testAttrs_svga( tag );
	langSpaceAttrs_svga( tag );
	graphicsElementEvents_svga( tag );
	PresentationAttributes_Markers_svga( tag );
	PresentationAttributes_TextContentElements_svga( tag );
	PresentationAttributes_TextElements_svga( tag );
	PresentationAttributes_Containers_svga( tag );
	PresentationAttributes_feFlood_svga( tag );
	PresentationAttributes_LightingEffects_svga( tag );
	PresentationAttributes_Viewports_svga( tag );
	documentEvents_svga( tag );
	xlinkRefAttrs_svga( tag );
	PresentationAttributes_Images_svga( tag );
	PresentationAttributes_Gradients_svga( tag );
	PresentationAttributes_FillStroke_svga( root , tag );
	PresentationAttributes_FontSpecification_svga( tag );
	PresentationAttributes_Graphics_svga( clip , root , tag );
}
// FillRefTag
public:
//=================================================================================================
void FillRef_pushcmd
		(
		iElement_svg&			root , 
		iElement_svg&			tag , 
		Attr::PaintAttr*		attr
		)
{
	m_fillref_stack.Push();
	m_fillref_stack->m_type	= FillRefArgs::Post;
	m_fillref_stack->m_root	= root;
	m_fillref_stack->m_tag	= tag;
	m_fillref_stack->m_attr	= attr;
	m_fillref_stack.Push();
	m_fillref_stack->m_type	= FillRefArgs::Pre;
	m_fillref_stack->m_root	= root;
	m_fillref_stack->m_tag	= tag;
	m_fillref_stack->m_attr	= attr;
}
//=================================================================================================
void FillRefTag_stop
		(
		istop_svg&				tag , 
		Attr::PaintAttr*		attr
		)
{
	if( tag == false )
		return;
	if( tag->m_offset == true )
	{
		// rate
		value_ipr	r;
		Length( *tag->m_offset , &r );
		attr->m_rate_tbl[ attr->m_rate_tbl.Add() ]	= r.m_value;

		// color
		rgba	color	= m_stack->m_stop_color;
		float	opacity	= m_stack->m_stop_opacity;
		if( tag->m_stop_color == true )
			Color_svgv( *(tag->m_stop_color) , &color );
		if( tag->m_stop_opacity == true )
			Opacity_svgv( *(tag->m_stop_opacity) , &opacity );
		attr->m_color_tbl[ attr->m_color_tbl.Add() ]	= color.MulAlpha( (uint8)(opacity * 255.0f) );
	}
}
//=================================================================================================
void FillRefTag_linearGradient
		(
		FillRefArgs::Type		type , 
		iElement_svg&			root , 
		ilinearGradient_svg&	tag , 
		Attr::PaintAttr*		attr
		)
{
	if( tag == false )
		return;

	if( type == FillRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		if( tag->m_xlink_href == true && tag->m_xlink_href->m_type == XlinkUri_svgv::id )
		{
			iElement_svg	tgt = SearchId( root , tag->m_xlink_href->m_id.m_value );
			if( tgt == true && tgt->GetTagName() == L"linearGradient" )
				FillRef_pushcmd( root , tgt , attr );
		}
	}
	else if( type == FillRefArgs::Post )
	{
		linearGradient_svg( tag , attr );

		// stop
		attr->m_rate_tbl.Resize( 0 );
		attr->m_color_tbl.Resize( 0 );
		iElement_svg	e = (iElement_svg)tag;
		int	c_off , c_num = e->GetChildnum();
		for( c_off = 0 ; c_off < c_num ; c_off++ )
			FillRefTag_stop( (istop_svg)e->GetChild( c_off ) , attr );
		PopId();
	}
}
//=================================================================================================
void FillRefTag_radialGradient
		(
		FillRefArgs::Type		type , 
		iElement_svg&			root , 
		iradialGradient_svg&	tag , 
		Attr::PaintAttr*		attr
		)
{
	if( tag == false )
		return;

	if( type == FillRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		if( tag->m_xlink_href == true && tag->m_xlink_href->m_type == XlinkUri_svgv::id )
		{
			iElement_svg	tgt = SearchId( root , tag->m_xlink_href->m_id.m_value );
			if( tgt == true && tgt->GetTagName() == L"radialGradient" )
				FillRef_pushcmd( root , tgt , attr );
		}
	}
	else if( type == FillRefArgs::Post )
	{
		radialGradient_svg( tag , attr );

		// stop
		attr->m_rate_tbl.Resize( 0 );
		attr->m_color_tbl.Resize( 0 );
		iElement_svg	e = (iElement_svg)tag;
		int	c_off , c_num = e->GetChildnum();
		for( c_off = 0 ; c_off < c_num ; c_off++ )
			FillRefTag_stop( (istop_svg)e->GetChild( c_off ) , attr );
		PopId();
	}
}
//=================================================================================================
void FillRefTag
		(
		iElement_svg&			root , 
		iElement_svg&			tag , 
		Attr::PaintAttr*		attr
		)
{
	if( tag == false )
		return;
	FillRef_pushcmd( root , tag , attr );
	if( m_fillref_stack.GetDatanum() != 2 )
		return;
	while( m_fillref_stack.GetDatanum() != 0 )
	{
		FillRefArgs		args = *m_fillref_stack;
		m_fillref_stack.Pop();
			
		if( args.m_tag->GetTagName() == L"linearGradient" )
			FillRefTag_linearGradient( args.m_type , args.m_root , (ilinearGradient_svg)args.m_tag , args.m_attr );
		else if( args.m_tag->GetTagName() == L"radialGradient" )
			FillRefTag_radialGradient( args.m_type , args.m_root , (iradialGradient_svg)args.m_tag , args.m_attr );
	}
}
// ClipRefTag
public:
//=================================================================================================
void ClipRef_pushcmd
		(
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		iElement_svg&			tag
		)
{
	m_clipref_stack.Push();
	m_clipref_stack->m_type	= ClipRefArgs::Post;
	m_clipref_stack->m_clip	= clip;
	m_clipref_stack->m_root	= root;
	m_clipref_stack->m_tag	= tag;
	m_clipref_stack.Push();
	m_clipref_stack->m_type	= ClipRefArgs::Pre;
	m_clipref_stack->m_clip	= clip;
	m_clipref_stack->m_root	= root;
	m_clipref_stack->m_tag	= tag;
}
//=================================================================================================
void ClipRefTag_path
		(
		ClipRefArgs::Type		type , 
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		ipath_svg&				tag
		)
{
	if( tag == false )
		return;
	if( type == ClipRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		PushStack();
		Attribute_svga( clip , root , (iElement_svg)tag );
	}
	else if( type == ClipRefArgs::Post )
	{	
		faffine		transform;
		if( tag->m_transform == true )
			TransformList( *(tag->m_transform) , &transform );
		iPathLogic	path = PathData_svgv( *(tag->m_d) );
		if( path == true )
		{
			instance<ClipPath_clipcmd>	obj;
			obj->m_transform	= transform;
			obj->m_clip			= path;
			clip->AddCmd( (iClip_clipcmd)obj );
		}
		PopStack();
		PopId();
	}
}
//=================================================================================================
void ClipRefTag_rect
		(
		ClipRefArgs::Type		type , 
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		irect_svg&				tag
		)
{
	if( tag == false )
		return;
	if( type == ClipRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		PushStack();

		Attribute_svga( clip , root , (iElement_svg)tag );
	}
	else if( type == ClipRefArgs::Post )
	{	
		faffine		transform;
		if( tag->m_transform == true )
			TransformList( *(tag->m_transform) , &transform );

		if( tag->m_width == true && tag->m_height == true )
		{
			rect_ipr	r;
			if( tag->m_x == true )
				Length( *(tag->m_x) , &r.x );
			if( tag->m_y == true )
				Length( *(tag->m_y) , &r.y );
			Length( *(tag->m_width) , &r.w );
			Length( *(tag->m_height) , &r.h );
			
			value_ipr	rx , ry;
			if( tag->m_rx == true )
				Length( *(tag->m_rx) , &rx );
			if( tag->m_ry == true )
				Length( *(tag->m_ry) , &ry );
			
			instance<ClipRect_clipcmd>	obj;
			obj->m_transform	= transform;
			obj->m_rect			= r;
			obj->m_rx			= rx;
			obj->m_ry			= ry;
			clip->AddCmd( (iClip_clipcmd)obj );
		}
		PopStack();
		PopId();
	}
}
//=================================================================================================
void ClipRefTag_circle
		(
		ClipRefArgs::Type		type , 
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		icircle_svg&			tag
		)
{
	if( tag == false )
		return;
	if( type == ClipRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		PushStack();

		Attribute_svga( clip , root , (iElement_svg)tag );
	}
	else if( type == ClipRefArgs::Post )
	{	
		faffine		transform;
		if( tag->m_transform == true )
			TransformList( *(tag->m_transform) , &transform );

		point_ipr	cp;
		if( tag->m_cx == true )
			Length( *(tag->m_cx) , &cp.x );
		if( tag->m_cy == true )
			Length( *(tag->m_cy) , &cp.y );

		value_ipr	r( value_ipr::px , 100.0f );
		if( tag->m_r == true )
			Length( *(tag->m_r) , &r );
		
		instance<ClipCircle_clipcmd>	obj;
		obj->m_cp	= cp;
		obj->m_r	= r;
		clip->AddCmd( (iClip_clipcmd)obj );

		PopStack();
		PopId();
	}
}
//=================================================================================================
void ClipRefTag_ellipse
		(
		ClipRefArgs::Type		type , 
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		iellipse_svg&			tag
		)
{
	if( tag == false )
		return;
	if( type == ClipRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		PushStack();

		Attribute_svga( clip , root , (iElement_svg)tag );
	}
	else if( type == ClipRefArgs::Post )
	{	
		faffine		transform;
		if( tag->m_transform == true )
			TransformList( *(tag->m_transform) , &transform );

		point_ipr	cp;
		if( tag->m_cx == true )
			Length( *(tag->m_cx) , &cp.x );
		if( tag->m_cy == true )
			Length( *(tag->m_cy) , &cp.y );
		value_ipr	rx( value_ipr::px , 100.0f );
		if( tag->m_rx == true )
			Length( *(tag->m_rx) , &rx );
		value_ipr	ry( value_ipr::px , 100.0f );
		if( tag->m_ry == true )
			Length( *(tag->m_ry) , &ry );

		instance<ClipEllipse_clipcmd>	obj;
		obj->m_cp	= cp;
		obj->m_rx	= rx;
		obj->m_ry	= ry;
		clip->AddCmd( (iClip_clipcmd)obj );

		PopStack();
		PopId();
	}
}
//=================================================================================================
void ClipRefTag_polygon
		(
		ClipRefArgs::Type		type , 
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		ipolygon_svg&			tag
		)
{
	if( tag == false )
		return;
	if( type == ClipRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		PushStack();

		Attribute_svga( clip , root , (iElement_svg)tag );
	}
	else if( type == ClipRefArgs::Post )
	{	
		faffine		transform;
		if( tag->m_transform == true )
			TransformList( *(tag->m_transform) , &transform );

		if( tag->m_points == true && tag->m_points->m_list.GetDatanum() > 2 )
		{
			instance<ClipLine_clipcmd>	obj;
			int		off , num = tag->m_points->m_list.GetDatanum();
			obj->m_points.SetPointnum( num );
			for( off = 0 ; off < num ; off++ )
			{
				point_ipr	p;
				Length( tag->m_points->m_list[off].m_value[0] , &p.x );
				Length( tag->m_points->m_list[off].m_value[1] , &p.y );
				obj->m_points[off]	= p;
			}
			clip->AddCmd( (iClip_clipcmd)obj );
		}

		PopStack();
		PopId();
	}
}
//=================================================================================================
void ClipRefTag_text
		(
		ClipRefArgs::Type		type , 
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		itext_svg&				tag
		)
{
	if( tag == false )
		return;

	if( type == ClipRefArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		PushStack();

		Attribute_svga( clip , root , (iElement_svg)tag );
	}
	else if( type == ClipRefArgs::Post )
	{	
		faffine		transform;
		if( tag->m_transform == true )
			TransformList( *(tag->m_transform) , &transform );

		point_ipr	p;
		if( tag->m_x == true )
			Length( *(tag->m_x) , &p.x );
		if( tag->m_y == true )
			Length( *(tag->m_y) , &p.y );

		wstring		text = GetText( (iElement_svg)tag );
		if( text.empty() == false )
		{
			instance<ClipText_clipcmd>	obj;
			obj->m_fontsize	= m_stack->m_font_size;
			obj->m_pos		= p;
			obj->m_font		= CreateFont();
			obj->m_text		= text;
			clip->AddCmd( (iClip_clipcmd)obj );
		}
		PopStack();
		PopId();
	}
}
//=================================================================================================
void ClipRefTag
		(
		IClip_clipcmds*			clip , 
		iElement_svg&			root , 
		iElement_svg&			tag
		)
{
	if( tag == false )
		return;

	if( tag->GetTagName() != L"clipPath" )
		return;

	int	c_off , c_num = tag->GetChildnum();
	for( c_off = c_num - 1 ; c_off >= 0 ; c_off-- )
		ClipRef_pushcmd( clip , root , (iElement_svg)tag->GetChild( c_off ) );

	if( m_clipref_stack.GetDatanum() != c_num * 2 )
		return;
	
	while( m_clipref_stack.GetDatanum() != 0 )
	{	
		ClipRefArgs	args = *m_clipref_stack;	
		m_clipref_stack.Pop();
		
		if( args.m_tag->GetTagName() == L"path" )
			ClipRefTag_path( args.m_type , args.m_clip , args.m_root , (ipath_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"rect" )
			ClipRefTag_rect( args.m_type , args.m_clip , args.m_root , (irect_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"circle" )
			ClipRefTag_circle( args.m_type , args.m_clip , args.m_root , (icircle_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"ellipse" )
			ClipRefTag_ellipse( args.m_type , args.m_clip , args.m_root , (iellipse_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"polygon" )
			ClipRefTag_polygon( args.m_type , args.m_clip , args.m_root , (ipolygon_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"text" )
			ClipRefTag_text( args.m_type , args.m_clip , args.m_root , (itext_svg)args.m_tag );
	}
}
// Tag
public:
//=================================================================================================
void Tag_pushcmd
		(
		IGraphicsCmds*			cmds , 
		iElement_svg&			root , 
		iElement_svg&			tag
		)
{
	m_tag_stack.Push();
	m_tag_stack->m_type	= TagArgs::Post;
	m_tag_stack->m_cmds	= cmds;
	m_tag_stack->m_root	= root;
	m_tag_stack->m_tag	= tag;
	m_tag_stack.Push();
	m_tag_stack->m_type	= TagArgs::Pre;
	m_tag_stack->m_cmds	= cmds;
	m_tag_stack->m_root	= root;
	m_tag_stack->m_tag	= tag;
}
//=================================================================================================
void TagChild
		(
		IGraphicsCmds*		cmds , 
		iElement_svg&		root , 
		iElement_svg&		tag
		)
{
	if( tag == false )
		return;
	int	c_off , c_num = tag->GetChildnum();
	for( c_off = 0 ; c_off < c_num ; c_off++ )
		Tag( cmds , root , (iElement_svg)tag->GetChild( c_off ) );
}
//=================================================================================================
void Tag_svg
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		isvg_svg&		tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			Attribute_svga( 0 , root , (iElement_svg)tag );
			
			View( cmds , tag->m_x , tag->m_y , tag->m_width , tag->m_height );
			if( tag->m_preserveAspectRatio == true )
				PreserveAspectRatio_svgv( *tag->m_preserveAspectRatio , &m_stack->m_aspect , &m_stack->m_align_h , &m_stack->m_align_v );
			if( tag->m_viewBox == true )
				ViewBox_svgv( cmds , *tag->m_viewBox );

			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_use
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		iuse_svg&		tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			Attribute_svga( 0 , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			View( cmds , tag->m_x , tag->m_y , tag->m_width , tag->m_height );
			if( tag->m_xlink_href == true && tag->m_xlink_href->m_type == XlinkUri_svgv::id )
				Tag( cmds , root , SearchId( root , tag->m_xlink_href->m_id.m_value ) );

			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_g
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		ig_svg&			tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			Attribute_svga( 0 , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );

			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_image
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		iimage_svg&		tag 
		)
{
	if( tag == false )
		return;

	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_xlink_href == true 
			 && tag->m_width == true 
			 && tag->m_height == true 
			 && tag->m_xlink_href->m_type == XlinkUri_svgv::url )
			{
				iTexture		img = CreateTexture( tag->m_xlink_href->m_url.m_value , Clamp_Wraptype );
				if( img == true )
				{
					rect_ipr	dest_rect;
					if( tag->m_x == true )
						Length( *tag->m_x , &dest_rect.x );
					if( tag->m_y == true )
						Length( *tag->m_y , &dest_rect.y );
					Length( *tag->m_width , &dest_rect.w );
					Length( *tag->m_height , &dest_rect.h );

					rect_ipr	src_rect
									(
									value_ipr( value_ipr::ratio , 0.0f ) , 
									value_ipr( value_ipr::ratio , 0.0f ) , 
									value_ipr( value_ipr::ratio , 1.0f ) , 
									value_ipr( value_ipr::ratio , 1.0f )
									);
					instance<StretchBlt_cmd>	cmd;
					cmd->m_dest_rect	= dest_rect;
					cmd->m_src_rect		= src_rect;
					cmd->m_texture		= img;
					cmd->m_blender		= CreateBlender();
					cmd->m_opacity		= m_stack->m_opacity;
					cmd->m_clip			= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}
			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_path
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		ipath_svg&		tag
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_d == true )
			{
				iPaint_ipr	fill_paint	= CreatePaint( m_stack->m_fill , m_stack->m_stop_color , m_stack->m_stop_opacity );
				if( fill_paint == true )
				{
					instance<PaintPath_cmd>	cmd;
					cmd->m_path		= PathData_svgv( *tag->m_d );
					cmd->m_paint	= fill_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_fill_opacity;
					cmd->m_fillrule	= m_stack->m_fill_rule;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokePath_cmd>	cmd;
					cmd->m_path		= PathData_svgv( *tag->m_d );
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_fillrule	= Winding_PathFillRule;
					if( fill_paint == false )
						cmd->m_clip			= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}
			
			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_rect
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		irect_svg&		tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_width == true && tag->m_height == true )
			{
				rect_ipr	rect;
				if( tag->m_x == true )
					Length( *(tag->m_x) , &rect.x );
				if( tag->m_y == true )
					Length( *(tag->m_y) , &rect.y );
				Length( *(tag->m_width) , &rect.w );
				Length( *(tag->m_height) , &rect.h );
				
				value_ipr	rx , ry;
				if( tag->m_rx == true )
					Length( *(tag->m_rx) , &rx );
				if( tag->m_ry == true )
					Length( *(tag->m_ry) , &ry );
				
				iPaint_ipr	fill_paint	= CreatePaint( m_stack->m_fill , m_stack->m_stop_color , m_stack->m_stop_opacity );
				if( fill_paint == true )
				{
					instance<PaintRect_cmd>	cmd;
					cmd->m_rect		= rect;
					cmd->m_rx		= rx;
					cmd->m_ry		= ry;
					cmd->m_paint	= fill_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_fill_opacity;
					cmd->m_fillrule	= m_stack->m_fill_rule;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokeRect_cmd>	cmd;
					cmd->m_rect		= rect;
					cmd->m_rx		= rx;
					cmd->m_ry		= ry;
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_fillrule	= Winding_PathFillRule;
					cmd->m_close	= true;
					if( fill_paint == false )
						cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}

			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_circle
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		icircle_svg&	tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_r == true )
			{
				point_ipr	cp;
				value_ipr	r;
				
				if( tag->m_cx == true )
					Length( *(tag->m_cx) , &cp.x );
				if( tag->m_cy == true )
					Length( *(tag->m_cy) , &cp.y );
				Length( *(tag->m_r) , &r );
				
				iPaint_ipr	fill_paint	= CreatePaint( m_stack->m_fill , m_stack->m_stop_color , m_stack->m_stop_opacity );
				if( fill_paint == true )
				{
					instance<PaintCircle_cmd>	cmd;
					cmd->m_cp		= cp;
					cmd->m_r		= r;
					cmd->m_paint	= fill_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_fill_opacity;
					cmd->m_fillrule	= m_stack->m_fill_rule;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokeCircle_cmd>	cmd;
					cmd->m_cp		= cp;
					cmd->m_r		= r;
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_fillrule	= Winding_PathFillRule;
					cmd->m_close	= true;
					if( fill_paint == false )
						cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}
			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_ellipse
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		iellipse_svg&	tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_rx == true && tag->m_ry == true )
			{
				point_ipr	cp;
				value_ipr	rx;
				value_ipr	ry;
				
				if( tag->m_cx == true )
					Length( *(tag->m_cx) , &cp.x );
				if( tag->m_cy == true )
					Length( *(tag->m_cy) , &cp.y );
				Length( *(tag->m_rx) , &rx );
				Length( *(tag->m_ry) , &ry );
				
				iPaint_ipr	fill_paint	= CreatePaint( m_stack->m_fill , m_stack->m_stop_color , m_stack->m_stop_opacity );
				if( fill_paint == true )
				{
					instance<PaintEllipse_cmd>	cmd;
					cmd->m_cp		= cp;
					cmd->m_rx		= rx;
					cmd->m_ry		= ry;
					cmd->m_paint	= fill_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_fill_opacity;
					cmd->m_fillrule	= m_stack->m_fill_rule;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokeEllipse_cmd>	cmd;
					cmd->m_cp		= cp;
					cmd->m_rx		= rx;
					cmd->m_ry		= ry;
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_fillrule	= Winding_PathFillRule;
					cmd->m_close	= true;
					if( fill_paint == false )
						cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}

			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_line
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		iline_svg&		tag
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_x1 == true 
			 && tag->m_y1 == true 
			 && tag->m_x2 == true 
			 && tag->m_y2 == true )
			{
				point_ipr	p[2];
				Length( *(tag->m_x1) , &p[0].x );
				Length( *(tag->m_y1) , &p[0].y );
				Length( *(tag->m_x2) , &p[1].x );
				Length( *(tag->m_y2) , &p[1].y );
				
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokeLine_cmd>	cmd;
					cmd->m_points.SetPoints( 2 , p );
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_fillrule	= Winding_PathFillRule;
					cmd->m_close	= false;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}

			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_polyline
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		ipolyline_svg&	tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_points == true && tag->m_points->m_list.GetDatanum() >= 2 )
			{
				iPaint_ipr	fill_paint	= CreatePaint( m_stack->m_fill , m_stack->m_stop_color , m_stack->m_stop_opacity );
				if( fill_paint == true )
				{
					instance<PaintLine_cmd>	cmd;
					int		pntoff , pntnum = tag->m_points->m_list.GetDatanum();
					cmd->m_points.SetPointnum( pntnum );
					for( pntoff = 0 ; pntoff < pntnum ; pntoff++ )
					{
						Length( tag->m_points->m_list[pntoff].m_value[0] , &cmd->m_points[pntoff].x );
						Length( tag->m_points->m_list[pntoff].m_value[1] , &cmd->m_points[pntoff].y );
					}
					cmd->m_paint	= fill_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_fill_opacity;
					cmd->m_fillrule	= m_stack->m_fill_rule;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokeLine_cmd>	cmd;
					int		pntoff , pntnum = tag->m_points->m_list.GetDatanum();
					cmd->m_points.SetPointnum( pntnum );
					for( pntoff = 0 ; pntoff < pntnum ; pntoff++ )
					{
						Length( tag->m_points->m_list[pntoff].m_value[0] , &cmd->m_points[pntoff].x );
						Length( tag->m_points->m_list[pntoff].m_value[1] , &cmd->m_points[pntoff].y );
					}
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_fillrule	= Winding_PathFillRule;
					cmd->m_close	= false;
					if( fill_paint == false )
						cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}

			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_polygon
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		ipolygon_svg&	tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );

			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );
			if( tag->m_points == true && tag->m_points->m_list.GetDatanum() >= 2 )
			{
				iPaint_ipr	fill_paint	= CreatePaint( m_stack->m_fill , m_stack->m_stop_color , m_stack->m_stop_opacity );
				if( fill_paint == true )
				{
					instance<PaintLine_cmd>	cmd;
					int		pntoff , pntnum = tag->m_points->m_list.GetDatanum();
					cmd->m_points.SetPointnum( pntnum );
					for( pntoff = 0 ; pntoff < pntnum ; pntoff++ )
					{
						Length( tag->m_points->m_list[pntoff].m_value[0] , &cmd->m_points[pntoff].x );
						Length( tag->m_points->m_list[pntoff].m_value[1] , &cmd->m_points[pntoff].y );
					}
					cmd->m_paint	= fill_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_fill_opacity;
					cmd->m_fillrule	= m_stack->m_fill_rule;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokeLine_cmd>	cmd;
					int		pntoff , pntnum = tag->m_points->m_list.GetDatanum();
					cmd->m_points.SetPointnum( pntnum );
					for( pntoff = 0 ; pntoff < pntnum ; pntoff++ )
					{
						Length( tag->m_points->m_list[pntoff].m_value[0] , &cmd->m_points[pntoff].x );
						Length( tag->m_points->m_list[pntoff].m_value[1] , &cmd->m_points[pntoff].y );
					}
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_fillrule	= Winding_PathFillRule;
					cmd->m_close	= true;
					if( fill_paint == false )
						cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}
			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag_text
		( 
		TagArgs::Type	type , 
		IGraphicsCmds*	cmds , 
		iElement_svg&	root , 
		itext_svg&		tag 
		)
{
	if( tag == false )
		return;
	if( type == TagArgs::Pre )
	{		
		PushId( (iElement_svg)tag );
		Push( cmds );
		{
			instance<ClipList_clipcmds>	clip;
			Attribute_svga( (iClip_clipcmds)clip , root , (iElement_svg)tag );
			if( tag->m_transform == true )
				TransformList( cmds , *(tag->m_transform) );

			point_ipr	p;
			if( tag->m_x == true )
				Length( *(tag->m_x) , &p.x );
			if( tag->m_y == true )
				Length( *(tag->m_y) , &p.y );

			wstring		text = GetText( (iElement_svg)tag );
			if( text.empty() == false )
			{
				iPaint_ipr	fill_paint	= CreatePaint( m_stack->m_fill , m_stack->m_stop_color , m_stack->m_stop_opacity );
				if( fill_paint == true )
				{
					instance<PaintText_cmd>	cmd;
					cmd->m_paint	= fill_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_fill_opacity;
					cmd->m_text		= text;
					cmd->m_font		= CreateFont();
					cmd->m_fontsize	= m_stack->m_font_size;
					cmd->m_pos		= p;
					cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
				iPaint_ipr	stroke_paint	= CreatePaint( m_stack->m_stroke , m_stack->m_stop_color , m_stack->m_stop_opacity );
				iPen_ipr	stroke_pen		= CreatePen();
				if( stroke_paint == true && stroke_pen == true )
				{
					instance<StrokeText_cmd>	cmd;
					cmd->m_pen		= stroke_pen;
					cmd->m_paint	= stroke_paint;
					cmd->m_blender	= CreateBlender();
					cmd->m_opacity	= m_stack->m_opacity * m_stack->m_stroke_opacity;
					cmd->m_text		= text;
					cmd->m_font		= CreateFont();
					cmd->m_fontsize	= m_stack->m_font_size;
					cmd->m_pos		= p;
					if( fill_paint == false )
						cmd->m_clip		= (iClip_clipcmd)clip;
					cmds->AddCmd( (iGraphicsCmd)cmd );
				}
			}
			TagChild( cmds , root , (iElement_svg)tag );
		}
	}
	else if( type == TagArgs::Post )
	{
		Pop( cmds );
		PopId();
	}
}
//=================================================================================================
void Tag
		(
		IGraphicsCmds*			cmds , 
		iElement_svg&			root , 
		iElement_svg&			tag
		)
{
	if( tag == false )
		return;
	Tag_pushcmd( cmds , root , tag );
	if( m_tag_stack.GetDatanum() != 2 )
		return;
	
	while( m_tag_stack.GetDatanum() != 0 )
	{
		TagArgs		args = *m_tag_stack;
		m_tag_stack.Pop();
		
		if( args.m_tag->GetTagName() == L"svg" )
			Tag_svg( args.m_type , args.m_cmds , args.m_root , (isvg_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"use" )
			Tag_use( args.m_type , args.m_cmds , args.m_root , (iuse_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"g" )
			Tag_g( args.m_type , args.m_cmds , args.m_root , (ig_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"image" )
			Tag_image( args.m_type , args.m_cmds , args.m_root , (iimage_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"path" )
			Tag_path( args.m_type , args.m_cmds , args.m_root , (ipath_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"rect" )
			Tag_rect( args.m_type , args.m_cmds , args.m_root , (irect_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"circle" )
			Tag_circle( args.m_type , args.m_cmds , args.m_root , (icircle_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"ellipse" )
			Tag_ellipse( args.m_type , args.m_cmds , args.m_root , (iellipse_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"line" )
			Tag_line( args.m_type , args.m_cmds , args.m_root , (iline_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"polyline" )
			Tag_polyline( args.m_type , args.m_cmds , args.m_root , (ipolyline_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"polygon" )
			Tag_polygon( args.m_type , args.m_cmds , args.m_root , (ipolygon_svg)args.m_tag );
		else if( args.m_tag->GetTagName() == L"text" )
			Tag_text( args.m_type , args.m_cmds , args.m_root , (itext_svg)args.m_tag );
	}	
}
// "ILoaderVectorfile" interface functions
public:
//=================================================================================================
iGraphicsCmds cb_call Load
		(
		IStreamRead*		reader
		)
{
	// parser svg
	ParserSVG		parser;
	iElement_svg	svg = parser.Load( reader );
	if( svg == false )
		return iGraphicsCmds();
	if( svg->GetTagName() != L"svg" )
		return iGraphicsCmds();

	// create commands
	InitializeLoad();
	instance<GraphicsCmds>	cmds;
	Tag( (iGraphicsCmds)cmds , svg , svg );
	FinalizeLoad();		
	return  (iGraphicsCmds)cmds;
}

// public functions
public:
//=================================================================================================
LoaderVectorfile_svg()
{
}
//=================================================================================================
~LoaderVectorfile_svg()
{
}
//=================================================================================================
void AddFileSerchFolder
		(
		const wchar_t*	folder
		)
{
	m_search_folders.AddFolder( folder );
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// global variable define

///////////////////////////////////////////////////////////////////////////////////////////////////
// global functions define

};	//namespace

//using namespace icubic;		

#pragma pack( pop )			//release align
