#pragma once

#ifdef _DEBUG
//#define TME_DEBUG
//#define TME_DEBUG_VSXML
//#define TME_LOG(msg, offset) MeasurerLogger::log3(msg, offset)
//#define TME_SHOW_TABS
//#define TME_EMPTY_DRAWING
//#define TME_DONT_OUTPUT_HEADER_FOOTER
//#define TME_NODE_XML
//#define TME_DRAW_SYMBOL_BORDER
//#define TME_DRAW_LINE_BORDER
//#define TME_DRAW_LETTER_BORDER
//#define TME_TEXT_BLACK
//#define TME_RENDERER_COMMAND_DEBUG
#endif

#include <map>
#include "Structures.h"
#include "Wrap.h"

namespace ImageStudio {
	namespace Serialize {
		namespace Paint {
			namespace Common {
#include "Numeration.h"
#include "RendererCommands.h"
#include "Settings.h"

				class MeasurerLogger {
				public:
					static void log3(CString text, const int& offset) {
						log2(text, offset);
					}
					static void log3(float value, const int& offset) {
						CString text;
						text.Format(_T("%f\n"), value);
						log2(text, offset, false);
					}
					static void log3(int value, const int& offset) {
						CString text;
						text.Format(_T("%d\n"), value);
						log2(text, offset, false);
					}
				private:
					static void log2(CString text, const int& offset, const bool& applyLevel = true) {
						static int level = 0;
						if (text != _T("")) {
							if (applyLevel)
								for (int i = 0; i < level; ++i)
									text = _T("\t") + text;
							log(text);
						}
						level += offset;
					}

					static void log(const CString& text) {
						static const char logFilePath[] = "c:\\temp\\measurerLog.xml";
						FILE* logFile;
						fopen_s(&logFile, logFilePath, "a+");
						fwprintf_s(logFile, L"%s", text);
						fclose(logFile);
					}
				};
				class CDrawGraphicPath;
				class ITextPainter
				{
				public:
					virtual void	CommandText(BSTR bsText, double fX, double fY, double fWidth, double fHeight, double fBaseLineOffset, IAVSRenderer *pRenderer) = 0;
				};

				class IWorker
				{
					// Methods
				public:
					virtual void	IWorker_Resume()	= 0;
					virtual void	IWorker_Pause()	= 0;
					virtual void	IWorker_Stop()		= 0;
					// Events
				public:
					virtual void	IWorker_OnNewPage(double dWidthMm, double dHeightMm)	= 0;
					virtual void	IWorker_OnCompletePage()								= 0;

				public:
					virtual void	IWorker_OnProgress(double dCompleteness)	= 0;
				};

				class CTextMeasurer : public IWorker {
				protected:
					// ### ### ###
					static enum CAlignHorizontal {
						NoneAlign = 0, LeftAlign, CenterAlign, RightAlign, WideAlign
					};
					static enum CAlignVertical {
						NoneAlignVert = 0, FarAlignVert, CenterAlignVert, NearAlignVert
					};
					static enum CRelativeFrom {
						FromCharacter = 0, FromLine, FromColumn, FromParagraph,
						FromPage, FromMargin, FromInsideMargin, FromOutsideMargin,
						FromLeftMargin, FromRightMargin, 
						FromBottomMargin,  FromTopMargin
					};
					static enum CItemType {
						Symbols = 0, Space, LineEnd, TabStop, Bullet, Word, Alternate, Footnote, None
					};
					// ### ### ###
					class CDocumentManager;
					class CGraphicLine
					{
					public:
						REAL	m_fStartX;
						REAL	m_fStartY;

						REAL	m_fFinishX;
						REAL	m_fFinishY;

						CPen	m_oPen;

					public:
						// ---
						CGraphicLine()
							: m_fStartX(0.0f), m_fStartY(0.0f), 
							m_fFinishX(0.0f), m_fFinishY(0.0f)
						{
						}
						// ---
						void	Clear()
						{
							m_fStartX	= 0.0f;
							m_fStartY	= 0.0f;

							m_fFinishX	= 0.0f;
							m_fFinishY	= 0.0f;
						}
						// ---
						void	SetStartPoint(const REAL &fStartX, const REAL &fStartY)
						{
							m_fStartX	= fStartX;
							m_fStartY	= fStartY;
						}
						void	SetFinishPoint(const REAL &fFinishX, const REAL &fFinishY)
						{
							m_fFinishX	= fFinishX;
							m_fFinishY	= fFinishY;
						}
						void	SetPen(const CPen &oPen)
						{
							m_oPen	= oPen;
						}
						void	MoveOn(const REAL &fDeltaX, const REAL &fDeltaY)
						{
							m_fStartX	+= fDeltaX;
							m_fStartY	+= fDeltaY;

							m_fFinishX	+= fDeltaX;
							m_fFinishY	+= fDeltaY;
						}
						// ---
						void	Draw(IAVSRenderer *pRenderer, const REAL &fCompleteness)
						{							
							m_oPen.SetToRenderer(pRenderer);
							pRenderer->BeginCommand(c_nPathType);
							//pRenderer->BeginCommand(c_nTextGraphicType);
							pRenderer->PathCommandStart();
							pRenderer->PathCommandMoveTo(m_fStartX, m_fStartY);
							pRenderer->PathCommandLineTo(m_fFinishX, m_fFinishY);
							pRenderer->PathCommandClose();
							pRenderer->DrawPath(0x01);
							pRenderer->PathCommandEnd();
							//pRenderer->EndCommand(c_nTextGraphicType);
							pRenderer->EndCommand(c_nPathType);


							/*pRenderer->PathCommandStart();

							SAFEARRAYBOUND rgsab;
							rgsab.lLbound	= 0;
							rgsab.cElements	= 4;

							SAFEARRAY* pArray = SafeArrayCreate(VT_R4, 1, &rgsab);
							FLOAT* pBuffer = (FLOAT*)(pArray->pvData);

							memset(pBuffer, 0, rgsab.cElements * sizeof(float));

							const float fPtToMm	= 

							*pBuffer = m_fStartX;	++pBuffer;
							*pBuffer = m_fStartY;	++pBuffer;
							*pBuffer = m_fFinishX;	++pBuffer;
							*pBuffer = m_fFinishY;	++pBuffer;

							pRenderer->PathCommandLinesTo(pArray);

							RELEASEARRAY(pArray);

							pRenderer->PathCommandClose();
							pRenderer->DrawPath(0x01);
							pRenderer->PathCommandEnd();*/
						}
					};

					class CBackgroundRect
					{
					public:
						REAL	m_fX;
						REAL	m_fY;

						REAL	m_fWidth;
						REAL	m_fHeight;

						CBrush	m_oBrush;

					public:
						// ---
						CBackgroundRect()
							: m_fX(0.0f), m_fY(0.0f), 
							m_fWidth(0.0f), m_fHeight(0.0f)
						{
						}
						// ---
						void	Clear()
						{
							m_fX	= 0.0f;
							m_fY	= 0.0f;

							m_fWidth	= 0.0f;
							m_fHeight	= 0.0f;
						}
						// ---
						void	SetStartPoint(const REAL &fStartX, const REAL &fStartY)
						{
							m_fX	= fStartX;
							m_fY	= fStartY;
						}
						void	SetSize(const REAL &fWidth, const REAL &fHeight)
						{
							m_fWidth	= fWidth;
							m_fHeight	= fHeight;
						}
						void	SetBrush(const CBrush &oBrush)
						{
							m_oBrush	= oBrush;
						}						
						void	MoveOn(const REAL &fDeltaX, const REAL &fDeltaY)
						{
							m_fX	+= fDeltaX;
							m_fY	+= fDeltaY;
						}
						// ---
						void	Draw(IAVSRenderer *pRenderer, const REAL &fCompleteness)
						{
							if (m_oBrush.m_oBrush.Alpha1 != 0)
							{
								pRenderer->put_PenColor(m_oBrush.m_oBrush.Color1);
								pRenderer->put_PenSize(0);

								/*pRenderer->PathCommandStart();
								pRenderer->PathCommandMoveTo(m_fX + m_fWidth, m_fY);
								pRenderer->PathCommandLineTo(m_fX + m_fWidth, m_fY + m_fHeight);
								pRenderer->PathCommandLineTo(m_fX, m_fY + m_fHeight);
								pRenderer->DrawPath(c_nStroke);
								pRenderer->PathCommandEnd();*/

								m_oBrush.SetToRenderer(pRenderer);

								pRenderer->BeginCommand(c_nPathType);
								//pRenderer->BeginCommand(c_nTextGraphicType);
								pRenderer->PathCommandStart();
								pRenderer->PathCommandMoveTo(m_fX, m_fY);
								pRenderer->PathCommandLineTo(m_fX + m_fWidth, m_fY);
								pRenderer->PathCommandLineTo(m_fX + m_fWidth, m_fY + m_fHeight);
								pRenderer->PathCommandLineTo(m_fX, m_fY + m_fHeight);
								pRenderer->PathCommandClose();
								pRenderer->DrawPath(c_nWindingFillMode);
								pRenderer->PathCommandEnd();
								//pRenderer->EndCommand(c_nTextGraphicType);
								pRenderer->EndCommand(c_nPathType);
							}
						}
					};


					class CBulletProperties
					{
					public:
						CString	m_strChar;

						REAL	m_fSize;

						LONG	m_iColor;

					public:
						// ---
						CBulletProperties()
							: m_strChar(_T("")), 
							m_fSize(1.0f), 
							m_iColor(0)
						{
						}
						// ---
						~CBulletProperties()
						{
							Clear();
						}
						// ---
						void	Clear()
						{
							m_strChar	= _T("");

							m_fSize		= 1.0f;

							m_iColor	= 0;
						}
						// ---
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
							m_strChar	= oXmlNode.GetAttributeOrValue(_T("bulletchar"), _T(""));

							m_fSize		= oXmlNode.ReadAttributeOrValueFloat(_T("bulletsize"), 100) / 100.0f;
							if (m_fSize <= 0)
							{
								m_fSize	= 1.0f;
							}

							m_iColor	= oXmlNode.ReadAttributeOrValueInt(_T("bulletcolor"), 0);
						}
					};

					class CLinkProperties
					{
					public:
						BYTE	nMode;
						CString	strTarget;

					public:
						// ---
						CLinkProperties()
							: nMode(0), strTarget(_T(""))
						{
						}
						// ---
						void	Clear()
						{
							nMode		= 0;
							strTarget	= _T("");
						}
						// ---
						void	FromXmlNode2(XmlUtils::CXmlNode& oXmlNode)
						{
							strTarget	= oXmlNode.GetAttribute(_T("external-destination"), _T(""));
							if (strTarget != _T(""))
							{
								nMode	= 2;
							}
							else
							{
								strTarget	= oXmlNode.GetAttribute(_T("internal-destination"), _T(""));
								if (strTarget != _T(""))
								{
									nMode	= 1;
								}
							}
						}
					};

					class CBreakProperties : protected CXmlAttributeReader
					{
					public:
						int	m_nBreakBeforeType;

					public:
						CBreakProperties() 
							: m_nBreakBeforeType(0)
						{
						}
						void	Clear()
						{
							m_nBreakBeforeType	= 0;
						}
					public:
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode)
						{
							CString strDefaultValue;

							strDefaultValue.Format(_T("%s"), GetBreakType(m_nBreakBeforeType));
							SetBreakType(m_nBreakBeforeType, oXmlNode.GetAttributeOrValue(_T("break-before"), strDefaultValue));
						}
					};

					class CBorderProperties : private CXmlAttributeReader
					{
					public:
						class CSide
						{
						public:
							CPen	m_oPen;

						public:
							CSide()
								: m_oPen()
							{
							}
						public:
							CGraphicLine*	GetGraphicLine(const REAL &fStartX, const REAL &fStartY, const REAL &fFinishX, const REAL &fFinishY)
							{
								CGraphicLine *pGraphicLine = new CGraphicLine();
								pGraphicLine->SetPen(m_oPen);
								pGraphicLine->SetStartPoint(fStartX * (25.4f / 72.0f), fStartY * (25.4f / 72.0f));
								pGraphicLine->SetFinishPoint(fFinishX * (25.4f / 72.0f), fFinishY * (25.4f / 72.0f));

								return pGraphicLine;
							}
						};
					public:
						CSide	*m_pLeftSide;
						CSide	*m_pRightSide;
						CSide	*m_pTopSide;
						CSide	*m_pBottomSide;

					public:
						CBorderProperties()
							: m_pLeftSide(NULL), m_pRightSide(NULL), 
							m_pTopSide(NULL), m_pBottomSide(NULL)
						{
						}
						CBorderProperties& operator=(const CBorderProperties& oSrc)
						{
							if (oSrc.m_pLeftSide != NULL)
							{
								m_pLeftSide		= new CSide();
								*m_pLeftSide	= *oSrc.m_pLeftSide;
							}
							if (oSrc.m_pRightSide != NULL)
							{
								m_pRightSide	= new CSide();
								*m_pRightSide	= *oSrc.m_pRightSide;
							}
							if (oSrc.m_pTopSide != NULL)
							{
								m_pTopSide	= new CSide();
								*m_pTopSide	= *oSrc.m_pTopSide;
							}
							if (oSrc.m_pBottomSide != NULL)
							{
								m_pBottomSide	= new CSide();
								*m_pBottomSide	= *oSrc.m_pBottomSide;
							}

							return *this;
						}
						int GetBorderType()
						{
							int res = 0;
							if (m_pLeftSide != NULL)
								res += 1;
							if (m_pRightSide != NULL)
								res += 2;
							if (m_pTopSide != NULL)
								res += 4;
							if (m_pBottomSide != NULL)
								res += 8;
							return res;
						}
					public:
						void	Clear()
						{
							RELEASEOBJECT(m_pLeftSide);
							RELEASEOBJECT(m_pRightSide);
							RELEASEOBJECT(m_pTopSide);
							RELEASEOBJECT(m_pBottomSide);
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode)
						{
							LoadSide(oXmlNode, _T("left"), &m_pLeftSide);
							LoadSide(oXmlNode, _T("right"), &m_pRightSide);
							LoadSide(oXmlNode, _T("top"), &m_pTopSide);
							LoadSide(oXmlNode, _T("bottom"), &m_pBottomSide);
						}
					private:
						void	LoadSide(XmlUtils::CXmlNode &oXmlNode, const CString &strSideName, CSide** ppSide)
						{
							CSide* pSide	= *ppSide;
							CString strStyle	= oXmlNode.GetAttributeOrValue(_T("border-") + strSideName + _T("-style"), _T(""));

							if (strStyle != _T(""))
							{
								if (strStyle == _T("none"))
								{
									RELEASEOBJECT(pSide);
									*ppSide	= NULL;
								}
								else
								{
									if (pSide == NULL)
									{
										*ppSide	= new CSide();
										pSide	= *ppSide;
									}

									CXmlAttributeReader::SetPenStyle(pSide->m_oPen.m_oPen, strStyle);

									REAL fWidth	= oXmlNode.ReadAttributeOrValueFloat(_T("border-") + strSideName + _T("-width"), -1);
									if (fWidth > 0)
									{
										if (fWidth > 6)
										{
											fWidth	= 1;
										}
										pSide->m_oPen.m_oPen.Size = fWidth * 0.3528f;
									}
									else
									{
										RELEASEOBJECT(pSide);
										*ppSide	= NULL;
										return;
									}

									LONG iColor	= CXmlAttributeReader::LongAttributeHexFromXml(oXmlNode, _T("border-") + strSideName + _T("-color"), -1);
									if (iColor >= 0)
									{
										if (iColor != 0xFFFFFF)
											pSide->m_oPen.m_oPen.Color = BGRToRGB(iColor);
										else 
											pSide->m_oPen.m_oPen.Color = 0xFFFFFF;
									}
								}
							}
						}
					};
					class CBackgroundProperties : private CXmlAttributeReader
					{
					public:
						CBackgroundRect*	m_pRect;
						CBrush				m_oBrush;	 

					public:
						CBackgroundProperties()
							: m_pRect(NULL)
						{
						}
						CBackgroundProperties& operator=(const CBackgroundProperties& oSrc)
						{
							if (oSrc.m_pRect != NULL)
							{
								m_pRect		= new CBackgroundRect();
								*m_pRect	= *oSrc.m_pRect;
							}

							return *this;
						}
						CBackgroundRect*	GetBackgroundRect(const REAL &fStartX, const REAL &fStartY, const REAL &fWidth, const REAL &fHeight)
						{
							CBackgroundRect *pBackgroundRect	= new CBackgroundRect();
							pBackgroundRect->SetBrush(m_oBrush);
							pBackgroundRect->SetStartPoint(fStartX * (25.4f / 72.0f), fStartY * (25.4f / 72.0f));
							pBackgroundRect->SetSize(fWidth * (25.4f / 72.0f), fHeight * (25.4f / 72.0f));

							return pBackgroundRect;
						}
						CBackgroundRect*	GetBackgroundRect2(const REAL &fStartX, const REAL &fStartY, const REAL &fWidth, const REAL &fHeight)
						{
							CBackgroundRect *pBackgroundRect	= new CBackgroundRect();
							pBackgroundRect->SetBrush(m_oBrush);
							pBackgroundRect->SetStartPoint(fStartX , fStartY);
							pBackgroundRect->SetSize(fWidth, fHeight);

							return pBackgroundRect;
						}
					public:
						void	Clear()
						{
							RELEASEOBJECT(m_pRect);
						}
						void	PageBGFromXml(XmlUtils::CXmlNode & oXmlNode)
						{	
							LONG iColor	= CXmlAttributeReader::LongAttributeHexFromXml(oXmlNode, _T("w:color"), -1);
							if (iColor >= 0 && iColor != 0x00FFFFFF)
							{		
								if (m_pRect == NULL)
								{
									CBackgroundRect* ppRect	= new CBackgroundRect();
									m_pRect	= ppRect;
								}	
								m_oBrush.m_oBrush.Color1 = BGRToRGB(iColor);
								m_oBrush.m_oBrush.Alpha1 = 255;
							}
							else
							{
								m_oBrush.m_oBrush.Alpha1 = 0;
							}
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode)
						{							
							LONG iColor	= CXmlAttributeReader::LongAttributeHexFromXml(oXmlNode, _T("background-color"), -1);
							if (iColor >= 0)
							{
								if (m_pRect == NULL)
								{
									CBackgroundRect* ppRect	= new CBackgroundRect();
									m_pRect	= ppRect;
								}			
								if (iColor != 0x00FFFFFF)
									m_oBrush.m_oBrush.Color1 = BGRToRGB(iColor);
								else
									m_oBrush.m_oBrush.Color1 = 0xFFFFFF;
								m_oBrush.m_oBrush.Alpha1 = 255;
							}
							else
							{
								m_oBrush.m_oBrush.Alpha1 = 0;
							}
						}
						bool HasColor()
						{
							//if ()
							return !(m_pRect->m_oBrush.m_oBrush.Alpha1 == 0);
						}
					};
					class CPaddingProperties : private CXmlAttributeReader
					{
					public:
						REAL	m_fPaddingLeft;
						REAL	m_fPaddingRight;
						REAL	m_fPaddingTop;
						REAL	m_fPaddingBottom;

					public:
						// ---
						CPaddingProperties()
							: m_fPaddingLeft(1.8f), m_fPaddingRight(1.8f), 
							m_fPaddingTop(1.8f), m_fPaddingBottom(1.8f)
						{
						}
						// ---
						void	Clear()
						{
							m_fPaddingLeft		= 18.0f;
							m_fPaddingRight		= 18.0f;
							m_fPaddingTop		= 18.0f;
							m_fPaddingBottom	= 18.0f;
						}
						// ---
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
							m_fPaddingLeft		= FloatPtAttributeFromXml(oXmlNode, _T("padding-left"), m_fPaddingLeft);
							if (m_fPaddingLeft < 0)
								m_fPaddingLeft	= 1.8f;
							m_fPaddingRight		= FloatPtAttributeFromXml(oXmlNode, _T("padding-right"), m_fPaddingRight);
							if (m_fPaddingLeft < 0)
								m_fPaddingLeft	= 1.8f;
							m_fPaddingTop		= FloatPtAttributeFromXml(oXmlNode, _T("padding-top"), m_fPaddingTop);
							if (m_fPaddingLeft < 0)
								m_fPaddingLeft	= 1.8f;
							m_fPaddingBottom	= FloatPtAttributeFromXml(oXmlNode, _T("padding-bottom"), m_fPaddingBottom);
							if (m_fPaddingLeft < 0)
								m_fPaddingLeft	= 1.8f;
						}

					};
					class CMarginProperties : protected CXmlAttributeReader
					{
					public:
						REAL	m_nSpaceBefore;
						REAL	m_nSpaceAfter;
						REAL	m_nLineSpacing; //  xsl-fo     line-height.minimum
						REAL	m_fLineHeight;

						REAL	m_fStartIndent;
						REAL	m_fEndIndent;
						REAL	m_fTextIndent;

					public:
						CMarginProperties() 
							: m_nSpaceBefore(0.0f), m_nSpaceAfter(0.0f), m_nLineSpacing(0.0f), m_fLineHeight(0.0f), 
							m_fStartIndent(0.0f), m_fEndIndent(0.0f), m_fTextIndent(0.0f)
						{
						}
					public:
						void	Clear()
						{
							m_nSpaceBefore		= 0;
							m_nSpaceAfter		= 0;
							m_nLineSpacing		= 0;
							m_fLineHeight		= 0;

							m_fStartIndent		= 0;
							m_fEndIndent		= 0;
							m_fTextIndent		= 0;
						}
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode, CDocumentManager& documentManager)
						{
							m_nLineSpacing	= -oXmlNode.ReadAttributeOrValueFloat(_T("linespacing"), 0);
							m_nSpaceBefore	= -oXmlNode.ReadAttributeOrValueFloat(_T("spacebefore"), 0);
							m_nSpaceAfter	= -oXmlNode.ReadAttributeOrValueFloat(_T("spaceafter"), 0);

							m_fStartIndent	= oXmlNode.ReadAttributeOrValueFloat(_T("leftmargin"), 0)	* documentManager.m_ItemManager.GetMultiplierX();
							m_fEndIndent	= oXmlNode.ReadAttributeOrValueFloat(_T("rightmargin"), 0)	* documentManager.m_ItemManager.GetMultiplierX();
							m_fTextIndent	= oXmlNode.ReadAttributeOrValueFloat(_T("indent"), 0)		* documentManager.m_ItemManager.GetMultiplierX();
							if (m_fStartIndent + m_fTextIndent < 0)
							{
								m_fTextIndent	= -m_fStartIndent;
							}
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode, const bool& bAndVerctical = true)
						{
							m_nSpaceBefore	= FloatPtAttributeFromXml(oXmlNode, _T("space-before"), m_nSpaceBefore);
							m_nSpaceAfter	= FloatPtAttributeFromXml(oXmlNode, _T("space-after"), m_nSpaceAfter);
							m_fLineHeight	= FloatPtAttributeFromXml(oXmlNode, _T("line-height"), m_fLineHeight);
							if (m_fLineHeight < -4.0f)
							{
								m_fLineHeight	= -1.0f;
							}

							m_nLineSpacing	= FloatPtAttributeFromXml(oXmlNode, _T("line-height.minimum"), 0);
							if (m_nLineSpacing < -4.0f)
							{
								m_nLineSpacing	= -1.0f;
							}

							if (bAndVerctical)
							{
								m_fStartIndent	= FloatPtAttributeFromXml(oXmlNode, _T("start-indent"), m_fStartIndent);
								m_fEndIndent	= FloatPtAttributeFromXml(oXmlNode, _T("end-indent"), m_fEndIndent);
								m_fTextIndent	= FloatPtAttributeFromXml(oXmlNode, _T("text-indent"), m_fTextIndent);
							}
						}
					};
					class CTabParams: CXmlAttributeReader
					{
					private:
						float	m_fTabPosition;
						byte	m_bLeader;
						byte	m_bType;
					public:
						CTabParams()
							: m_fTabPosition(0),
							m_bLeader(0),
							m_bType(0)
						{}
						CTabParams(float fPos, byte bLeader, byte bType)
							: m_fTabPosition(fPos),
							m_bLeader(bLeader),
							m_bType(bType)
						{}
						CTabParams(float fPos, CString strLeader, CString strType)
							: m_fTabPosition(fPos)
						{
							m_bLeader	= SetLeaderTab(strLeader);
							m_bType		= SetTypeTab(strType);
						}
						~CTabParams()
						{}
						friend bool operator>(const CTabParams& a, const CTabParams& b)
						{
							return (a.m_fTabPosition > b.m_fTabPosition) ? true : false;
						}
						friend bool operator<(const CTabParams& a, const CTabParams& b)
						{
							return (a.m_fTabPosition < b.m_fTabPosition) ? true : false;
						}
						friend bool operator>=(const CTabParams& a, const CTabParams& b)
						{
							return (a.m_fTabPosition >= b.m_fTabPosition) ? true : false;
						}
						friend bool operator<=(const CTabParams& a, const CTabParams& b)
						{
							return (a.m_fTabPosition <= b.m_fTabPosition) ? true : false;
						}
					public:
						float GetPosition()
						{
							return m_fTabPosition;
						}
						void SetPosition(float fPos)
						{
							m_fTabPosition = fPos;
						}
						byte GetLeader()
						{
							return m_bLeader;
						}
						void SetLeader(byte bLeader)
						{
							m_bLeader = bLeader;
						}
						byte GetType()
						{
							return m_bType;
						}
						void SetType(byte bType)
						{
							m_bType = bType;
						}

					};
					class CTabProperties : protected CXmlAttributeReader
					{
					public:
						CArray<CTabParams> m_arrTabs;
						float			m_fDefaultTabSize;

					public:
						CTabProperties()
							: m_arrTabs(), m_fDefaultTabSize(0.0f) 
						{
						}
					public:
						void	Clear()
						{
							m_arrTabs.RemoveAll();
							m_fDefaultTabSize	= 0.0f;
						}
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
							m_fDefaultTabSize	= (REAL)oXmlNode.ReadAttributeOrValueInt(_T("defaulttabsize"), 0) * 72.0f / (36000.0f*25.4f);

							if (m_fDefaultTabSize < 0)
								m_fDefaultTabSize = -m_fDefaultTabSize;
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode)
						{
							m_fDefaultTabSize = FloatPtAttributeFromXml(oXmlNode, _T("default-tab-size"), 0);
							XmlUtils::CXmlNodes oTabsNodes;
							XmlUtils::CXmlNode oTabsNode;
							if (oXmlNode.GetNodes(_T("fo:tabs"), oTabsNodes))
							{
								for(int i = 0; i < oTabsNodes.GetCount(); i++ )
									if (oTabsNodes.GetAt(i, oTabsNode))
									{
										XmlUtils::CXmlNodes oTabNodes;
										oTabsNode.GetNodes(_T("fo:tab"), oTabNodes);
										int iCount = oTabNodes.GetCount();
										for (int iIndex = 0; iIndex < iCount; ++iIndex)
										{
											XmlUtils::CXmlNode oNode;
											oTabNodes.GetAt(iIndex, oNode);
											float fTabPosition = oNode.ReadAttributeOrValueFloat(_T("position"), -1);
											if (fTabPosition >= 0.0f)
											{												
												CString tabLeader = oNode.GetAttributeOrValue(_T("leader"));
												CString tabType   = oNode.GetAttributeOrValue(_T("val"), _T("left"));
												m_arrTabs.Add(CTabParams(fTabPosition, tabLeader, tabType));
											}
										}
									}
									m_arrTabs.Sort();
									Replace();
							}
						}
						//   left,    num,    
						void Replace()
						{
							size_t nSize = m_arrTabs.GetCount();
							bool hasLeftInThisPosition = false;
							for(size_t i = 0; i < nSize; i++)
							{
								if (m_arrTabs[i].GetType() == 0)
									hasLeftInThisPosition = true;
								if (m_arrTabs[i].GetType() == 2)
								{
									if (i>0 && m_arrTabs[i].GetPosition() == m_arrTabs[i - 1].GetPosition() && hasLeftInThisPosition == true)
									{
										m_arrTabs[i].SetType(0);
									}
									else
									{
										size_t j = i;
										while (j < nSize - 1 && m_arrTabs[j].GetPosition() == m_arrTabs[j + 1].GetPosition() )
										{											
											j++;
											if (m_arrTabs[j].GetType() == 0)
											{
												m_arrTabs[i].SetType(0);
												break;
											}
										}
									}
								}
							}
						}						
					};
					class CBlockAttributes : public CMarginProperties, public CBreakProperties, public CTabProperties, public CBorderProperties, public CBackgroundProperties
					{
					public:
						BOOL	m_bIsFirst;

						LONG	m_lCount;

						WORD	m_nTextAlignment;

						WORD	m_nWrapFlags;
						BYTE	m_nKeepTogether;
						BYTE	m_nKeepNext;
						bool _oneLine;

						CString				m_pStyle;
						CString				m_contextualSpacing;

						CBulletProperties	*m_pBulletProperties;

					public:
						CBlockAttributes() 
							: CMarginProperties(), 
							CBreakProperties(), 
							m_bIsFirst(FALSE), 
							m_lCount(0), 
							m_nTextAlignment(0), 
							m_nWrapFlags(0), m_nKeepTogether(0), m_nKeepNext(0), 
							m_pBulletProperties(NULL), m_pStyle(), m_contextualSpacing(), 
							_oneLine(false)
						{
						}						
						~CBlockAttributes()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							CMarginProperties::Clear();
							CBreakProperties::Clear();
							CTabProperties::Clear();

							m_lCount			= 0;

							m_nTextAlignment	= 0;

							m_nWrapFlags		= 1;
							m_nKeepTogether		= 0;
							m_nKeepNext			= 0;

							RELEASEOBJECT(m_pBulletProperties);
							_oneLine = false;
						}
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode, CDocumentManager& documentManager)
						{
							m_lCount	= oXmlNode.ReadAttributeOrValueInt(_T("count"), 0);

							int nTextAlignment	= (WORD)oXmlNode.ReadAttributeOrValueInt(_T("textalignment"), -1);
							if (nTextAlignment >= 0)
							{
								m_nTextAlignment	= nTextAlignment;
							}

							m_nWrapFlags	= (WORD)oXmlNode.ReadAttributeOrValueInt(_T("wrapflags"), 0);

							WORD nBulletFlag	= (WORD)oXmlNode.ReadAttributeOrValueInt(_T("bulletflag"), 0);
							if (nBulletFlag & 1)
							{
								RELEASEOBJECT(m_pBulletProperties);
								m_pBulletProperties	= new CBulletProperties();
								m_pBulletProperties->FromXmlNode(oXmlNode);
							}

							CMarginProperties::FromXmlNode(oXmlNode, documentManager);
							CTabProperties::FromXmlNode(oXmlNode);

							if (oXmlNode.GetAttribute(_T("oneline")) == _T("1"))
								_oneLine = true;
							else
								_oneLine = false;
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode, const bool &bMarginSet = true)
						{
							CMarginProperties::FromXmlNode2(oXmlNode, bMarginSet);
							m_arrTabs.Add(CTabParams((float)m_fStartIndent - 0.001, _T("leader"), _T("num")));

							CBreakProperties::FromXmlNode2(oXmlNode);
							CTabProperties::FromXmlNode2(oXmlNode);
							CBorderProperties::FromXmlNode2(oXmlNode);
							CBackgroundProperties::FromXmlNode2(oXmlNode);

							m_pStyle			= oXmlNode.GetAttributeOrValue(_T("fo:pStyle"), _T("usualStyle"));
							m_contextualSpacing = oXmlNode.GetAttributeOrValue(_T("fo:contextualSpacing"), _T("false"));

							CString strDefaultValue;
							strDefaultValue.Format(_T("%s"), GetTextAlignment(m_nTextAlignment));
							SetTextAlignment(m_nTextAlignment, oXmlNode.GetAttributeOrValue(_T("text-align"), strDefaultValue));
							SetKeepTogether(m_nKeepTogether, oXmlNode.GetAttributeOrValue(_T("keep-together.within-page")));
							SetKeepNext(m_nKeepNext, oXmlNode.GetAttributeOrValue(_T("keep-with-next")));
						}
					};

					class CBlockFrameAttributes : private CXmlAttributeReader
					{
					public:
						CString m_dropCap;
						int		m_lines;

					public:
						double		m_vSpace;
						double		m_hSpace;

					public:
						CString		m_vAnchor;
						CString		m_hAnchor;
						CString		m_xAlign;
						CString		m_yAlign;

					public:
						double		m_x;
						double		m_y;
						double		m_width;
						double		m_height;

					public:
						CString m_wrap;
					public:
						CBlockFrameAttributes() 
							: m_dropCap(_T("")), m_lines(0), m_vSpace(0), m_hSpace(0), m_vAnchor(_T("")),
							m_hAnchor(_T("")), m_wrap(_T("")), m_x(-1), m_y(-1), m_width(0), m_height(0)
						{
						}
					public:
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
#ifdef AVS_LOG_DEBUG
							CString p = oXmlNode.GetXml();
#endif
							m_dropCap	= oXmlNode.GetAttributeOrValue(_T("w:dropCap"), _T(""));
							m_lines		= oXmlNode.ReadAttributeOrValueInt(_T("w:lines"), 0);

							m_vSpace	= oXmlNode.ReadAttributeOrValueDouble(_T("w:vSpace"), 0) / 20;
							m_hSpace	= oXmlNode.ReadAttributeOrValueDouble(_T("w:hSpace"), 0) / 20;

							m_vAnchor	= oXmlNode.GetAttributeOrValue(_T("w:vAnchor"), _T(""));
							m_hAnchor	= oXmlNode.GetAttributeOrValue(_T("w:hAnchor"), _T(""));

							m_xAlign	= oXmlNode.GetAttributeOrValue(_T("w:xAlign"), _T(""));
							m_yAlign	= oXmlNode.GetAttributeOrValue(_T("w:yAlign"), _T(""));

							m_x			= oXmlNode.ReadAttributeOrValueDouble(_T("w:x"), -1)/20;
							m_y			= oXmlNode.ReadAttributeOrValueDouble(_T("w:y"), -1)/20;

							m_width		= oXmlNode.ReadAttributeOrValueDouble(_T("w:w"), 0)/20;
							m_height	= oXmlNode.ReadAttributeOrValueDouble(_T("w:h"), 0)/20;

							m_wrap		= oXmlNode.GetAttributeOrValue(_T("w:wrap"), _T(""));
						}						
					};
					class CListBlockAttributes : public CBreakProperties
					{
					public:
						CListBlockAttributes() 
							: CBreakProperties()
						{
						}						
						~CListBlockAttributes()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							CBreakProperties::Clear();
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode)
						{
							XmlUtils::CXmlNode oItemNode;
							oXmlNode.GetNode(_T("fo:list-item"), oItemNode);
							CBreakProperties::FromXmlNode2(oItemNode);
						}
					};

					class CTextAttributes : private CXmlAttributeReader
					{
					public:
						enum ETextTransform {
							NoneTransform = 0, CapsTransform, SmallCapsTransform
						};

					public:
						CFont		m_oFont;
						CString		m_FontFamilyEA;
						CString		_fontFamilyCS;

						CBrush		m_oBrush;
						CShadow		m_oShadow;
						CBackground m_oBackground;
						CEdge		m_oEdge;

						WORD	m_nTextAlignmentVertical;
						WORD	m_nTextAlignmentHorizontal;
						BOOL	m_bAntiAliasText;

						WORD	m_nBaselineShift;
						REAL	m_fBaselineShift;
					public:
						CTextAttributes() : m_oFont(), m_FontFamilyEA(_T("")), _fontFamilyCS(_T("")),
							m_oBrush(), m_oShadow(), m_oBackground(), m_oEdge(),
							m_nTextAlignmentVertical(0), m_nTextAlignmentHorizontal(0),
							m_bAntiAliasText(TRUE), 
							m_nBaselineShift(0), m_fBaselineShift(0.0f), 
							m_TextTransform(NoneTransform)
						{
						}
						CTextAttributes&	operator=(const CTextAttributes& oSrc)
						{
							m_oFont			= oSrc.m_oFont;
							m_FontFamilyEA	= oSrc.m_FontFamilyEA;
							_fontFamilyCS	= oSrc._fontFamilyCS;

							m_oBrush		= oSrc.m_oBrush;
							m_oShadow		= oSrc.m_oShadow;
							m_oBackground	= oSrc.m_oBackground;
							m_oEdge			= oSrc.m_oEdge;

							m_nTextAlignmentVertical	= oSrc.m_nTextAlignmentVertical;
							m_nTextAlignmentHorizontal	= oSrc.m_nTextAlignmentHorizontal;
							m_bAntiAliasText			= oSrc.m_bAntiAliasText;

							m_nBaselineShift	= oSrc.m_nBaselineShift;
							m_fBaselineShift	= oSrc.m_fBaselineShift;

							m_TextTransform = oSrc.m_TextTransform;

							return *this;
						}
					public:
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
							m_oFont.FromXmlNode(oXmlNode);
							m_oBrush.FromXmlNode(oXmlNode);
							m_oShadow.FromXmlNode(oXmlNode);
							m_oBackground.FromXmlNode(oXmlNode);
							m_oEdge.FromXmlNode(oXmlNode);

							m_nTextAlignmentVertical	= 1 + (WORD)oXmlNode.ReadAttributeOrValueInt(_T("font-stringalignmentvertical"), 0);
							m_nTextAlignmentHorizontal	= (WORD)oXmlNode.ReadAttributeOrValueInt(_T("font-stringalignmenthorizontal"), 0);
							m_bAntiAliasText			= (BOOL)oXmlNode.ReadAttributeOrValueInt(_T("font-antialiastext"), -1);

							m_fBaselineShift			= oXmlNode.ReadAttributeOrValueFloat(_T("baseline-shift"), 0) / 100.0f;
							if (m_fBaselineShift != 0)
							{
								m_fBaselineShift	*= (REAL)m_oFont.m_oFont.Size;
								m_oFont.m_oFont.Size = m_oFont.m_oFont.Size * 0.667f;
							}
						}						
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode)
						{
							FromXmlAttributes(oXmlNode);
						}
						void	FromXmlNode3(XmlUtils::CXmlNode &oXmlNode, bool IsInTOC)
						{
							if (IsInTOC == false)
							{
								XmlUtils::CXmlNode oXmlComplete;
								oXmlNode.GetNode(_T("style-complete"), oXmlComplete);
								FromXmlAttributes(oXmlComplete);
							}
							else
							{
								XmlUtils::CXmlNode oXmlReduce;
								oXmlNode.GetNode(_T("style-reduce"), oXmlReduce);
								FromXmlAttributes(oXmlReduce);
							}
						}
					public:
						const ETextTransform&	TextTransform() const
						{
							return m_TextTransform;
						}
					public:
						void	ProcessFontProperties(XmlUtils::CXmlNode& character, CDocumentManager& documentManager)
						{
							XmlUtils::CXmlNode fontProperties;
							if (character.GetNode(_T("FontProperties"), fontProperties))
								documentManager.AddFont(m_oFont, fontProperties.GetXml());
						}



					private:
						ETextTransform	m_TextTransform;
					private:
						void	FromXmlAttributes(XmlUtils::CXmlNode &oXmlNode)
						{
							XML::IXMLDOMNamedNodeMapPtr pAttributes = oXmlNode.GetAttributes();
							if (NULL == pAttributes)
								return;

							m_oFont.FromXmlAttributes(pAttributes);
							BSTR value = GetAttribute(pAttributes, g_cpszXML_Font_Family_EA);
							if (value != NULL)
							{
								m_FontFamilyEA = value;
								SysFreeString(value);
							}

							value = GetAttribute(pAttributes, g_cpszXML_Font_Family_CS);
							if (value != NULL)
							{
								_fontFamilyCS = value;
								SysFreeString(value);
							}

							m_oBrush.FromXmlAttributes(pAttributes);
							m_oShadow.FromXmlAttributes(pAttributes);
							m_oBackground.FromXmlAttributes(pAttributes);

							BSTR bsValue = GetAttribute(pAttributes, g_cpszXML_Text_Align);
							if (NULL != bsValue)
							{
								m_nTextAlignmentHorizontal = (WORD)XmlUtils::GetInteger(bsValue);
								SysFreeString(bsValue);
							}
							else
								m_nTextAlignmentHorizontal = 0;

							bsValue = GetAttribute(pAttributes, g_cpszXML_Text_BaselineShift);
							if (NULL != bsValue)
							{
								CString strValue = (CString)bsValue;
								SetBaselineShift(m_nBaselineShift, m_fBaselineShift, strValue);

								SysFreeString(bsValue);
							}

							if (m_nBaselineShift != 0)
								m_oFont.m_oFont.Size = m_oFont.m_oFont.Size * 0.667f;

							value = GetAttribute(pAttributes, g_cpszXML_Text_Transform);
							if (value != NULL)
							{
								CString transform = value;
								SysFreeString(value);
								if (transform == _T("caps"))
									m_TextTransform = CapsTransform;
							}
							else
								m_TextTransform = NoneTransform;
						}
						void	LoadBaseline(XmlUtils::CXmlNode &oXmlNode)
						{
							CString strDefaultValue = _T("");

							strDefaultValue.Format(_T("%s"), GetBaselineShift(m_nBaselineShift));
							SetBaselineShift(m_nBaselineShift, m_fBaselineShift, oXmlNode.GetAttributeOrValue(_T("baseline-shift"), strDefaultValue));

							if (m_nBaselineShift != 0)
								m_oFont.m_oFont.Size = m_oFont.m_oFont.Size * 0.667f;
						}

					public:
						void checkFontRange(CString& text) {
							if (text.GetLength() < 1)
								return;
							WCHAR symbol = text[0];
							if ((0x2e80 <= symbol) && (symbol <= 0x9fff) && (m_FontFamilyEA != _T("")))
								m_oFont.SetName(m_FontFamilyEA);
							else if ((0x0590 <= symbol) && (symbol <= 0x05ff) && (_fontFamilyCS != _T("")))
								m_oFont.SetName(_fontFamilyCS);
						}
					};

					class CCharacter
					{
					private:
						bool _isLabel;

					public:
						LONG			m_lCount;
						CTextAttributes	m_oAttributes;

						CLinkProperties	m_oLink;
						BYTE			m_nAdditionalParam;

					public:
						CCharacter() 
							: m_oAttributes(), m_lCount(0), 
							m_oLink(), m_nAdditionalParam(0),
							_isLabel(false)
						{
						}
						CCharacter(const CCharacter& src) {
							m_lCount = src.m_lCount;
							m_oAttributes = src.m_oAttributes;

							m_oLink = src.m_oLink;
							m_nAdditionalParam = src.m_nAdditionalParam;

							_isLabel = src._isLabel;
						}
						~CCharacter()
						{
						}
					public:
						void	FromXmlNode(XmlUtils::CXmlNode& oXmlNode)
						{
							m_lCount = oXmlNode.ReadAttributeOrValueInt(_T("count"), 0);

							XmlUtils::CXmlNode oAttributeNode;
							if (oXmlNode.GetNode(_T("Attributes"), oAttributeNode))
								m_oAttributes.FromXmlNode(oAttributeNode);
						}
						void	FromXmlNode(XmlUtils::CXmlNode& oXmlNode, CDocumentManager& documentManager)
						{
							FromXmlNode(oXmlNode);
							m_oAttributes.ProcessFontProperties(oXmlNode, documentManager);
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode, CLinkProperties& oLink)
						{
							if (oXmlNode.GetName() == _T("fo:inline"))
							{
								CString strText	= oXmlNode.GetTextExt();
								m_lCount		= strText.GetLength();
							}

							m_oLink	= oLink;

							m_oAttributes.FromXmlNode2(oXmlNode);
						}
						void	FromXmlNode3(XmlUtils::CXmlNode &oXmlNode, CLinkProperties& oLink, bool IsInTOC)
						{
							if (oXmlNode.GetName() == _T("fo:inline"))
							{
								CString strText	= oXmlNode.GetTextExt();
								m_lCount		= strText.GetLength();
							}

							m_oLink	= oLink;

							m_oAttributes.FromXmlNode3(oXmlNode, IsInTOC);
						}
						void	FromXmlNode2(XmlUtils::CXmlNode &oXmlNode)
						{
							if (oXmlNode.GetName() != _T("text"))
							{
								m_oAttributes.FromXmlNode2(oXmlNode);
								m_lCount = 0;
							}
							else
							{
								CString strText	= oXmlNode.GetTextExt();
								m_lCount		= strText.GetLength();
							}
						}
						void	FromXmlNode3(XmlUtils::CXmlNode &oXmlNode, bool IsInTOC)
						{
							if (oXmlNode.GetName() != _T("text"))
							{
								m_oAttributes.FromXmlNode3(oXmlNode, IsInTOC);
								m_lCount = 0;
							}
							else
							{
								CString strText	= oXmlNode.GetTextExt();
								m_lCount		= strText.GetLength();
							}
						}
					public:
						inline bool getIsLabel() const {
							return _isLabel;
						}
						inline void setIsLabel(const bool& value) {
							_isLabel = value;
						}
					public:
						void	Transform(CString& text)
						{
							try
							{
								if (m_oAttributes.TextTransform() == CTextAttributes::CapsTransform)
									CharUpper(text.GetBuffer());
							}
							catch (...)
							{
							}
						}
						void CheckFontRange(CString& text) {
							m_oAttributes.checkFontRange(text);
						}
					};
					// ### ### ###
					class CPage;
					class CRegion;
					class CAlternate2;
					class CItem;
					class CSymbols;
					class CBullet;
					class CTabStop;
					class CFootnote;
					class CGrapher;
					class CFontTable
					{
					public:
						class CFontProperties
						{
						public:
							CFontProperties() : 
							  m_Name(_T("")), m_AltName(_T("")), 
								  m_Charset(0), m_Family(_T("")), m_Panose(_T("")), m_Fixed(_T("1")), 
								  m_SigUsb0(_T("00000000")), m_SigUsb1(_T("00000000")), m_SigUsb2(_T("00000000")), m_SigUsb3(_T("00000000")), 
								  m_SigCsb0(_T("00000000")), m_SigCsb1(_T("00000000"))
							  {
							  }
						public:
							byte	FromXml(XmlUtils::CXmlNode& font, const CString& name, IAVSFontManager* fontManager)
							{
								m_Name = name;
								FromXml(font);

								CString params = _T("<FontProperties>");
								CString charset;
								charset.Format(_T("%x"), m_Charset);
								params += _T("<Charset value='") + charset + _T("'/>");
								params += _T("<Name value='") + m_Name + _T("'/>");
								params += _T("<AltName value='") + m_AltName + _T("'/>");
								params += _T("<FamilyClass name='") + m_Family + _T("'/>");
								params += _T("<Panose value='") + m_Panose + _T("'/>");
								params += _T("<FixedWidth value='") + m_Fixed + _T("'/>");
								params += _T("<UnicodeRange range1='") + m_SigUsb0 + _T("' ");
								params += _T("range2='") + m_SigUsb1 + _T("' ");
								params += _T("range3='") + m_SigUsb2 + _T("' ");
								params += _T("range4='") + m_SigUsb3 + _T("' ");
								params += _T("coderange1='") + m_SigCsb0 + _T("' ");
								params += _T("coderange2='") + m_SigCsb1 + _T("'/>");
								params += _T("</FontProperties>");

								BSTR bstrFontPath;
								long index = 0;
								BSTR bstrParams = params.AllocSysString();
								fontManager->GetWinFontByParams(bstrParams, &bstrFontPath, &index);
								SysFreeString(bstrParams);
								int status = fontManager->LoadFontFromFile(bstrFontPath, 12, 72, 72, index);
								SysFreeString(bstrFontPath);
								if (!CheckRange(fontManager))
								{
									params = _T("<FontProperties>");
									CString charset;
									charset.Format(_T("%x"), m_Charset);
									params += _T("<Charset value='") + charset + _T("'/>");
									params += _T("<Name value='") + m_Name + _T("'/>");
									params += _T("<AltName value='") + m_AltName + _T("'/>");
									params += _T("</FontProperties>");

									index = 0;
									bstrParams = params.AllocSysString();
									fontManager->GetWinFontByParams(bstrParams, &bstrFontPath, &index);
									SysFreeString(bstrParams);
									status = fontManager->LoadFontFromFile(bstrFontPath, 12, 72, 72, index);
									SysFreeString(bstrFontPath);
								}
								BSTR bstrFamilyName;
								fontManager->GetFamilyName(&bstrFamilyName);
								m_Name = CString(bstrFamilyName);
								SysFreeString(bstrFamilyName);

								return 0;
							}
							byte	FromXml(const CFont& font, const CString& properties, IAVSFontManager* fontManager)
							{
								BSTR bstrFontPath;
								long index = 0;
								BSTR bstrParams = properties.AllocSysString();
								fontManager->GetWinFontByParams(bstrParams, &bstrFontPath, &index);
								SysFreeString(bstrParams);
								int status = fontManager->LoadFontFromFile(bstrFontPath, 12, 72, 72, index);
								BSTR bstrFamilyName;
								fontManager->GetFamilyName(&bstrFamilyName);
								m_Name = CString(bstrFamilyName);
								SysFreeString(bstrFamilyName);
								return 0;
							}
						public:
							CString	Name() const 
							{
								return m_Name;
							}
							void	Name(const CString& name)
							{
								m_Name = name;
							}
							CString	AltName() const 
							{
								return m_AltName;
							}
							void	AltName(const CString& altName)
							{
								m_AltName = altName;
							}
						public:
							bool	CheckRange(IAVSFontManager* fontManager) const 
							{
								unsigned char charset = (unsigned char)m_Charset;
								unsigned long bit;
								unsigned int index;
								GetCodePageByCharset(charset, &bit, &index);
								VARIANT_BOOL rangeSuits = VARIANT_FALSE;
								fontManager->IsUnicodeRangeAvailable(bit, index, &rangeSuits);
								return (rangeSuits == VARIANT_TRUE);
							}

						private:
							CString	m_Name;
							CString m_AltName;

							int		m_Charset;
							CString	m_Family;
							CString	m_Panose;
							CString m_Fixed;

							CString	m_SigUsb0;
							CString	m_SigUsb1;
							CString	m_SigUsb2;
							CString	m_SigUsb3;
							CString	m_SigCsb0;
							CString	m_SigCsb1;

						private:
							byte	FromXml(XmlUtils::CXmlNode& font)
							{
								XmlUtils::CXmlNode altName;
								if (font.GetNode(_T("altName"), altName))
									m_AltName = altName.GetText();
								XmlUtils::CXmlNode charset;
								if (font.GetNode(_T("charset"), charset))
									m_Charset = HexToInt(charset.GetText());
								XmlUtils::CXmlNode family;
								if (font.GetNode(_T("family"), family))
									m_Family = family.GetText();
								XmlUtils::CXmlNode panose;
								if (font.GetNode(_T("panose"), panose))
									m_Panose = panose.GetText();
								XmlUtils::CXmlNode fixed;
								if (font.GetNode(_T("fixed"), fixed))
									m_Fixed = fixed.GetText();

								XmlUtils::CXmlNode sig;
								if (font.GetNode(_T("sig"), sig))
								{
									m_SigUsb0 = sig.GetAttribute(_T("usb0"), _T("00000000"));
									m_SigUsb1 = sig.GetAttribute(_T("usb1"), _T("00000000"));
									m_SigUsb2 = sig.GetAttribute(_T("usb2"), _T("00000000"));
									m_SigUsb3 = sig.GetAttribute(_T("usb3"), _T("00000000"));
									m_SigCsb0 = sig.GetAttribute(_T("csb0"), _T("00000000"));
									m_SigCsb1 = sig.GetAttribute(_T("csb1"), _T("00000000"));
								}

								return 0;
							}
						private:
							static int	HexToInt(int hex)
							{
								if ( hex >= '0' && hex <= '9' ) return (hex - '0');
								if ( hex >= 'a' && hex <= 'f' ) return (hex - 'a' + 10);
								if ( hex >= 'A' && hex <= 'F' ) return (hex - 'A' + 10);

								return 0;
							}
							static int	HexToInt(CString hex)
							{
								int result = 0;
								int mult = 1;
								for (int i = hex.GetLength() - 1; i >= 0; --i )
								{
									result += HexToInt(hex.GetAt(i)) * mult;
									mult <<= 4;
								}

								return result;
							}
						};

					private:
						std::map<CString, CFontProperties> m_Fonts;

					public:
						CFontTable() :
						  m_Fonts()
						  {
						  }
					public:
						byte	FromXml(XmlUtils::CXmlNode& fontTable, IAVSFontManager* fontManager)
						{
							XmlUtils::CXmlNodes fonts;
							if (!fontTable.GetNodes(_T("font"), fonts))
								return 1;
							int fontCount = fonts.GetCount();
							for (int index = 0; index < fontCount; ++index)
							{
								XmlUtils::CXmlNode font;
								fonts.GetAt(index, font);
								std::pair<CString, CFontProperties> fontPair;
								fontPair.first = font.GetAttribute(_T("name"));
								if (fontPair.second.FromXml(font, fontPair.first, fontManager))
									continue;
								m_Fonts.insert(fontPair);
							}

							return 0;
						}
					public:
						CString	SetFont(const CFont& font, IAVSFontManager* fontManager)
						{
							bool contains = Contains(font.Name());
							if (!contains)
								AddFont(font, fontManager);

							CFontProperties& properties = m_Fonts[font.Name()];

							if  (LoadFont(font, properties.Name(), fontManager) != S_OK) {
								BSTR fontName;
								fontManager->GetFamilyName(&fontName);
								properties.Name(fontName);
								SysFreeString(fontName);
							}

							return properties.Name();
						}
						void	AddFont(const CFont& font, const CString& properties, IAVSFontManager* fontManager)
						{
							std::pair<CString, CFontProperties> fontPair;
							fontPair.first = font.Name();
							fontPair.second.FromXml(font, properties, fontManager);
							m_Fonts.insert(fontPair);							
						}
					public:
						CString	GetName(const CFont& font)
						{
							return m_Fonts[font.Name()].Name();
						}
					private:
						int		LoadFont(const CFont& font, IAVSFontManager* fontManager)
						{
							return LoadFont(font, font.Name(), fontManager);
						}
						int		LoadFont(const CFont& font, const CString& name, IAVSFontManager* fontManager)
						{
							BSTR bstrName = name.AllocSysString();
							float size = (float)font.Size();
							LONG style = font.Style();
							int status = fontManager->LoadFontByName(bstrName, size, style, 72, 72);
							SysFreeString(bstrName);
							return status;
						}
					private:
						bool	Contains(const CString& name)
						{
							return (m_Fonts.find(name) != m_Fonts.end());
						}
						void	AddFont(const CFont& font, IAVSFontManager* fontManager)
						{
							std::pair<CString, CFontProperties> fontPair;
							fontPair.first = font.Name();
							fontPair.second.Name(fontPair.first);
							m_Fonts.insert(fontPair);
						}
					};
					class CLinker
					{
					private:
						struct CChain
						{
							CString	m_strID;
							INT		m_nID;

							RectF	m_oRect;
							WORD	m_nPageNumber;

							CChain(const CString& strID, const RectF& oRect, const WORD nPageNumber, const INT& nID = -1)
								: m_strID(strID), m_nID(nID), 
								m_oRect(oRect), m_nPageNumber(nPageNumber)
							{
							}
							CChain()
								: m_strID(_T("")), m_nID(-1), 
								m_oRect(), m_nPageNumber(0)
							{
							}
						};

						CArray<CChain>	m_arrSources;
						CArray<CChain>	m_arrTargets;

					public:
						CLinker() : 
						  m_arrSources(), m_arrTargets()
						  {
						  }
						  void	Clear()
						  {
							  m_arrSources.RemoveAll();
							  m_arrTargets.RemoveAll();
						  }
					public:
						void	AddTarget(const CString& strID, const RectF& oRect, const CDocumentManager& documentManager)
						{
							WORD pageIndex = documentManager.getPageIndex();
							CChain oChain(strID, oRect, pageIndex);

							m_arrTargets.Add(oChain);
						}
						void	AddSource(const CString& strID, const RectF& oRect, const CDocumentManager& documentManager, const bool& bIsExtern = true)
						{
							WORD nPageNumber = documentManager.getPageIndex() - 1;
							CChain oChain(strID, oRect, nPageNumber);

							m_arrSources.Add(oChain);
						}
						BSTR	GenerateXml()
						{
							CString strXml;
							strXml += _T("<linker>");

							size_t nCount = m_arrSources.GetCount();
							for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
							{
								strXml	+= _T("<link>");

								CChain* pChain	= &m_arrSources[nIndex];
								CString strSource;
								strSource.Format(_T("<source x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" page=\"%i\"/>"), pChain->m_oRect.X, pChain->m_oRect.Y, pChain->m_oRect.Width, pChain->m_oRect.Height, pChain->m_nPageNumber);
								strXml	+= strSource;

								CChain* pChain2	= FindTarget(pChain->m_strID);
								if (pChain2 != 0)
								{
									strSource.Format(_T("<target x=\"%f\" y=\"%f\" width=\"0\" height=\"0\" page=\"%i\"/>"), pChain2->m_oRect.X, pChain2->m_oRect.Y, pChain2->m_nPageNumber);
								}
								else
								{
									strSource.Format(_T("<target url=\"%s\"/>"), pChain->m_strID);
								}
								strXml	+= strSource;

								strXml	+= _T("</link>");
							}

							strXml	+= _T("</linker>");
							strXml.Replace(_T("&"), _T("&amp;"));

							return strXml.AllocSysString();
						}

					private:
						bool	IsContains()
						{
							return NULL;
						}
						CChain*	FindTarget(const CString& strID)
						{
							CChain* pTarget	= NULL;
							size_t nCount	= m_arrTargets.GetCount();
							for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
							{
								CString strTarget	= m_arrTargets[nIndex].m_strID;
								INT iPos			= 0;
								while (iPos != -1)
								{
									CString strToken	= strTarget.Tokenize(_T(";"), iPos);
									if (strToken == strID)
									{
										iPos	= 0;
										break;
									}
								}

								if (iPos == 0)
								{
									pTarget	= &m_arrTargets[nIndex];
								}
							}

							return pTarget;
						}
					};

					class CItemManager
					{
					private:
						REAL	m_fPrevLineHeight;

						REAL	m_fMultiplierX;
						REAL	m_fMultiplierY;

						REAL	m_fWidthL;
						REAL	m_fHeightL;

						bool	m_bWrapFlags;
						bool	m_bIsFo;

					public:
						CItemManager() : 
						  m_fPrevLineHeight(0), 
							  m_fMultiplierX(0), m_fMultiplierY(0), 
							  m_fWidthL(6000), m_fHeightL(6000), 
							  m_bWrapFlags(true), m_bIsFo(false)
						  {
						  }
					public:
						void	SetMultiplierY(const REAL &fMultiplierY)
						{
							m_fMultiplierY = fMultiplierY / m_fHeightL;
						}
						REAL	GetMultiplierY()
						{
							return m_fMultiplierY;
						}
						void	SetMultiplierX(const REAL &fMultiplierX)
						{
							m_fMultiplierX = fMultiplierX / m_fWidthL;
						}
						REAL	GetMultiplierX()
						{
							return m_fMultiplierX;
						}
						void	SetWidthL(const REAL &fWidthL)
						{
							m_fWidthL = fWidthL;
						}
						void	SetHeightL(const REAL &fHeightL)
						{
							m_fHeightL = fHeightL;
						}
						bool	WrapBySymbol()
						{
							return m_bWrapFlags;
						}
						BYTE	GetWrapFlags()
						{
							return m_bWrapFlags;
						}
						void	SetWrapFlags(const WORD &nWrapFlags)
						{
							if (nWrapFlags & 1)
							{
								m_bWrapFlags	= TRUE;
							}
							else
							{
								m_bWrapFlags	= FALSE;
							}
						}

						void	SetIsFo(const bool &bIsFo)
						{
							m_bIsFo	= bIsFo;
						}
						bool	IsFo()
						{
							return m_bIsFo;
						}
					public:
						void	PrepareItems(const CString &strText, CBlockAttributes *pParagraph, 
							CAtlArray<CCharacter*> &arrCharacters, CAtlArray<CAlternate2*> &arrAlternates, 
							CAtlArray<CAlternate2*> &anchors, CAtlArray<CFootnote*>& arrFootnotes, 
							CAtlArray<CItem*>& arrItems, CGrapher* pGrapher)
						{
							size_t nCharacterIndex	= 0;
							size_t nCharacterCount	= arrCharacters.GetCount();
							if (nCharacterCount == 0)
							{
								INT	iIndexContent	= GetNextInline(arrAlternates, -1);
								INT iIndexFootnote	= GetNextFootnote(arrFootnotes, -1);
								int indexAnchor = GetNextAnchor(anchors, -1);
								while (iIndexContent != -1)
								{
									arrItems.Add(arrAlternates[iIndexContent]);
									iIndexContent	= GetNextInline(arrAlternates, iIndexContent);
								}
								while (indexAnchor != -1)
								{
									anchors[indexAnchor]->InlinePosition((int) arrItems.GetCount());
									indexAnchor = GetNextAnchor(anchors, indexAnchor);
								}
								while (iIndexFootnote != -1)
								{
									arrItems.Add(arrFootnotes[iIndexFootnote]);
									iIndexFootnote	= GetNextFootnote(arrFootnotes, iIndexFootnote);
								}
								return;
							}

							// add bullet symbol
							if (pParagraph->m_pBulletProperties != NULL)
							{
								CBullet *pBullet	= CreateBullet(pParagraph->m_pBulletProperties, arrCharacters[nCharacterIndex], pGrapher);
								if (fabs(pParagraph->m_fTextIndent) > pBullet->GetRect().Width) {
									pBullet->GetRect().Width	= fabs(pParagraph->m_fTextIndent);
									if (pParagraph->m_fTextIndent < -pParagraph->m_fStartIndent)
										pParagraph->m_fTextIndent	= -pParagraph->m_fStartIndent;
								}
								arrItems.Add(pBullet);
								arrCharacters.InsertAt(nCharacterIndex, pBullet->GetCharacter());

								++nCharacterIndex;
								++nCharacterCount;
							}

							CCharacter *pCurrentCharacter	= arrCharacters[nCharacterIndex];
							size_t nMaxLength				= pCurrentCharacter->m_lCount;

							INT	iIndexInStr		= 0;
							INT	iIndexContent	= GetNextInline(arrAlternates, -1);
							int indexAnchor = GetNextAnchor(anchors, -1);
							INT iIndexFootnote	= GetNextFootnote(arrFootnotes, -1);

							// process text string
							CString strTextCopy	= strText;
							while (strTextCopy.GetLength() != 0)
							{
								// add inline alternate content to item array
								if (iIndexContent != -1)
								{
									while (iIndexInStr == arrAlternates[iIndexContent]->InlinePosition())
									{
										arrItems.Add(arrAlternates[iIndexContent]);
										iIndexContent	= GetNextInline(arrAlternates, iIndexContent);
										if (iIndexContent == -1)
											break;
									}
								}
								if (indexAnchor != -1)
								{
									while (iIndexInStr == anchors[indexAnchor]->InlinePosition())
									{
										anchors[indexAnchor]->InlinePosition((int) arrItems.GetCount());
										indexAnchor = GetNextAnchor(anchors, indexAnchor);
										if (indexAnchor == -1)
											break;
									}
								}
								if (iIndexFootnote != -1)
								{
									if (iIndexInStr == arrFootnotes[iIndexFootnote]->GetInilinePosition())
									{
										arrItems.Add(arrFootnotes[iIndexFootnote]);
										iIndexFootnote	= GetNextFootnote(arrFootnotes, iIndexFootnote);
									}
								}

								// get next syllable
								CSymbols *pSyllable	= GetNextSyllable(strTextCopy, nMaxLength, pParagraph, pCurrentCharacter, pGrapher);
								if (pSyllable != 0)
								{
									iIndexInStr	+= pSyllable->GetLength();

									arrItems.Add(pSyllable);
								}
								else
								{
									break;
								}

								// check is current character end
								if (nMaxLength == 0)
								{
									if (nCharacterIndex != nCharacterCount - 1)
									{
										++nCharacterIndex;

										pCurrentCharacter	= arrCharacters[nCharacterIndex];
										nMaxLength			= pCurrentCharacter->m_lCount;
									}
									else
									{
										break;
									}
								}
							}

							// add remaining alternate content
							while (iIndexContent != -1)
							{
								arrItems.Add(arrAlternates[iIndexContent]);
								iIndexContent	= GetNextInline(arrAlternates, iIndexContent);
							}
							while (indexAnchor != -1)
							{
								anchors[indexAnchor]->InlinePosition((int) arrItems.GetCount());
								indexAnchor = GetNextAnchor(anchors, indexAnchor);
							}
							while (iIndexFootnote != -1)
							{
								arrItems.Add(arrFootnotes[iIndexFootnote]);
								iIndexFootnote	= GetNextFootnote(arrFootnotes, iIndexFootnote);
							}
						}
						// ---
						INT		GetNextInline(CAtlArray<CAlternate2*> &arrAlternateContent, INT iPreviousIndex)
						{
							if (iPreviousIndex < (INT)arrAlternateContent.GetCount() - 1)
								return ++iPreviousIndex;
							else
								return	-1;
						}
						int		GetNextAnchor(CAtlArray<CAlternate2*>& anchors, const int& prevIndex)
						{
							if (prevIndex < (int)anchors.GetCount() - 1)
								return prevIndex + 1;
							else
								return	-1;
						}
						INT		GetNextFootnote(CAtlArray<CFootnote*> &arrFootnotes, INT iPreviousIndex)
						{
							if (iPreviousIndex < (INT)arrFootnotes.GetCount() - 1)
							{
								return ++iPreviousIndex;
							}
							else
							{
								return	-1;
							}
						}
						// ---
						REAL	GetPlcOrPxl(const REAL &iValue, const REAL &fHeight, const byte& nType = 0)
						{
							if (m_bIsFo == TRUE)
							{
								REAL fResult	= 0.0f;
								if (iValue >= 0)
								{
									fResult	= iValue;
								}
								else
								{
									fResult	= iValue * (-fHeight);
								}

								//*/
								if (nType == 1)
								{
									if (fResult < fHeight)
									{
										fResult	= fHeight;
									}
								}
								//*/

								return fResult;
							}
							else if (iValue < 0)
							{
								return ((-iValue)/100.0f)*fHeight;
							}
							else
							{
								return iValue*m_fMultiplierY;
							}
						}
					protected:
						CSymbols*	GetNextSyllable(CString &strText, size_t &nMaxCount, 
							CBlockAttributes *pParagraph, CCharacter *pCharacter, CGrapher* pGrapher)
						{
							int iMaxLength = (int)nMaxCount;
							if (iMaxLength <= 0)
								return NULL;
							//if (iMaxLength > 20)
							//	iMaxLength = 20;
							if (iMaxLength > strText.GetLength())
								iMaxLength = strText.GetLength();
							CSymbols *pSyllable = NULL;
							if (iMaxLength == 0)
								return pSyllable;
							int iIndex = 0;
							if (strText[(int)iIndex] == _T('\t'))
							{
								++iIndex;
								pSyllable = CreateTabStop(pCharacter, pGrapher);
							}
							else if (strText[(int)iIndex] == _T(' '))
							{
								for (iIndex = 1; iIndex < iMaxLength; ++iIndex)
									if (strText[(int)iIndex] != _T(' '))
										break;
								pSyllable = new CSpace(iIndex, pCharacter, pGrapher);
								((CSpace*)pSyllable)->SetOriginWidth();
							}
							else if (strText[(int)iIndex] == _T('\n'))
							{
								iIndex = 1;
								pSyllable = new CLineEnd(iIndex, pCharacter, pGrapher);
							}
							else
							{
								for (iIndex = 1; iIndex < iMaxLength; ++iIndex)
									if ((strText[(int)iIndex] == _T(' ')) || (strText[(int)iIndex] == _T('\n')) || (strText[(int)iIndex] == _T('\t')))
										break;
								CString strSyllableText = strText.Mid(0, (int)iIndex);
								pSyllable = new CSymbols(strSyllableText, pCharacter, pGrapher);
							}
							strText.Delete(0, (int)iIndex);
							nMaxCount -= iIndex;
							return pSyllable;
						}
						CBullet*	CreateBullet(CBulletProperties *pBulletProperties, CCharacter *pCharacter, CGrapher* pGrapher)
						{
							CCharacter *pBulletCharacter	= new CCharacter();						
							pBulletCharacter->m_lCount		= pBulletProperties->m_strChar.GetLength();
							pBulletCharacter->m_oAttributes = pCharacter->m_oAttributes;

							double dFontSize	= pBulletCharacter->m_oAttributes.m_oFont.m_oFont.Size;
							pBulletCharacter->m_oAttributes.m_oFont.m_oFont.Size = dFontSize * pBulletProperties->m_fSize;

							XmlUtils::CXmlNode oXmlBulletFontSettings;
							oXmlBulletFontSettings.FromXmlString(CString(_T("<Attributes font-underline=\"0\" font-strikeout=\"0\"/>")));

							pBulletCharacter->m_oAttributes.m_oFont.FromXmlNode(oXmlBulletFontSettings);

							CBullet *pBullet	= new CBullet(pBulletProperties->m_strChar, pBulletCharacter, pGrapher);

							return pBullet;
						}
						CTabStop*	CreateTabStop(CCharacter *pCharacter, CGrapher* pGrapher)
						{
							CCharacter *pTabStopCharacter		= new CCharacter();
							pTabStopCharacter->m_lCount			= 1;
							pTabStopCharacter->m_oAttributes	= pCharacter->m_oAttributes;

							XmlUtils::CXmlNode oXmlTabFontSettings;

							pTabStopCharacter->m_oAttributes.m_oFont.FromXmlNode(oXmlTabFontSettings);
							CTabStop *pTabStop	= new CTabStop(pTabStopCharacter, pGrapher);

							return pTabStop;
						}						
					};
					class CDocumentManager
					{
					private:
						int m_iPageCount;
						int	m_iCurrentPageNumber;
						int m_iBlocksCount;
						int m_iBlockIndex;

						bool	m_bStaticProcessing;

						CArray<CTabParams> m_arrTabs;
						float			m_fDefaultTabSize;
						float _lastTab;
						float			m_fLeftBorder;
						float			m_fRightBorder;
						bool			m_bTabReady;

						ListNumeration _listNum;
						PageNumeration _pageNum;

						float	m_fWidthMm;
						float	m_fHeightMm;

						CFontTable	m_FontTable;
						bool	m_UseHtmlSpacing;

						bool m_RendererHtml;

					public:
						CItemManager	m_ItemManager;
						CLinker			m_Linker;
						IAVSFontManager*	m_FontManager;
						ITextPainter*	m_TextPainter;

					public:
						CDocumentManager() 
							: m_iCurrentPageNumber(0), 
							m_iBlocksCount(0), m_iBlockIndex(0), 
							m_bStaticProcessing(false), 
							m_arrTabs(), m_fDefaultTabSize(0.0f), _lastTab(0),
							m_fLeftBorder(0.0f), m_fRightBorder(0.0f), m_bTabReady(false), 
							_listNum(), 
							m_fWidthMm(0.0f), m_fHeightMm(0.0f), 
							m_FontTable(), 
							m_UseHtmlSpacing(true), 
							m_ItemManager(), m_Linker(), 
							m_FontManager(NULL), m_TextPainter(NULL), 
							m_RendererHtml(false)
						{
						}
						
					public:
						void loadFromXml(XmlUtils::CXmlNode& docInfoXml) {
							XmlUtils::CXmlNode listNumSettingsXml;
							if (docInfoXml.GetNode(_T("listSettings"), listNumSettingsXml))
								_listNum.loadFromXml(listNumSettingsXml);

							XmlUtils::CXmlNode pageListNumSettingsXml;
							if (docInfoXml.GetNode(_T("pageNumSettings"), pageListNumSettingsXml))
								_pageNum.loadFromXml(pageListNumSettingsXml);
						}
						void	Clear()
						{
							m_iCurrentPageNumber	= 0;
							m_iBlocksCount			= 0;
							m_iBlockIndex			= 0;

							m_bStaticProcessing	= false;

							m_arrTabs.RemoveAll();
							m_fDefaultTabSize	= 0.0f;
							_lastTab = 0;
							m_fLeftBorder		= 0.0f;
							m_fRightBorder		= 0.0f;
							m_bTabReady			= false;

							_listNum.clear();
							_pageNum.clear();

							m_UseHtmlSpacing = true;
							m_Linker.Clear();

							m_TextPainter = NULL;

							m_RendererHtml = false;
						}

					public:
						void	BlockCreated()
						{
							if (m_bStaticProcessing)
								return;
							++m_iBlocksCount;
						}
						void	BlockProcessed()
						{
							if (m_bStaticProcessing)
								return;
							if (m_iBlocksCount > 0)
							{
								++m_iBlockIndex;
								if (m_iBlockIndex >= m_iBlocksCount - 2)
									m_iBlockIndex = m_iBlocksCount;
							}
						}
						void	SetStaticProcessing(const bool bSet)
						{
							m_bStaticProcessing	= bSet;
						}
						bool	GetStaticProcessing() const 
						{
							return m_bStaticProcessing;
						}
						float	GetCompleteness()
						{
							if (m_iBlocksCount != 0)
							{
								float fProgress = (float)m_iBlockIndex / m_iBlocksCount;
								if (fProgress >= 0.99f)
									fProgress = 0.99f;
								return fProgress;
							}
							else
								return 0.99f;
						}
					public:
						void	SetDefaultTab(const float& fDefaultTabSize, const float& fLeftBorder, const float& fRightBorder)
						{
							m_arrTabs.RemoveAll();

							if (fDefaultTabSize != 0)
								m_fDefaultTabSize = fDefaultTabSize;
							else
								m_fDefaultTabSize = 35.433f;
							
							_lastTab = fLeftBorder;
							m_fLeftBorder		= fLeftBorder;
							m_fRightBorder		= fRightBorder;
							m_bTabReady			= false;
						}
						void	AddTab(CTabParams& Tab)
						{
							m_arrTabs.Add(CTabParams(m_fLeftBorder + Tab.GetPosition(), Tab.GetLeader(), Tab.GetType()));
						}
						CTabParams	GetTabSize(const float& fCurrentPosition)
						{
							if (!m_bTabReady)
							{
								m_bTabReady = true;
								if (m_fDefaultTabSize != 0)
								{
									float fTabPosition = m_fLeftBorder;	

									int iCount = (int)m_arrTabs.GetCount();
									if (iCount)
									{
										_lastTab = m_arrTabs[iCount - 1].GetPosition();
										while (fTabPosition < _lastTab)
											fTabPosition += m_fDefaultTabSize;
									}
									
									while (fTabPosition < m_fRightBorder) {
										m_arrTabs.Add(CTabParams(fTabPosition, 0, 0));
										fTabPosition += m_fDefaultTabSize;
									}

									if (_lastTab < fTabPosition)
										_lastTab = fTabPosition;
									//m_arrTabs.Add(CTabParams(m_fRightBorder, 0, 0));
								}
							}
							/*/ feature : ïîäñ÷¸ò ðàçìåðà òàáóëÿöèè çà ïðåäåëàìè ðàçìåòêè ñòðàíèöû
							if (fCurrentPosition > _lastTab) {
								do {
									_lastTab += m_fDefaultTabSize;
									m_arrTabs.Add(CTabParams(_lastTab, 0, 0));
								} while (_lastTab < fCurrentPosition);
							}
							//*/
							for (size_t nIndex = 0; nIndex < m_arrTabs.GetCount(); ++nIndex) {
								if (fCurrentPosition < m_arrTabs[nIndex].GetPosition() 
									    || (fCurrentPosition == m_arrTabs[nIndex].GetPosition() && m_arrTabs[nIndex].GetType() == 2)) {
									return CTabParams(m_arrTabs[nIndex].GetPosition() - fCurrentPosition + 0.001, m_arrTabs[nIndex].GetLeader(), m_arrTabs[nIndex].GetType());
								}
							}

							if (fCurrentPosition <= m_fRightBorder) {
								return CTabParams(m_fRightBorder - fCurrentPosition - 0.001, 0, 0);
							}
							else
								return CTabParams();
						}
					public:
						CString	getListElement(const CString& id, const CString& numId, const int& level) {
							return _listNum.getElement(id, numId, level);
						}

					public:
						void setPageNumbering(const PageNumbering& numbering) {
							_pageNum.setNumbering(numbering);
						}
						void nextPage() {
							_pageNum.nextPage();
						}

						int getPageIndex() const {
							return _pageNum.getPageIndex();
						}
						CString getPageIndexString() const {
							return _pageNum.getPageIndexElement();
						}
						int getPageCount() const {
							return _pageNum.getPageCount();
						}
						CString getPageCountString() const {
							return _pageNum.getPageCountElement();
						}

					public:
						void	SetPage(const CPage& oPage)
						{
							m_fWidthMm = oPage.GetWidthMm();
							m_fHeightMm = oPage.GetHeightMm();
						}
						void	SetBorders(const CRegion& oRegion)
						{
							m_fLeftBorder  = oRegion.GetRectPt().GetLeft();
							m_fRightBorder = oRegion.GetRectPt().GetRight();
						}
						float	GetPageWidthMm()
						{
							return m_fWidthMm;
						}
						float	GetPageHeightMm()
						{
							return m_fHeightMm;
						}
						float	GetPageLeftBorderMm()
						{
							return m_fLeftBorder;
						}
						float	GetPageRightBorderMm()
						{
							return m_fRightBorder;
						}
					public:
						void	FontTableFromXml(XmlUtils::CXmlNode& fontTable)
						{
							m_FontTable.FromXml(fontTable, m_FontManager);
						}
						void	AddFont(const CFont& font, const CString& properties)
						{
							m_FontTable.AddFont(font, properties, m_FontManager);
						}
						CString	SetFont(const CFont& font)
						{
							return m_FontTable.SetFont(font, m_FontManager);
						}
						CString	GetFontName(const CFont& font)
						{
							return m_FontTable.GetName(font);
						}

					public:
						bool	UseHtmlSpacing()
						{
							return m_UseHtmlSpacing;
						}
						void	UseHtmlSpacing(const bool& useHtmlSpacing)
						{
							m_UseHtmlSpacing = useHtmlSpacing;
						}
					public:
						bool RendererHtml() const {
							return m_RendererHtml;
						}
						void RendererType(IAVSRenderer* renderer) {
							LONG rendererType;
							renderer->get_Type(&rendererType);
							if (rendererType == c_nHtmlRendrerer)
								m_RendererHtml = true;
							else
								m_RendererHtml = false;
						}
					};
					class CGrapher
					{
					private:
						class CFontMetrics
						{
						private:
							float	m_fLineSpacing;
							float	m_fEmHeight;
							float	m_fAscent;
							float	m_fDescent;

							float	m_fFontSize;

						public:
							CFontMetrics() : 
							  m_fLineSpacing(0), m_fEmHeight(0), 
								  m_fAscent(0), m_fDescent(0), 
								  m_fFontSize(0)
							  {
							  }
						public:
							void	FromFontManager(IAVSFontManager* m_pFontManager)
							{
								unsigned short iTemp = 0;
								m_pFontManager->GetCellAscent(&iTemp);
								m_fAscent = iTemp;
								m_pFontManager->GetCellDescent(&iTemp);
								m_fDescent = iTemp;
								m_pFontManager->GetLineSpacing(&iTemp);
								m_fLineSpacing = iTemp;
								m_pFontManager->GetEmHeight(&iTemp);
								m_fEmHeight = iTemp;
							}
							void	FontSize(const float& fFontSize)
							{
								m_fFontSize = fFontSize;
							}
						public:
							void	ApplyToRect(RectF& oRect)
							{
								oRect.X = 0;
								oRect.Height = m_fLineSpacing * m_fFontSize / m_fEmHeight;
								oRect.Y = m_fDescent * m_fFontSize / m_fEmHeight - oRect.Height;
							}
							float	GetDescent()
							{
								return (m_fDescent * m_fFontSize / m_fEmHeight);
							}
						};

					private:
						IAVSFontManager*	m_pFontManager;
						CFontMetrics	m_oFontMetrics;

						NSStructuresGDI::CFont m_oldFont;
						bool	m_FontSubstitute;

					public:
						CDocumentManager*	m_DocumentManager;

					public:
						CGrapher() : 
						  m_pFontManager(NULL), m_oFontMetrics(), 
							  m_oldFont(), m_FontSubstitute(false), 
							  m_DocumentManager(NULL)
						  {
							  m_oldFont.Size = -1;
						  }
						  ~CGrapher()
						  {
							  Clear();
						  }
						  void	Clear()
						  {
							  RELEASEINTERFACE(m_pFontManager);

							  m_oldFont.Size = -1;
							  m_DocumentManager = NULL;
						  }
					public:
						void	FontManager(IAVSFontManager* pFontManager)
						{
							RELEASEINTERFACE(m_pFontManager);
							m_pFontManager = pFontManager;
							ADDREFINTERFACE(m_pFontManager);
						}
						void	DocumentManager(CDocumentManager* documentManager)
						{
							assert(documentManager !=NULL);
							m_DocumentManager = documentManager;
						}
					public:
						float	GetDescent(CCharacter* pCharacter)
						{
							return m_oFontMetrics.GetDescent();
						}
						RectF	GetRectForString(const CString& strText, CCharacter *pCharacter)
						{
							SetFont(pCharacter);

							BSTR bstrText = strText.AllocSysString();
							m_pFontManager->LoadString(bstrText, 0, 0);
							SysFreeString(bstrText);

							RectF oRect;
							m_pFontManager->MeasureString2(&oRect.X, &oRect.Y, &oRect.Width, &oRect.Height);
							m_oFontMetrics.ApplyToRect(oRect);

							return oRect;
						}
						float*	GetWidths(const CString& text, CCharacter* character)
						{
							SetFont(character);

							int length = text.GetLength();
							float* widths	= new float[length];

							float temp = 0;
							float width = 0;
							float sumWidth = 0;
							for (int index = 0; index < length; ++index)
							{
								BSTR sysText = CString(text[index]).AllocSysString();
								m_pFontManager->LoadString(sysText, 0, 0);
								SysFreeString(sysText);
								m_pFontManager->MeasureString2(&temp, &temp, &width, &temp);
								widths[index] = width + sumWidth;
								sumWidth += width;
							}

							return widths;
						}
						double	GetStrikePosition(CCharacter	*m_pCharacter)
						{
							BOOL bAvailible; 
							m_pFontManager->IsCharAvailable(121, &bAvailible);
							if (bAvailible)
							{
								CString strText = _T("x");
								BSTR bstrText = strText.AllocSysString();
								m_pFontManager->LoadString(bstrText, 0, 0);
								SysFreeString(bstrText);

								RectF oRect;
								m_pFontManager->MeasureString(&oRect.X, &oRect.Y, &oRect.Width, &oRect.Height);
								float fFontSize = m_pCharacter->m_oAttributes.m_oFont.m_oFont.Size;
								double dStrike = fabs((double)(oRect.Y + oRect.Height / 2));
								return dStrike;
							}
							else
							{
								return 0;
							}
						}
						double	GetUnderlinePosition(CCharacter	*m_pCharacter, double& dSize)
						{
							float fX1, fY1, fX2, fY2, fSize; 
							m_pFontManager->GetUnderline(&fX1, &fY1, &fX2, &fY2, &fSize);
							float fFontSize = m_pCharacter->m_oAttributes.m_oFont.m_oFont.Size;
							double dUnderline = (double) (fY1);
							dSize = (double) fSize * 25.4 / 72.0 / 2.0;
							return dUnderline;						
						}
					public:
						static IAVSFontManager*	GenerateFontManager()
						{
							IAVSFontManager* pFontManager = NULL;
							CoCreateInstance(__uuidof(CAVSFontManager), NULL, CLSCTX_INPROC, __uuidof(IAVSFontManager), (void**)&pFontManager);
							pFontManager->Initialize(L"");

							CString strDefaultFontName = _T("Arial");
							BSTR bstrDefaultFontName = strDefaultFontName.AllocSysString();
							float fFontSize = 12;
							LONG iFontStyle = 0;
							pFontManager->SetDefaultFont(bstrDefaultFontName);
							SysFreeString(bstrDefaultFontName);

							return pFontManager;
						}
					private:
						void	SetFont(CCharacter *pCharacter)
						{
							assert(m_DocumentManager != NULL);
							NSStructuresGDI::CFont& oFont = pCharacter->m_oAttributes.m_oFont.m_oFont;

							if (!oFont.IsEqual(&m_oldFont))
							{
								m_FontSubstitute = false;
								m_oldFont = oFont;

								CString name = m_DocumentManager->SetFont(pCharacter->m_oAttributes.m_oFont);
								if (oFont.Name != name)
								{
									oFont.Name = m_DocumentManager->GetFontName(pCharacter->m_oAttributes.m_oFont);
									m_FontSubstitute = true;
								}

								m_oFontMetrics.FromFontManager(m_pFontManager);
								m_oFontMetrics.FontSize((float)oFont.Size);
							}
							else
							{
								if (m_FontSubstitute)
									oFont.Name = m_DocumentManager->GetFontName(pCharacter->m_oAttributes.m_oFont);
							}

							m_pFontManager->SetCharSpacing(oFont.CharSpace * (72.0f / 25.4f));
						}
					};

					class CAreaManager
					{
					private:
						CWrapRegion	m_oWrapRegion;
						bool		m_bHasWrap;

					public:
						CAreaManager()
							: m_oWrapRegion(), m_bHasWrap(false) 
						{
						}
						~CAreaManager()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							m_oWrapRegion.RemoveAll();
							m_bHasWrap	= false;
						}
					public:
						void	AddWrapPolygon(const CArray<PointF>& arrPoints, const REAL& fDistanceLeft, const REAL& fDistanceRight)
						{
							if (arrPoints.GetCount() == 0)
								return;
							m_bHasWrap	= true;

							CWrapPolygon oWrapPolygon;
							oWrapPolygon.SetPoints(arrPoints);
							m_oWrapRegion.Add(oWrapPolygon, fDistanceLeft, fDistanceRight);
						}
						REAL	GetArea(const RectF& oLineRect, CArray<RectF>& arrRects)
						{
							if (m_bHasWrap)
							{
								m_oWrapRegion.Calculate(oLineRect, arrRects);

								return 0;
							}
							else
							{
								arrRects.RemoveAll();
								arrRects.Add(oLineRect);

								return -1;
							}
						}					
					};

					// ### ### ###
					class CItem
					{
					protected:
						RectF	m_oRect;
						REAL	m_fDescent;

					public:
						CItem() : 
						  m_oRect(), m_fDescent(0.0f)
						  {
						  }
						  virtual ~CItem()
						  {
							  Clear();
						  }
						  void	Clear()
						  {
							  m_oRect	= RectF();
							  m_fDescent	= 0.0f;
						  }
					public:
						virtual RectF&	GetRect()
						{
							return m_oRect;
						}
						virtual REAL	GetHeightPt()
						{
							return m_oRect.Height;
						}
						virtual REAL	GetWidthPt()
						{
							return m_oRect.Width;
						}
						virtual REAL	GetDescent()
						{
							return m_fDescent;
						}
						virtual void	RestoreRect()
						{
							m_oRect.X	= 0.0f;
							m_oRect.Y	= -m_oRect.Height + m_fDescent;
						}
						virtual CItemType	GetType()
						{
							return None;
						}
					public:
						virtual bool	IsOneSymbol()
						{
							return false;
						}
						virtual bool	CanRupture()
						{
							return false;
						}
						virtual bool	CanRupture(CGrapher* grapher, const float& maxWidth)
						{
							return false;
						}
						virtual CItem*	Rupture(const float& maxWidth, CGrapher* grapher, const bool& bySymbol = false
							, const bool& firstSymbolAlways = false)
						{
							return NULL;
						}
						virtual void SetOnBaseline(const bool& inited = true) {
							if (inited)
								MoveTo(0, m_fDescent - m_oRect.Height);
							else
								MoveTo(m_oRect.X, m_fDescent - m_oRect.Height);
						}
						virtual void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const float &fCompleteness) = 0;
						virtual void	MoveTo(const REAL &fNewX)
						{
							m_oRect.X	= fNewX;
						}
						virtual void	MoveTo(const REAL &fNewX, const REAL &fNewY)
						{
							m_oRect.X	= fNewX;
							m_oRect.Y	= fNewY;
						}
						virtual void	MoveOn(const REAL &fDeltaX, const REAL &fDeltaY)
						{
							m_oRect.X	+= fDeltaX;
							m_oRect.Y	+= fDeltaY;
						}
					public:
						static void drawRect(IAVSRenderer* renderer, RectF rect) {
							static const float ptToMm = 25.4f / 72.0f;
							rect.X *= ptToMm;
							rect.Y *= ptToMm;
							rect.Width *= ptToMm;
							rect.Height *= ptToMm;

							renderer->put_PenColor(0x0000ff);
							renderer->put_PenSize(0.1);
							renderer->put_PenAlpha(255);
							renderer->BeginCommand(c_nPathType);
							renderer->BeginCommand(c_nTextGraphicType);
							renderer->PathCommandStart();
							renderer->PathCommandMoveTo(rect.X, rect.Y);
							renderer->PathCommandLineTo(rect.X + rect.Width, rect.Y);
							renderer->PathCommandLineTo(rect.X + rect.Width, rect.Y + rect.Height);
							renderer->PathCommandLineTo(rect.X, rect.Y + rect.Height);
							renderer->PathCommandClose();
							renderer->DrawPath(0x01);
							renderer->PathCommandEnd();
							renderer->EndCommand(c_nPathType);
							renderer->EndCommand(c_nTextGraphicType);
						}
					};

					class CSymbols : public CItem
					{
					protected:
						CString		m_strText;

						CCharacter	*m_pCharacter;

					public:
						double		m_size;
						double		m_underlinePosition;	
						double		m_strikePosition;

					public:
						CSymbols() 
							: CItem(), 
							m_strText(_T("")), 
							m_pCharacter(NULL)
						{
						}
						CSymbols(CCharacter* pCharacter)
							: CItem(), 
							m_strText(_T("")), 
							m_pCharacter(pCharacter)
						{
						}
						CSymbols(const CString &strText, CCharacter* pCharacter, CGrapher* pGrapher)
							: CItem(), 
							m_strText(strText), 
							m_pCharacter(pCharacter)
						{
							m_oRect		= pGrapher->GetRectForString(m_strText, pCharacter);							
							m_fDescent	= pGrapher->GetDescent(pCharacter);
							SetOnBaseline();

							m_strikePosition	= GetStrikePosition(pGrapher);
							m_underlinePosition = GetUnderlinePosition(pGrapher, m_size);
						}
					public:
						CCharacter*	GetCharacter()
						{
							return m_pCharacter;
						}
						int			GetLength()
						{
							return m_strText.GetLength();
						}
						inline CItemType	GetType()
						{
							return Symbols;
						}						
						double	GetStrikePosition( CGrapher* pGrapher)
						{
							double dPos = pGrapher->GetStrikePosition(m_pCharacter);
							if (dPos != 0)
								m_strikePosition = dPos;
							else 
								m_strikePosition = GetDescent();
							return dPos;
						}
						double	GetUnderlinePosition( CGrapher* pGrapher, double& dSize)
						{
							double dPos = pGrapher->GetUnderlinePosition(m_pCharacter, dSize);
							return dPos;
						}
						bool	CanRupture()
						{
							return (m_strText.FindOneOf(_T("-")) != -1);
						}
						bool	CanRupture(CGrapher* grapher, const float& maxWidth)
						{
							if (m_strText.GetLength() == 0)
								return false;

							float* firstSymbolWidth = grapher->GetWidths((CString) m_strText[0], m_pCharacter);
							bool canRupture = false;
							if (firstSymbolWidth[0] <= maxWidth)
								canRupture = true;

							return canRupture;
						}
					public:
						bool	IsOneSymbol()
						{
							return (m_strText.GetLength() == 1);
						}
						CItem*	Rupture(const float& maxWidth, CGrapher* grapher, const bool& bySymbol = false
							, const bool& firstSymbolAlways = false)
						{
							float* widths = grapher->GetWidths(m_strText, m_pCharacter);

							int length = m_strText.GetLength();
							int lastSuitItem = -1;

							CArray<int> rupPositions;
							RupturePositions(rupPositions);
							int rupPositionsCount = (int)rupPositions.GetCount();
							if (rupPositionsCount > 0)
							{
								int rupPos = rupPositionsCount - 1;
								while (rupPos >= 0)
									if (widths[rupPositions[rupPos]] > maxWidth)
										--rupPos;
									else
										break;
								if (rupPos >= 0)
									lastSuitItem = rupPositions[rupPos];
							}

							if (lastSuitItem < 0 && bySymbol)
							{
								lastSuitItem = length - 1;
								while (lastSuitItem >= 0)
									if (widths[lastSuitItem] > maxWidth)
										--lastSuitItem;
									else
										break;
							}

							RELEASEARRAYOBJECTS(widths);

							if (lastSuitItem == -1 && firstSymbolAlways)
								++lastSuitItem;

							CSymbols* newItem = NULL;
							if (lastSuitItem >= 0)
							{
								CString newItemText = m_strText.Mid(0, lastSuitItem + 1);
								m_strText.Delete(0, lastSuitItem + 1);

								newItem = new CSymbols(newItemText, m_pCharacter, grapher);

								m_oRect = grapher->GetRectForString(m_strText, m_pCharacter);
								m_oRect.Y = newItem->m_oRect.Y;
							}
							return newItem;
						}
						void	SetOnBaseline(const bool& bIsInit = true)
						{
							if (bIsInit)
							{
								MoveTo(0, m_fDescent - m_oRect.Height);
							}
							else
							{
								MoveTo(m_oRect.X, m_fDescent - m_oRect.Height);
							}

							if (m_pCharacter->m_oAttributes.m_nBaselineShift == 1)
							{
								MoveOn(0, -2 * m_fDescent);
							}
							else if (m_pCharacter->m_oAttributes.m_nBaselineShift == 2)
							{
								MoveOn(0, m_fDescent);
							}
							else if (m_pCharacter->m_oAttributes.m_fBaselineShift != 0)
							{
								MoveOn(0, -m_pCharacter->m_oAttributes.m_fBaselineShift);
							}
						}
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const float &fCompleteness)
						{
							if (m_oRect.Width == 0)
								return;

							if (m_pCharacter->m_oLink.strTarget != _T(""))
								documentManager.m_Linker.AddSource(m_pCharacter->m_oLink.strTarget, m_oRect, documentManager);

							BSTR bstrText	= m_strText.AllocSysString();

							m_pCharacter->m_oAttributes.m_oFont.SetToRenderer(pRenderer);
							m_pCharacter->m_oAttributes.m_oBrush.SetToRenderer(pRenderer, fCompleteness);
							m_pCharacter->m_oAttributes.m_oShadow.SetToRenderer(pRenderer);
							m_pCharacter->m_oAttributes.m_oEdge.SetToRenderer(pRenderer);

							sendBaselineShiftToRenderer(pRenderer);

							#ifdef TME_TEXT_BLACK
							pRenderer->put_BrushColor1(0xff000000);
							#endif

							const float fPtToMm	= 25.4f / 72.0f;

							if (m_pCharacter->getIsLabel())
								pRenderer->BeginCommand(c_nNumberingMarker);

							if (NULL == documentManager.m_TextPainter)
								pRenderer->CommandDrawText(bstrText, m_oRect.X * fPtToMm, m_oRect.Y * fPtToMm, m_oRect.Width * fPtToMm, m_oRect.Height * fPtToMm, (m_oRect.Height - m_fDescent) * fPtToMm);
							else
								documentManager.m_TextPainter->CommandText(bstrText, m_oRect.X * fPtToMm, m_oRect.Y * fPtToMm, m_oRect.Width * fPtToMm, m_oRect.Height * fPtToMm, (m_oRect.Height - m_fDescent) * fPtToMm, pRenderer);
							SysFreeString(bstrText);
							if (m_pCharacter->getIsLabel())
								pRenderer->EndCommand(c_nNumberingMarker);

							#ifdef TME_DRAW_SYMBOL_BORDER
							CItem::drawRect(pRenderer, m_oRect);
							#endif
						}						
					private:
						void	RupturePositions(CArray<int>& rupturePositions)
						{
							CString rupSymbols = _T("-");

							int index = 0;
							int length = m_strText.GetLength();
							while (index < length)
							{
								if (rupSymbols.Find(m_strText[index]) != -1)
									rupturePositions.Add(index);
								++index;
							}
						}
					private:
						void sendBaselineShiftToRenderer(IAVSRenderer* renderer) {
							IAVSRenderer2* renderer2 = NULL;
							if (SUCCEEDED(renderer->QueryInterface(__UUIDOF__IAVSRENDERER2, (void**)&renderer2)) && (NULL != renderer2)) {
								byte baselineShiftPos = m_pCharacter->m_oAttributes.m_nBaselineShift;
								float baselineShift = m_pCharacter->m_oAttributes.m_fBaselineShift;

								if (baselineShiftPos != 0)
									renderer2->CommandLong2(c_nBaselineShift, baselineShiftPos);
								else if (baselineShift != 0) {
									if (baselineShift > 0)
										renderer2->CommandLong2(c_nBaselineShift, 1);
									else
										renderer2->CommandLong2(c_nBaselineShift, 2);
								}
							}
						}
					};

					class CSpace : public CSymbols
					{
					private:
						double m_originWidth;

					public:
						CSpace() 
							: CSymbols()
						{
							m_originWidth = 0;
						}
						CSpace(const size_t &nCount, CCharacter* pCharacter, CGrapher* pGrapher)
							: CSymbols()
						{
							m_strText	= _T("");
							for (size_t i = 0; i < nCount; ++i)
							{
								m_strText	+= _T(" ");
							}

							m_pCharacter	= pCharacter;

							m_oRect		= pGrapher->GetRectForString(m_strText, pCharacter);
							m_fDescent	= pGrapher->GetDescent(pCharacter);

							m_strikePosition	= GetStrikePosition(pGrapher);
							m_underlinePosition = GetUnderlinePosition(pGrapher, m_size);

							SetOnBaseline();
						}
					public:
						inline CItemType	GetType()
						{
							return Space;
						}
						void	RestoreRect()
						{
							m_oRect.X	= 0.0f;
							m_oRect.Y	= -m_oRect.Height + m_fDescent;
							m_originWidth;

							m_oRect.Width = m_originWidth;
						}
						void   SetOriginWidth()
						{
							m_originWidth = m_oRect.Width;
						}
					public:
						CItem*	Rupture(const float& maxWidth, CGrapher* grapher, const bool& bySymbol = false
							, const bool& firstSymbolAlways = false)
						{
							CItem* newItem = CSymbols::Rupture(maxWidth, grapher, bySymbol, firstSymbolAlways);
							if (newItem != NULL)
							{
								CSymbols* symbolsItem = (CSymbols*) newItem;
								int length = (int) symbolsItem->GetLength();
								CCharacter* character = symbolsItem->GetCharacter();
								CSpace* spaceItem = new CSpace(length, character, grapher);
								RELEASEOBJECT(newItem);
								return spaceItem;
							}
							else
								return newItem;
						}
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const float &fCompleteness)
						{
						}
					};

					class CLineEnd : public CSymbols
					{
					public:
						CLineEnd() 
							: CSymbols()
						{
						}
						CLineEnd(const size_t &nCount, CCharacter *pCharacter, CGrapher* pGrapher)
							: CSymbols()
						{
							m_strText	= _T("");
							for (size_t i = 0; i < nCount; ++i)
							{
								m_strText	+= _T("\n");
							}

							m_pCharacter	= pCharacter;

							m_oRect		= pGrapher->GetRectForString(m_strText, pCharacter);
							m_fDescent	= pGrapher->GetDescent(pCharacter);

							SetOnBaseline();

							m_oRect.Width	= 0.0f;
						}
					public:
						inline CItemType	GetType()
						{
							return LineEnd;
						}
					public:
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const float &fCompleteness)
						{
						}
					};

					class CBullet : public CSymbols
					{
					public:
						CBullet() 
							: CSymbols()
						{
							m_pCharacter->setIsLabel(true);
						}
						CBullet(const CString &strBullet, CCharacter *pCharacter, CGrapher* pGrapher)
							: CSymbols(strBullet, pCharacter, pGrapher)
						{
							m_strikePosition	= GetStrikePosition(pGrapher);
							m_underlinePosition = GetUnderlinePosition(pGrapher, m_size);

							m_pCharacter->setIsLabel(true);
						}
						~CBullet()
						{
						}
					public:
						inline CItemType	GetType()
						{
							return Bullet;
						}
					};

					class CTabStop : public CSymbols
					{
					public:
						byte m_bType;
						byte m_bLeader;

					public:
						CTabStop() 
							: CSymbols()
						{
						}
						CTabStop(CCharacter *pCharacter, CGrapher* pGrapher)
						{
							m_strText = _T("x");
							m_pCharacter = pCharacter;

							m_oRect		= pGrapher->GetRectForString(m_strText, pCharacter);
							m_fDescent	= pGrapher->GetDescent(pCharacter);

							m_strikePosition	= GetStrikePosition(pGrapher);
							m_underlinePosition = GetUnderlinePosition(pGrapher, m_size);

							SetOnBaseline();
						}
					public:
						inline CItemType	GetType()
						{
							return TabStop;
						}
					public:
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const float& completeness) {
							#ifdef TME_SHOW_TABS
							CSymbols::Draw(pRenderer, documentManager, completeness);
							#endif

							const float fPtToMm	= 25.4f / 72.0f;
							if (m_bLeader != 0 && (m_bLeader == 1 || m_bLeader == 2 || m_bLeader == 3))
							{
								double lineY;
								if (m_bLeader == 1)
								{
									lineY = GetRect().GetBottom() - GetDescent();
									pRenderer->put_PenSize(2 * m_size);
									pRenderer->put_PenDashStyle(Aggplus::DashStyleCustom);

									SAFEARRAYBOUND rgsab;
									rgsab.lLbound	= 0;
									rgsab.cElements	= 2;

									SAFEARRAY* pArray = SafeArrayCreate(VT_R8, 1, &rgsab);

									double* pData = (double*)pArray->pvData;
									pData[0] = 1;
									pData[1] = 2;

									pRenderer->PenDashPattern(pArray);

									RELEASEARRAY(pArray);
								}
								else if (m_bLeader == 2)
								{
									lineY = GetRect().GetBottom() - GetDescent() - m_strikePosition;
									pRenderer->put_PenSize(m_size);
									pRenderer->put_PenDashStyle(Aggplus::DashStyleCustom);

									SAFEARRAYBOUND rgsab;
									rgsab.lLbound	= 0;
									rgsab.cElements	= 2;

									SAFEARRAY* pArray = SafeArrayCreate(VT_R8, 1, &rgsab);

									double* pData = (double*)pArray->pvData;
									pData[0] = 2;
									pData[1] = 2;

									pRenderer->PenDashPattern(pArray);

									RELEASEARRAY(pArray);

								}
								else if (m_bLeader == 3)
								{
									lineY = GetRect().GetBottom() - GetDescent() + m_underlinePosition / 2;
									pRenderer->put_PenSize(m_size);
									pRenderer->put_PenDashStyle(Aggplus::DashStyleCustom);

									SAFEARRAYBOUND rgsab;
									rgsab.lLbound	= 0;
									rgsab.cElements	= 2;

									SAFEARRAY* pArray = SafeArrayCreate(VT_R8, 1, &rgsab);

									double* pData = (double*)pArray->pvData;
									pData[0] = 5;
									pData[1] = 1;

									pRenderer->PenDashPattern(pArray);

									RELEASEARRAY(pArray);
								}
								if ((GetRect().GetRight() - GetRect().GetLeft()) * fPtToMm > 10)
								{
									pRenderer->put_PenColor(GetCharacter()->m_oAttributes.m_oBrush.m_oBrush.Color1);
									pRenderer->BeginCommand(c_nPathType);
									//pRenderer->BeginCommand(c_nTextGraphicType);
									pRenderer->PathCommandStart();
									pRenderer->PathCommandMoveTo(GetRect().GetLeft() * fPtToMm + 1, lineY * fPtToMm);
									pRenderer->PathCommandLineTo(GetRect().GetRight() * fPtToMm, lineY * fPtToMm);
									pRenderer->DrawPath(c_nStroke);
									pRenderer->PathCommandEnd();
									//pRenderer->EndCommand(c_nTextGraphicType);
									pRenderer->EndCommand(c_nPathType);
								}
							}
						}
					};

					class CRect
					{
					private:
						RectF  m_rect;
						long   m_color;
						byte   m_underline;
						byte   m_alpha;

					public:
						CRect()
							: m_rect(),
							m_color(0xFFFFFF),
							m_underline()
						{
						}
						CRect(RectF rect, long color, byte alpha,byte underline)
							: m_rect(rect),
							m_color(color),
							m_alpha(alpha),
							m_underline(underline)
						{
						}
						CRect(RectF rect, long color)
							: m_rect(rect),
							m_color(color),
							m_underline()
						{
						}

						double GetLeft()
						{
							return m_rect.GetLeft();
						}
						double GetRight()
						{
							return m_rect.GetRight();
						}
						double GetTop()
						{
							return m_rect.GetTop();
						}
						double GetBottom()
						{
							return m_rect.GetBottom();
						}
						long GetColor()
						{
							return m_color;
						}
						byte GetAlpha()
						{
							return m_alpha;
						}
						byte GetUnderline()
						{
							return m_underline;
						}
					};

					class CWord : public CItem {
					protected:
						CAtlArray<CItem*>	m_arrItems;
						size_t				m_nItemsCount;

						float _originDescent;

					public:
						CWord() 
							: CItem(), 
							m_nItemsCount(0), 
							_originDescent(0) {
						}
						~CWord() {
							Clear();
						}
						void Clear() {
							for (size_t nIndex = 0; nIndex < m_nItemsCount; ++nIndex)
							{
								RELEASEOBJECT(m_arrItems[nIndex]);
							}
							m_arrItems.RemoveAll();
							m_nItemsCount = 0;

							_originDescent = 0;
						}
					public:
						void RemoveAllItems()
						{
							m_arrItems.RemoveAll();
							m_nItemsCount	= 0;
						}
						inline CItemType	GetType()
						{
							return Word;
						}

						inline float getOriginDescent() const {
							return _originDescent;
						}
					public:
						void	AddItem(CItem *pItem)
						{
							pItem->MoveTo(m_oRect.X + m_oRect.Width, pItem->GetRect().Y);
							m_oRect.Width	+= pItem->GetRect().Width;

							updateAscent(pItem);
							updateDescent(pItem);

							m_fDescent	= m_oRect.GetBottom();

							m_arrItems.Add(pItem);
							++m_nItemsCount;
						}

					private:
						void updateAscent(CItem* item) {
							float itemAscent = item->GetHeightPt() - item->GetDescent();

							float itemTop = item->GetRect().GetTop();
							if (itemTop > -itemAscent)
								itemTop = -itemAscent;
							float lineTop = m_oRect.GetTop();

							if (lineTop > itemTop) {
								m_oRect.Height += lineTop - itemTop;
								m_oRect.Y = itemTop;
							}
						}
						void updateDescent(CItem* item) {
							float itemDescent = item->GetDescent();
							if (itemDescent > _originDescent)
								_originDescent = itemDescent;
							
							float itemBottom = item->GetRect().GetBottom();
							if (itemBottom < itemDescent)
								itemBottom = itemDescent;

							if (m_oRect.GetBottom() < itemBottom)
								m_oRect.Height	= itemBottom - m_oRect.GetTop();
						}

					public:
						size_t	GetItemsCount()
						{
							return m_nItemsCount;
						}
						void	RearrangeItems()
						{
							REAL fCurrentX	= m_oRect.X;
							for (size_t nIndex = 0; nIndex < m_nItemsCount; ++nIndex)
							{
								CItem *pItem	= m_arrItems[nIndex];
								pItem->MoveTo(fCurrentX);
								fCurrentX		+= pItem->GetRect().Width;
							}
						}
						CWord*	Rupture(REAL &fPersistWidth, CGrapher* pGrapher)
						{
							REAL fCurrentWidth	= 0;							
							CItem *pItem		= NULL;

							size_t nItemIndex	= 0;
							for (; nItemIndex < m_nItemsCount; ++nItemIndex)
							{
								pItem	= m_arrItems[nItemIndex];
								if (fCurrentWidth + pItem->GetRect().Width > fPersistWidth)
								{
									break;
								}
								fCurrentWidth	+= pItem->GetRect().Width;
							}

							CWord *pNewWord	= new CWord();
							for (size_t nIndex = 0; nIndex < nItemIndex; ++nIndex)
							{
								pNewWord->AddItem(m_arrItems[nIndex]);
							}

							m_arrItems.RemoveAt(0, nItemIndex);
							m_nItemsCount	-= nItemIndex;

							fPersistWidth	-= fCurrentWidth;

							CItem *pNewItem = pItem->Rupture(fPersistWidth, pGrapher);
							if (pNewItem != NULL)
							{
								pNewWord->AddItem(pNewItem);
							}

							if (pNewWord->m_nItemsCount != 0)
							{
								m_oRect.Width	-= pNewWord->m_oRect.Width;

								RearrangeItems();
							}
							else
							{
								RELEASEOBJECT(pNewWord);
							}

							return pNewWord;
						}
					public:
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const float &fCompleteness)
						{
							RectF underlineRect;
							RectF shadingRect;
							RectF strikeRect;
							double descent = 0;							
							double dSizeUnderline = 0.25;
							double dSizeStrike = 0.25;
							const float fPtToMm	= 25.4f / 72.0f;
							CAtlArray<CRect> arrShadings;
							CAtlArray<CRect> arrUnderlines;


							for (size_t nIndex = 0; nIndex < m_nItemsCount; ++nIndex)
							{								
#ifdef _DEBUG
								CItemType p = m_arrItems[nIndex]->GetType();
#endif

								if (m_arrItems[nIndex]->GetType() != Word && m_arrItems[nIndex]->GetType() != Alternate &&
									m_arrItems[nIndex]->GetType() != Footnote)
								{
									CSymbols* item = (CSymbols*)m_arrItems[nIndex];

									//SHADING
									if (item->GetCharacter()->m_oAttributes.m_oBackground.m_oBackground.Alpha)
									{
										if (IsLastInEquallyShading(nIndex - 1))
										{
											shadingRect.X = item->GetRect().GetLeft();
											shadingRect.Y = item->GetRect().GetTop();
										}

										shadingRect.Width += item->GetWidthPt();

										if (IsLastInEquallyShading(nIndex))
										{
											long color = item->GetCharacter()->m_oAttributes.m_oBackground.m_oBackground.Color;
											arrShadings.Add(CRect(RectF(shadingRect.X * fPtToMm, shadingRect.Y * fPtToMm, shadingRect.Width * fPtToMm, shadingRect.Height * fPtToMm), color));

											shadingRect.Width  = 0;
										}
									}
								}
							}
							//drawShading
							for(size_t nIndex = 0; nIndex < arrShadings.GetCount(); ++nIndex)
							{
								CRect rect = arrShadings[nIndex];
								DrawShading(pRenderer, rect.GetLeft(), GetRect().GetTop() * fPtToMm, rect.GetRight() - rect.GetLeft(), GetRect().Height * fPtToMm, rect.GetColor());
								//DrawShading(pRenderer, rect.GetLeft(), (shadingRect.Y + descent - shadingRect.Height) * fPtToMm, rect.GetRight() - rect.GetLeft(), shadingRect.Height * fPtToMm, rect.GetColor());
							}

							for(size_t nIndex = 0; nIndex < m_nItemsCount; ++nIndex)
							{
#ifdef AVS_LOG_DEBUG
								CItemType p = m_arrItems[nIndex]->GetType();
#endif
								if (m_arrItems[nIndex]->GetType() != Word && m_arrItems[nIndex]->GetType() != Alternate && m_arrItems[nIndex]->GetType() != Footnote)
								{
									CSymbols* item = (CSymbols*)m_arrItems[nIndex];									
									CTextAttributes textAttrs = item->GetCharacter()->m_oAttributes;

									//item->m_strikePosition	= item->GetStrikePosition(pGrapher);
									//item->m_underlinePosition = item->GetUnderlinePosition(pGrapher, item->m_size);

									double dHeightLine = item->GetHeightPt();
									//STRIKE
									if (textAttrs.m_oFont.m_oFont.Strikeout != 0)
									{

										strikeRect.Width = item->GetWidthPt();
										dSizeStrike = item->m_size;

										strikeRect.X = item->GetRect().GetLeft();
										if (item->m_strikePosition != 0)
											strikeRect.Y = item->GetRect().GetBottom() - item->GetDescent() - item->m_strikePosition;
										else
											strikeRect.Y = item->GetRect().GetBottom() - 2 * item->GetDescent();

										DrawStrike(pRenderer, strikeRect.X * fPtToMm,
											strikeRect.Y * fPtToMm,
											(strikeRect.X + strikeRect.Width)  * fPtToMm,
											strikeRect.Y  * fPtToMm,
											textAttrs.m_oBrush.m_oBrush.Color1,
											textAttrs.m_oBrush.m_oBrush.Alpha1,
											textAttrs.m_oFont.m_oFont.Strikeout, 
											dSizeStrike);
									}

									//UNDERLINE
									if (textAttrs.m_oFont.m_oFont.Underline != 0)
									{
										/*if (textAttrs.m_oFont.m_oFont.Strikeout == 0)
										;item->m_underlinePosition = item->GetUnderlinePosition(pGrapher, item->m_size);*/

										if (dHeightLine > underlineRect.Height)
											underlineRect.Height = dHeightLine;

										if (IsLastInEquallyUnder(nIndex - 1))
										{
											underlineRect.X = item->GetRect().GetLeft();
											underlineRect.Y = 0;
											underlineRect.Width  = 0;
											underlineRect.Height = 0;
											dSizeUnderline = 0;										
										}
										double size  = item->m_size;//dHeightLine / 50;
										double width = item->GetWidthPt();
										double dUnderlinePos = item->m_underlinePosition / 2 * fPtToMm  + item->GetRect().GetBottom() * fPtToMm - item->GetDescent() * fPtToMm;	

										if ((underlineRect.Width + width) != 0 )
										{
											dSizeUnderline  = (width * size + underlineRect.Width * dSizeUnderline) / (underlineRect.Width + width);
											underlineRect.Y = (width * dUnderlinePos + underlineRect.Width * underlineRect.Y) / (underlineRect.Width + width);
										}

										underlineRect.Width  += width;

										if (IsLastInEquallyUnder(nIndex))
										{										
											arrUnderlines.Add(CRect(RectF(underlineRect.X * fPtToMm, underlineRect.Y * fPtToMm, underlineRect.Width * fPtToMm, 0), textAttrs.m_oBrush.m_oBrush.Color1, textAttrs.m_oBrush.m_oBrush.Alpha1, textAttrs.m_oFont.m_oFont.Underline));

											underlineRect.Width  = 0;
											if (IsLastInEquallyTypeUnder(nIndex) && nIndex != m_nItemsCount - 1)
											{
												for(size_t nIndex = 0; nIndex < arrUnderlines.GetCount(); ++nIndex)
												{
													CRect rect = arrUnderlines[nIndex];
													DrawUnderline(pRenderer, rect.GetLeft(), 
														(underlineRect.Y),
														rect.GetRight(),
														(underlineRect.Y),												 
														rect.GetColor(),
														rect.GetAlpha(),
														rect.GetUnderline(), 
														dSizeUnderline);												
												}

												arrUnderlines.RemoveAll();
												underlineRect.Height = 0;
												dSizeUnderline = 0;
											}
										}
									}
								}

								m_arrItems[nIndex]->Draw(pRenderer, documentManager, fCompleteness);
							}

							//drawUnderline
							for(size_t nIndex = 0; nIndex < arrUnderlines.GetCount(); ++nIndex)
							{
								CRect rect = arrUnderlines[nIndex];
								DrawUnderline(pRenderer, rect.GetLeft(), 
									(underlineRect.Y), 
									rect.GetRight(),
									(underlineRect.Y), 														 
									rect.GetColor(), 
									rect.GetAlpha(),
									rect.GetUnderline(),
									dSizeUnderline);								
							}
						}
					public:
						bool	IsLastInEquallyUnder(size_t num)
						{
							if (num == m_nItemsCount - 1 || num == -1)
								return true;
							CItemType type1 = m_arrItems[num]->GetType();
							CItemType type2 = m_arrItems[num + 1]->GetType();
							if (type1 == Word || type2 == Word ||
								type1 == Alternate || type2 == Alternate ||
								type1 == Footnote || type2 == Footnote)
								return true;
							CTextAttributes cur  = ((CSymbols*)m_arrItems[num])->GetCharacter()->m_oAttributes;
							CTextAttributes next = ((CSymbols*)m_arrItems[num + 1])->GetCharacter()->m_oAttributes;
							byte under1 = cur.m_oFont.m_oFont.Underline;
							byte under2 = next.m_oFont.m_oFont.Underline;
							long color1 = cur.m_oBrush.m_oBrush.Color1;
							long color2 = next.m_oBrush.m_oBrush.Color1;

							if ((under1 == under2) != 0 && color1 == color2)
								return false;
							else
								return true;								
						}
						bool	IsLastInEquallyTypeUnder(size_t num)
						{
							if (num == m_nItemsCount - 1 || num == -1)
								return true;
							CItemType type1 = m_arrItems[num]->GetType();
							CItemType type2 = m_arrItems[num + 1]->GetType();
							if (type1 == Word || type2 == Word ||
								type1 == Alternate || type2 == Alternate ||
								type1 == Footnote || type2 == Footnote)
								return true;
							CTextAttributes cur  = ((CSymbols*)m_arrItems[num])->GetCharacter()->m_oAttributes;
							CTextAttributes next = ((CSymbols*)m_arrItems[num + 1])->GetCharacter()->m_oAttributes;
							byte under1 = cur.m_oFont.m_oFont.Underline;
							byte under2 = next.m_oFont.m_oFont.Underline;

							if ((under1 == under2) != 0)
								return false;
							else
								return true;								
						}
						bool	IsLastInEquallyShading(size_t num)
						{
							if (num == m_nItemsCount - 1 || num == -1)
								return true;
							CItemType type1 = m_arrItems[num]->GetType();
							CItemType type2 = m_arrItems[num + 1]->GetType();
							if (type1 == Word || type2 == Word ||
								type1 == Alternate || type2 == Alternate ||
								type1 == Footnote || type2 == Footnote)
								return true;
							CSymbols* cur  = (CSymbols*)m_arrItems[num];
							CSymbols* next = (CSymbols*)m_arrItems[num + 1];
							CCharacter* curCharacter  = cur->GetCharacter();
							CCharacter* nextCharacter = next->GetCharacter();
							if (curCharacter == NULL || nextCharacter == NULL)
								return false;
							long shadow1 = curCharacter->m_oAttributes.m_oBackground.m_oBackground.Color;
							long shadow2 = nextCharacter->m_oAttributes.m_oBackground.m_oBackground.Color;
							byte alpha1 = curCharacter->m_oAttributes.m_oBackground.m_oBackground.Alpha;
							byte alpha2 = nextCharacter->m_oAttributes.m_oBackground.m_oBackground.Alpha;

							if ((shadow1 == shadow2) && (alpha1 == alpha2) )
								return false;
							else
								return true;

						}
						void	DrawUnderline(IAVSRenderer *pRenderer, double dX1, double dY1, double dX2, double dY2, long lColor, byte bAlpha, byte bUnderline, double dSize)
						{							
							if (bUnderline != 0)
							{
								pRenderer->put_PenAlpha(bAlpha);
								pRenderer->put_PenSize(dSize);
								pRenderer->put_PenColor(lColor);
								pRenderer->BeginCommand(c_nTextGraphicType);
								if (bUnderline == 1  || bUnderline == 3  || bUnderline == 4  || bUnderline == 5 ||
									bUnderline == 6  || bUnderline == 7  || bUnderline == 8  || bUnderline == 9 ||
									bUnderline == 10 || bUnderline == 11 || bUnderline == 12 || bUnderline == 13)
								{
									//Type
									if (bUnderline == 1)
										pRenderer->put_PenDashStyle(DashStyleSolid);									
									else if (bUnderline == 6 || bUnderline == 7 || bUnderline == 8 || bUnderline == 9)
										pRenderer->put_PenDashStyle(DashStyleDash);
									else if (bUnderline == 4 || bUnderline == 5)
										pRenderer->put_PenDashStyle(DashStyleDot);
									else if (bUnderline == 10 || bUnderline == 11)
										pRenderer->put_PenDashStyle(DashStyleDashDot);
									else if (bUnderline == 12 || bUnderline == 13)
										pRenderer->put_PenDashStyle(DashStyleDashDotDot);

									//Size
									if (bUnderline == 3 || bUnderline == 5 || bUnderline == 7 ||
										bUnderline == 9 || bUnderline == 11 || bUnderline == 13)
										pRenderer->put_PenSize(2 * dSize);
									else
										pRenderer->put_PenSize(dSize);

									DrawLine(pRenderer, dX1, dY1  - dSize, dX2, dY2  - dSize);
								}
								else if (bUnderline == 2)
								{
									pRenderer->put_PenDashStyle(DashStyleSolid);

									DrawLine(pRenderer, dX1, dY1  - dSize, dX2, dY2  - dSize);
									DrawLine(pRenderer, dX1, dY1  + dSize, dX2, dY2  + dSize);									
								}
								else if (bUnderline == 14 || bUnderline == 15 || bUnderline == 16)
								{		
									pRenderer->put_PenDashStyle(DashStyleSolid);
									if (bUnderline == 14)
									{
										pRenderer->put_PenSize(dSize / 2);
										DrawWave(pRenderer, dX1, dY1, dX2, dY2, dSize);
									}
									else if (bUnderline == 15)
									{
										pRenderer->put_PenSize(dSize);
										DrawWave(pRenderer, dX1, dY1, dX2, dY2, 3 * dSize / 2);
									}
									else if (bUnderline == 16)
									{
										pRenderer->put_PenSize(dSize / 2);
										DrawWave(pRenderer, dX1, dY1 - dSize / 2, dX2, dY2 - dSize / 2, dSize / 2);
										DrawWave(pRenderer, dX1, dY1 + dSize / 2, dX2, dY2 + dSize / 2, dSize / 2);
									}
								}
								pRenderer->EndCommand(c_nTextGraphicType);
							}
						}
						void	DrawStrike(IAVSRenderer *pRenderer, double dX1, double dY1, double dX2, double dY2, long lColor, byte bAlpha, byte bStrike, double dSize)
						{
							if (bStrike != 0)
							{
								pRenderer->BeginCommand(c_nTextGraphicType);
								pRenderer->put_PenDashStyle(DashStyleSolid);
								pRenderer->put_PenSize(dSize);
								pRenderer->put_PenColor(lColor);
								pRenderer->put_PenAlpha(bAlpha);

								if (bStrike == 1)
								{
									DrawLine(pRenderer, dX1, dY1, dX2, dY2);
								}
								if (bStrike == 2)
								{
									DrawLine(pRenderer, dX1, dY1 - dSize, dX2, dY2 - dSize);
									DrawLine(pRenderer, dX1, dY1 + 3 * dSize / 2, dX2, dY2 + 3 * dSize / 2);
								}
								pRenderer->EndCommand(c_nTextGraphicType);
							}
						}
						void	DrawShading(IAVSRenderer *pRenderer, double dX, double dY, double dWidth, double dHeight, long lColor)
						{	

							pRenderer->put_BrushColor1(lColor);
							pRenderer->BeginCommand(c_nPathType);
							//pRenderer->BeginCommand(c_nTextGraphicType);
							pRenderer->PathCommandStart();
							pRenderer->PathCommandMoveTo(dX, dY);
							pRenderer->PathCommandLineTo(dX + dWidth, dY);
							pRenderer->PathCommandLineTo(dX + dWidth, dY + dHeight);
							pRenderer->PathCommandLineTo(dX, dY + dHeight);
							pRenderer->PathCommandClose();
							pRenderer->DrawPath(c_nWindingFillMode);
							//pRenderer->DrawPath(1);
							pRenderer->PathCommandEnd();
							//pRenderer->EndCommand(c_nTextGraphicType);
							pRenderer->EndCommand(c_nPathType);
						}
						void	DrawWave(IAVSRenderer *pRenderer, double dX1, double dY1, double dX2, double dY2, double dSize)
						{
							pRenderer->BeginCommand(c_nPathType);
							pRenderer->BeginCommand(c_nTextGraphicType);
							pRenderer->PathCommandStart();
							pRenderer->PathCommandMoveTo(dX1, dY1);
							//2.29 -  
							double lenghtWave = 2.3;
							int dev = (int)((dX2 - dX1) / lenghtWave);
							if (dev == 0)
								dev = 1;
							double dStep = (dX2 - dX1) / dev;							
							for(double dX3 = dX1, dY3 = dY1; dX3 + 3 * dStep / 4 < dX2; dX3 += dStep )
							{								
								pRenderer->PathCommandCurveTo(dX3, dY3, dX3 + dStep / 4, dY3 - dSize, dX3 + dStep / 2, dY3 );
								pRenderer->PathCommandCurveTo(dX3 + dStep / 2, dY3, dX3 + 3 * dStep / 4, dY3 + dSize, dX3 + dStep, dY3 );
							}
							pRenderer->DrawPath(c_nStroke);
							pRenderer->PathCommandEnd();
							pRenderer->EndCommand(c_nTextGraphicType);
							pRenderer->EndCommand(c_nPathType);
						}
						void	DrawLine(IAVSRenderer *pRenderer, double dX1, double dY1, double dX2, double dY2)
						{
							pRenderer->BeginCommand(c_nPathType);
							pRenderer->BeginCommand(c_nTextGraphicType);
							pRenderer->PathCommandStart();
							pRenderer->PathCommandMoveTo(dX1, dY1);
							pRenderer->PathCommandLineTo(dX2, dY2);
							pRenderer->DrawPath(c_nStroke);
							pRenderer->PathCommandEnd();
							pRenderer->EndCommand(c_nTextGraphicType);
							pRenderer->EndCommand(c_nPathType);
						}

					public:
						void	MoveTo(const REAL &fNewX)
						{
							REAL fDeltaX = fNewX - m_oRect.X;							
							MoveOn(fDeltaX, 0);
						}						
						void	MoveTo(const REAL &fNewX, const REAL &fNewY)
						{
							REAL fDeltaX = fNewX - m_oRect.X;							
							REAL fDeltaY = fNewY - m_oRect.Y;
							MoveOn(fDeltaX, fDeltaY);
						}
						void	MoveOn(const REAL &fDeltaX, const REAL &fDeltaY)
						{
							m_oRect.X	+= fDeltaX;
							m_oRect.Y	+= fDeltaY;
							for (size_t i = 0; i < m_arrItems.GetCount(); ++i)
							{
								m_arrItems[i]->MoveOn(fDeltaX, fDeltaY);
							}
						}
					};
					class CLine : public CWord, public RendererCommandSender {
					protected:
						REAL	m_fPersistWidth;
						REAL	m_fTextHeight;

						size_t	m_nSpacesCount;
						bool	m_bIsContainsAlternate;
						INT		m_iFootnoteCount;

						bool _startCell;
						bool _finishCell;

						bool _dummy;

					public:
						CLine() 
							: CWord(), RendererCommandSender() 
							, m_fPersistWidth(0.0f), m_fTextHeight(11*1.147f)
							, m_nSpacesCount(0), m_bIsContainsAlternate(false)
							, m_iFootnoteCount(0)
							, _startCell(false), _finishCell(false)
							, _dummy(false) {
						}
						~CLine()
						{
							Clear();
						}
						void	Clear()
						{
							m_fPersistWidth	= 0.0f;
							m_fTextHeight	= 11 * 1.147f;

							m_arrItems.RemoveAll();
							m_nItemsCount	= 0;

							m_nSpacesCount			= 0;
							m_bIsContainsAlternate	= false;
							m_iFootnoteCount		= 0;
							
							_startCell = false;
							_finishCell = false;
						}
					public:
						virtual void	AddItem(CItem *pItem)
						{
							if (pItem->GetType() == Alternate)
							{
								m_bIsContainsAlternate	= true;
							}
							else
							{
								if (pItem->GetType() == Space)
								{
									++m_nSpacesCount;
								}
								else if (pItem->GetType() == Footnote)
								{
									++m_iFootnoteCount;
								}

								if (pItem->GetRect().Height > m_fTextHeight)
								{
									m_fTextHeight	= pItem->GetRect().Height;
								}
							}

							CWord::AddItem(pItem);
						}
						void			SetPersistWidth(const REAL &fPersistWidth)
						{
							m_fPersistWidth	= fPersistWidth;
						}
						REAL			GetPersistWidth()
						{
							return m_fPersistWidth;
						}
						virtual void SetAlign(const CAlignHorizontal& align, const bool& first = false, const bool& last = false)
						{
							if (m_nItemsCount != 0)
							{
								AbsentLastSpaces();
								if (!first)
									AbsentFormerSpaces();

								switch(align) {
								case LeftAlign :
									break;

								case CenterAlign :
									MoveOn(m_fPersistWidth/2, 0);
									break;

								case RightAlign :
									MoveOn(m_fPersistWidth, 0);
									break;

								case WideAlign :
									if (last )
										break;
									float deltaSpace = (m_nSpacesCount != 0) ? m_fPersistWidth / m_nSpacesCount : 0;
									if (deltaSpace != 0) {
										for (int i = 0; i < (int) m_nItemsCount; ++i) {
											CItem* item = m_arrItems[i];
											if (item->GetType() == Space)
												if (item->GetRect().Width != 0)
													item->GetRect().Width += deltaSpace;
										}
									}
									break;
								}

								RearrangeItems();
							}
						}
						REAL			GetTextHeight()
						{
							return m_fTextHeight;
						}

						void setStartCell(const bool& value = true) {
							_startCell = value;
						}
						void setFinishCell(const bool& value = true) {
							_finishCell = value;
						}
						void setDummy(const bool& dummy) {
							_dummy = dummy;
						}
						bool isDummy() const {
							return _dummy;
						}
					public:
						CAtlArray<CItem*>*	GetItems()
						{
							return &m_arrItems;
						}
						virtual void		RestoreItems()
						{
							size_t nItemsCount	= m_arrItems.GetCount();
							for (size_t nIndex = 0; nIndex < nItemsCount; ++nIndex)
							{
								m_arrItems[nIndex]->RestoreRect();
							}
						}
						virtual void		SetOnBaseline(const bool& bIsInit = true)
						{
							m_oRect.Y	= m_fDescent - m_oRect.Height;

							size_t nItemsCount	= m_arrItems.GetCount();
							for (size_t nIndex = 0; nIndex < nItemsCount; ++nIndex)
							{
								m_arrItems[nIndex]->SetOnBaseline(false);
							}
						}
						REAL				GetAscent()
						{
							return m_oRect.Height - m_fDescent;
						}
						inline BOOL			IsContainsAlternate()
						{
							return m_bIsContainsAlternate;
						}
						inline INT			GetFootnoteCount()
						{
							return m_iFootnoteCount;
						}
					public:
						void Draw(IAVSRenderer* renderer, CDocumentManager& documentManager, const float& completeness) {
							sendRendererCommands(renderer, RendererCommand::BEGIN);

							if (_startCell)
								renderer->BeginCommand(c_nTableCell);
							renderer->BeginCommand(c_nLine);

							CWord::Draw(renderer, documentManager, completeness);

							renderer->EndCommand(c_nLine);
							if (_finishCell)
								renderer->EndCommand(c_nTableCell);

							sendRendererCommands(renderer, RendererCommand::END);

							#ifdef TME_DRAW_LINE_BORDER
							CItem::drawRect(renderer, m_oRect);
							#endif
						}
					private:
						void	AbsentLastSpaces()
						{
							for (int nIndex = (int)m_nItemsCount - 1; nIndex >= 0; --nIndex)
							{
								CItem *pItem	= m_arrItems[nIndex];
								REAL fWidth		= pItem->GetRect().Width;

								switch (pItem->GetType())
								{
								case Space :
									((CSpace*)pItem)->SetOriginWidth();
									m_fPersistWidth		+= fWidth;
									m_oRect.Width		-= fWidth;
									pItem->GetRect().Width	= 0.0f;
									--m_nSpacesCount;
									break;

								case LineEnd :
									pItem->GetRect() = RectF();
									break;

								default :
									return;
								}
							}
						}
						void	AbsentFormerSpaces()
						{
							for (size_t nIndex = 0; nIndex < m_nItemsCount; ++nIndex)
							{
								CItem *pItem	= m_arrItems[nIndex];
								REAL fWidth		= pItem->GetRect().Width;

								switch (pItem->GetType())
								{
								case Space :
									((CSpace*)pItem)->SetOriginWidth();
									m_fPersistWidth		+= fWidth;

									m_oRect.Width		-= fWidth;

									pItem->GetRect().Width	= 0;
									--m_nSpacesCount;
									break;

								default :
									return;									
								}
							}
						}
					};
					class CCompositeLine : public CLine
					{
					public:
						CCompositeLine()
							: CLine()
						{
						}
						~CCompositeLine()
						{
							Clear();
						}
						void	Clear()
						{
							for (size_t nIndex = 0; nIndex < m_nItemsCount; ++nIndex)
							{
								RELEASEOBJECT(m_arrItems[nIndex]);
							}
							m_arrItems.RemoveAll();
							m_nItemsCount	= 0;
						}
					public:
						void	AddItem(CItem *pItem)
						{
							if (pItem->GetType() == Word)
							{
								m_iFootnoteCount += ((CLine*)pItem)->GetFootnoteCount();
							}
							if (m_oRect.GetTop() > pItem->GetRect().GetTop())
							{
								m_oRect.Height	+= m_oRect.GetTop() - pItem->GetRect().GetTop();
								m_oRect.Y		= pItem->GetRect().GetTop();
							}

							if (m_oRect.GetBottom() < pItem->GetRect().GetBottom())
							{
								m_oRect.Height	= pItem->GetRect().GetBottom() - m_oRect.GetTop();
							}

							m_fDescent	= m_oRect.GetBottom();

							m_arrItems.Add(pItem);
							++m_nItemsCount;
						}
						void	RestoreItems()
						{
							size_t nItemsCount	= m_arrItems.GetCount();
							for (size_t nIndex = 0; nIndex < nItemsCount; ++nIndex)
							{
								((CLine*)(m_arrItems[nIndex]))->RestoreItems();
							}
						}
						virtual void SetAlign(const CAlignHorizontal& eAlign, const bool& bIsFirstLine = false, const bool& last = false)
						{

							switch(eAlign)
							{
							case LeftAlign :
								break;

							case CenterAlign :
								for (size_t iIndex = 1; iIndex < m_arrItems.GetCount() - 2; ++iIndex)
								{
									((CLine*)(m_arrItems[iIndex]))->SetAlign(CenterAlign, false);
								}
								if (m_arrItems.GetCount() > 1)
								{
									((CLine*)(m_arrItems[0]))->SetAlign(RightAlign, bIsFirstLine);
									((CLine*)(m_arrItems[m_arrItems.GetCount() - 1]))->SetAlign(LeftAlign);
								}
								else
								{
									((CLine*)(m_arrItems[0]))->SetAlign(CenterAlign, bIsFirstLine);
								}
								break;

							case RightAlign :
								for (size_t iIndex = 0; iIndex < m_arrItems.GetCount() - 1; ++iIndex)
								{
									((CLine*)(m_arrItems[iIndex]))->SetAlign(RightAlign, bIsFirstLine && (iIndex == 0));
								}
								break;

							case WideAlign :
								if (last)
									break;
								for (size_t iIndex = 0; iIndex < m_arrItems.GetCount(); ++iIndex)
								{
									((CLine*)(m_arrItems[iIndex]))->SetAlign(WideAlign, bIsFirstLine && (iIndex == 0));
								}
								break;
							}
						}
					};
					// ### ### ###
					class CFlowMap;
					class CSimplePageMaster;
					class CPageSequenceMaster;
					class CLayoutMasterSet;
					class CFlow;
					class CBounds : private CXmlAttributeReader
					{
					private:
						bool	m_bIsMargin;

						RectF	m_oRectPt;

					public:
						CBounds()
							: m_bIsMargin(TRUE), 
							m_oRectPt()
						{
						}
						~CBounds()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							m_bIsMargin	= TRUE;

							m_oRectPt	= RectF();
						}
						void	FromXmlNodeFo(XmlUtils::CXmlNode& oXmlNode, const bool& withPaddings = false)
						{
							m_oRectPt.X		= FloatPtAttributeFromXml(oXmlNode, _T("margin-left"));
							m_oRectPt.Y		= FloatPtAttributeFromXml(oXmlNode, _T("margin-top"));
							m_oRectPt.Width		= FloatPtAttributeFromXml(oXmlNode, _T("margin-right"));
							m_oRectPt.Height	= FloatPtAttributeFromXml(oXmlNode, _T("margin-bottom"));

							if (withPaddings)
								ReadMarginsFromPaddings(oXmlNode);

							m_bIsMargin	= TRUE;
						}
						void	FromXmlNodeFo2(XmlUtils::CXmlNode& oXmlNode, const bool& withPaddings = false)
						{
							m_oRectPt.X		= FloatPtAttributeFromXml(oXmlNode, _T("margin-left"), 85.0f);
							m_oRectPt.Y		= FloatPtAttributeFromXml(oXmlNode, _T("margin-top"), 56.7f);
							m_oRectPt.Width		= FloatPtAttributeFromXml(oXmlNode, _T("margin-right"), 42.5f);
							m_oRectPt.Height	= FloatPtAttributeFromXml(oXmlNode, _T("margin-bottom"), 56.7f);

							if (withPaddings)
								ReadMarginsFromPaddings(oXmlNode);

							m_bIsMargin	= TRUE;
						}
					public:
						void	SetAsMarginPt(const REAL& fLeftMarginPt, const REAL& fTopMarginPt, 
							const REAL& fRightMarginPt, const REAL& fBottommarginPt)
						{
							m_oRectPt.X			= fLeftMarginPt;
							m_oRectPt.Y			= fTopMarginPt;
							m_oRectPt.Width		= fRightMarginPt;
							m_oRectPt.Height	= fBottommarginPt;

							m_bIsMargin	= TRUE;
						}
						void	SetAsMarginMm(const REAL& fLeftMarginMm, const REAL& fTopMarginMm, 
							const REAL& fRightMarginMm, const REAL& fBottommarginMm)
						{
							static const REAL fMmToPt	= 72.0f / 25.4f;

							m_oRectPt.X			= fLeftMarginMm * fMmToPt;
							m_oRectPt.Y			= fTopMarginMm * fMmToPt;
							m_oRectPt.Width		= fRightMarginMm * fMmToPt;
							m_oRectPt.Height	= fBottommarginMm * fMmToPt;

							m_bIsMargin	= TRUE;
						}
						void	AddMarginPt(const REAL& fLeftMarginPt, const REAL& fTopMarginPt, 
							const REAL& fRightMarginPt, const REAL& fBottomMarginPt)
						{
							assert(m_bIsMargin);
							m_oRectPt.X			+= fLeftMarginPt;
							m_oRectPt.Y			+= fTopMarginPt;
							m_oRectPt.Width		+= fRightMarginPt;
							m_oRectPt.Height	+= fBottomMarginPt;
						}
					public:
						void	SetAsRect(const CBounds& oBounds)
						{
							REAL fLeftMarginPt	= m_oRectPt.X;
							REAL fTopMarginPt	= m_oRectPt.Y;

							m_oRectPt.X			= oBounds.m_oRectPt.X + fLeftMarginPt;
							m_oRectPt.Y			= oBounds.m_oRectPt.Y + fTopMarginPt;
							m_oRectPt.Width		= oBounds.m_oRectPt.Width - fLeftMarginPt - m_oRectPt.Width;
							m_oRectPt.Height	= oBounds.m_oRectPt.Height - fTopMarginPt - m_oRectPt.Height;

							m_bIsMargin	= FALSE;
						}
						void	SetAsRectPt(const RectF& oRectPt)
						{
							if (m_bIsMargin)
							{
								REAL fLeftMarginPt	= m_oRectPt.X;
								REAL fTopMarginPt	= m_oRectPt.Y;

								m_oRectPt.X			= oRectPt.X + fLeftMarginPt;
								m_oRectPt.Y			= oRectPt.Y + fTopMarginPt;
								m_oRectPt.Width		= oRectPt.Width - fLeftMarginPt - m_oRectPt.Width;
								m_oRectPt.Height	= oRectPt.Height - fTopMarginPt - m_oRectPt.Height;

								m_bIsMargin	= FALSE;
							}
							else
							{
								m_oRectPt	= oRectPt;
							}
						}
						void	SetAsRectPt(const REAL& fWidthPt, const REAL& fHeightPt)
						{
							m_oRectPt.Width		= fWidthPt - m_oRectPt.X - m_oRectPt.Width;
							m_oRectPt.Height	= fHeightPt - m_oRectPt.Y - m_oRectPt.Height;

							m_bIsMargin	= FALSE;
						}
						void	SetAsRectMm(const RectF& oRectMm)
						{
							if (m_bIsMargin)
							{
								static const REAL fMmToPt	= 72.0f / 25.4f;

								REAL fLeftMarginPt	= m_oRectPt.X;
								REAL fTopMarginPt	= m_oRectPt.Y;

								m_oRectPt.X			= oRectMm.X * fMmToPt + fLeftMarginPt;
								m_oRectPt.Y			= oRectMm.Y * fMmToPt + fTopMarginPt;
								m_oRectPt.Width		= oRectMm.Width * fMmToPt - fLeftMarginPt - m_oRectPt.Width;
								m_oRectPt.Height	= oRectMm.Height * fMmToPt - fTopMarginPt - m_oRectPt.Height;

								m_bIsMargin	= FALSE;
							}
						}
						void	SetAsRectMm(const REAL& fWidthMm, const REAL& fHeightMm)
						{
							static const REAL fMmToPt	= 72.0f / 25.4f;

							m_oRectPt.Width		= fWidthMm * fMmToPt - m_oRectPt.X - m_oRectPt.Width;
							m_oRectPt.Height	= fHeightMm * fMmToPt - m_oRectPt.Y - m_oRectPt.Height;

							m_bIsMargin	= FALSE;
						}
						// ---
						void	SetAfter(const RectF& oRectPt)
						{
							m_oRectPt.Y	= oRectPt.GetBottom();
						}
						// ---
						RectF	GetRectPt() const
						{
							if (!m_bIsMargin)
								return m_oRectPt;
							else
								return m_oRectPt;
						}
					private:
						void	ReadMarginsFromPaddings(XmlUtils::CXmlNode& paddings)
						{
							m_oRectPt.X		+= FloatPtAttributeFromXml(paddings, _T("padding-left"));
							m_oRectPt.Y		+= FloatPtAttributeFromXml(paddings, _T("padding-top"));
							m_oRectPt.Width		+= FloatPtAttributeFromXml(paddings, _T("padding-right"));
							m_oRectPt.Height	+= FloatPtAttributeFromXml(paddings, _T("padding-bottom"));
						}
					};
					class CRegion : private CXmlAttributeReader
					{
					private:
						CString	m_strName;

						CBounds	m_oBounds;

						RectF	m_oRectPt;
						BYTE	m_nIsFilled;

						bool	m_bIsColumn;
						byte	m_BreakType;

					public:
						CRegion()
							: m_strName(_T("")), 
							m_oBounds(), 
							m_oRectPt(), m_nIsFilled(1), 
							m_bIsColumn(false), m_BreakType(0)
						{
						}
						~CRegion()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							m_strName	= _T("");

							m_oBounds.Clear();

							m_oRectPt	= RectF();
							m_nIsFilled	= 1;

							m_bIsColumn = false;
							m_BreakType = 0;
						}
						void	FromXmlNodeFo(XmlUtils::CXmlNode& oXmlNode, const bool& withPaddings = false)
						{
							m_strName	= oXmlNode.GetAttributeOrValue(_T("region-name"), _T(""));
							if (m_strName == _T(""))
							{
								LoadStandartRegionName(oXmlNode);
							}

							m_oBounds.FromXmlNodeFo(oXmlNode, withPaddings);

							ReadDisplayAlign(oXmlNode);
						}						
						void	FromRectMm(const RectF& rect, const bool& asMargin = false)
						{
							CString m_strName = _T("from-rect");

							m_oBounds.Clear();
							if (asMargin)
								m_oBounds.SetAsMarginMm(rect.X, rect.Y, rect.Width, rect.Height);
							else
								m_oBounds.SetAsRectMm(rect);

							SetComplete();
							CheckRect();
						}
					public:
						inline void	SetReady()
						{
							m_nIsFilled	= 0;
						}
						inline void	SetComplete()
						{
							m_nIsFilled	= 1;
						}
						inline void SetProcessing()
						{
							m_nIsFilled	= 2;
						}
						inline bool	IsReady()
						{
							return (m_nIsFilled == 0);
						}
						inline BOOL	IsComplete()
						{
							return (m_nIsFilled == 1);
						}
						inline BOOL	IsEqualName(const CString& strName)
						{
							return (m_strName == strName);
						}

						inline byte	BreakType()
						{
							return m_BreakType;
						}
						inline void BreakType(const byte& breakType)
						{
							m_BreakType = breakType;
						}
					public:
						inline const RectF&	GetRectPt()	const
						{
							return m_oRectPt;
						}
						inline CBounds		GetBounds()
						{
							return m_oBounds;
						}
						inline RectF		GetOriginalRectPt() const
						{
							return m_oBounds.GetRectPt();
						}
						RectF				GetFilledRectPt() const
						{
							RectF boundsRect = m_oBounds.GetRectPt();
							return RectF(boundsRect.GetLeft(), boundsRect.GetTop(), m_oRectPt.GetRight() - m_oRectPt.GetLeft(), m_oRectPt.GetTop() - boundsRect.GetTop());							
						}
						inline REAL			GetRegionHeightPt()	const
						{
							return m_oRectPt.Height;
						}
						inline void			SetIsColumn()
						{
							m_bIsColumn = true;
						}
						inline bool			IsColumn() {
							return m_bIsColumn;
						}
						double				GetFilledHeight()
						{
							RectF originRect = GetOriginalRectPt();
							RectF rect		 = GetRectPt();
							double originHeight = originRect.GetBottom() - originRect.GetTop();
							double height		= rect.GetBottom() - rect.GetTop();
							return (originHeight - height);
						}
						double				GetFilledWidth()
						{
							RectF originRect = GetOriginalRectPt();
							double originWidth = originRect.GetRight() - originRect.GetLeft();
							return originWidth;
						}
						void				CheckRect()
						{
							if (IsComplete())
							{
								m_oRectPt	= m_oBounds.GetRectPt();
								SetReady();
							}
						}
						inline void			TrancateRectPt(const REAL &fHeightPt)
						{
							m_oRectPt.Y			+= fHeightPt;
							m_oRectPt.Height	-= fHeightPt;
						}
						inline void			TruncateHeightPt(const REAL &fHeightPt)
						{
							m_oRectPt.Height	-= fHeightPt;
						}
						inline void			TruncateLeftPt(const float& delta)
						{
							m_oRectPt.X += delta;
							m_oRectPt.Width += delta;
						}
						void				ChangeRect(CBounds oBoundsPt)
						{
							oBoundsPt.SetAsRectPt(m_oRectPt);
							m_oBounds	= oBoundsPt;
							m_oRectPt	= m_oBounds.GetRectPt();
						}
						void				SetRect(RectF &oRectPt)
						{
							m_oBounds.SetAsRectPt(oRectPt);
							m_oRectPt	= m_oBounds.GetRectPt();
						}
					public:
						void	SetBounds(const CBounds& oBounds)
						{
							m_oBounds.SetAsRect(oBounds);
						}
						void	AddBounds(const REAL& fLeftMarginPt, const REAL& fTopMarginPt, 
							const REAL& fRightMarginPt, const REAL& fBottommarginPt)
						{
							m_oBounds.AddMarginPt(fLeftMarginPt, fTopMarginPt, fRightMarginPt, fBottommarginPt);
						}
					public:
						void	ApplyDisplayAlign(RectF& oRectPt)
						{
							if (m_strName == _T("xsl-region-body"))
							{
								oRectPt	= m_oBounds.GetRectPt();
							}
							if (m_nIsFilled == 4)
							{
								m_oBounds.SetAfter(oRectPt);
							}
						}
					private:
						void	LoadStandartRegionName(XmlUtils::CXmlNode& oXmlNode)
						{
							CString strNodeName	= oXmlNode.GetName();

							if (strNodeName == _T("fo:region-body"))
							{
								m_strName	= _T("xsl-region-body");
							}
						}
						void	ReadDisplayAlign(XmlUtils::CXmlNode& oXmlNode)
						{
							CString strDisplayAlign	= oXmlNode.GetAttributeOrValue(_T("display-align"), _T(""));

							if (strDisplayAlign == _T("after"))
							{
								m_nIsFilled	= 4;
							}
							else
							{
								m_nIsFilled	= 3;
							}
						}
					};

					// ### ### ###
					class CBlock;
					class CContent;
					class CPictureC;
					class CShapeC;
					class CBlockC;
					class CTextC;
					class CPageNumberC;
					class CAlternate2 : public CItem, private CXmlAttributeReader {
					public:
						class CAreaWrap;
						enum EWrapType {
							WrapRuntime = 0, WrapInline, WrapNone, 
							WrapTopAndBottom, WrapSquare, WrapThrough, WrapTight
						};
						struct SSidesF
						{
							float	m_fTop;
							float	m_fBottom;
							float	m_fLeft;
							float	m_fRight;

							SSidesF() :
							m_fTop(0), m_fBottom(0), 
								m_fLeft(0), m_fRight(0)
							{
							}
						};
						class CAreaProperties : private CXmlAttributeReader2 {
							enum EActual {
								ActualComplete = 0, ActualPartial, ActualNone
							};

						public:
							class GeometryProperties : private CXmlAttributeReader2 {
							private:
								bool _horizontalFlip;
								bool _verticalFlip;

								float _rotate;

								bool _anchored;

							public:
								GeometryProperties() {
									_horizontalFlip = false;
									_verticalFlip = false;

									_rotate = 0;

									_anchored = false;
								}

							public:
								void loadFromTransformXml(XmlUtils::CXmlNode& transformXml) {
									setRotate(transformXml.GetAttribute(_T("rotate")));
									setHFlip(transformXml.GetAttribute(_T("hFlip")));
									setVFlip(transformXml.GetAttribute(_T("vFlip")));
									if (_horizontalFlip != _verticalFlip)
										_rotate *= -1;
								}
								void loadFromBoundsXml(XmlUtils::CXmlNode& boundsXml) {
									setRotate(AttrToStr(boundsXml, _T("rotation"), _T("val")));
									setFlips(AttrToStr(boundsXml, _T("flip"), _T("val")));
									if (_horizontalFlip != _verticalFlip)
										_rotate *= -1;
								}

							private:
								void setFlips(const CString& flip) {
									if (flip.Find(_T('x')) != -1)
										_horizontalFlip = true;
									if (flip.Find(_T('y')) != -1)
										_verticalFlip = true;
								}
								void setHFlip(const CString& flip) {
									_horizontalFlip = XmlUtils::GetBoolean(flip) == TRUE;
								}
								void setVFlip(const CString& flip) {
									_verticalFlip = XmlUtils::GetBoolean(flip) == TRUE;
								}
								void setRotate(const CString& rotate) {
									if (rotate != _T(""))
										_rotate = XmlUtils::GetFloat(rotate) * M_PI / 180;
								}

							public:
								void setRotationAngle(const float& rotate) {
									_rotate = rotate;
								}

								void changeHFlip() {
									_horizontalFlip = !_horizontalFlip;
									_rotate *= -1;
								}
								void changeVFlip() {
									_verticalFlip = !_verticalFlip;
									_rotate *= -1;
								}
							public:
								const bool& getHorzFlip() const {
									return _horizontalFlip;
								}
								const bool& getVertFlip() const {
									return _verticalFlip;
								}
								const float& getRotationAngle() const {
									return _rotate;
								}
							public:
								void setAnchored(const bool& anchored) {
									_anchored = anchored;
								}
								bool isAnchored() const {
									return _anchored;
								}
							};
							
						private:
							CRelativeFrom	m_eRelHorz;
							CRelativeFrom	m_eRelVert;
							PointF	m_oRelPoint;
							RectF	m_oArea;
							SSidesF _stretch;
							PointF _contraint;

							RectF	m_oRect;
							EActual	m_eActualOfRect;

							CAlignHorizontal	m_eAlignHorz;
							CAlignVertical		m_eAlignVert;

							GeometryProperties _geometryProperties;

							float _zIndex;

						private:
							bool	ReadIsRuntime(XmlUtils::CXmlNode& oPropertyNode)
							{
								CString strType = oPropertyNode.GetAttribute(_T("type"));
								if (strType == _T("runtime"))
									return true;
								else
									return false;
							}
							void	ReadArea(RectF& area, XmlUtils::CXmlNode& propertyXml) {
								area.X = TextToPt(propertyXml, _T("fo:position-x"));
								area.Y = TextToPt(propertyXml, _T("fo:position-y"));
								area.Width = TextToPt(propertyXml, _T("fo:extent-x"));
								area.Height = TextToPt(propertyXml, _T("fo:extent-y"));

								XmlUtils::CXmlNode transformXml;
								if (propertyXml.GetNode(_T("transform"), transformXml))
									_geometryProperties.loadFromTransformXml(transformXml);
							}
							CRelativeFrom	ReadRelHorz(XmlUtils::CXmlNode& propertyXml) {
								CString relative = AttrToStr(propertyXml, _T("fo:position-x"), _T("relative-from"));
								return GetRelHorz(relative);
							}
							CRelativeFrom	ReadRelVert(XmlUtils::CXmlNode& propertyXml) {
								CString relative = AttrToStr(propertyXml, _T("fo:position-y"), _T("relative-from"));
								return GetRelVert(relative);
							}
							CRelativeFrom	GetRelHorz(const CString& relativeHorz) {
								if (relativeHorz == _T("page"))
									return FromPage;
								else if (relativeHorz == _T("margin"))
									return FromMargin;
								else
									return FromColumn;
							}
							CRelativeFrom	GetRelVert(const CString& relativeVert) {
								if (relativeVert == _T("page"))
									return FromPage;
								else if (relativeVert == _T("margin"))
									return FromMargin;
								else if (relativeVert == _T("line"))
									return FromLine;
								else
									return FromParagraph;
							}

							void readStretch(XmlUtils::CXmlNode& propertyXml) {
								XmlUtils::CXmlNode stretchXml;
								if (propertyXml.GetNode(_T("stretch"), stretchXml)) {
									_stretch.m_fTop = stretchXml.ReadAttributeFloat(_T("top"), 0) / 100;
									_stretch.m_fBottom = stretchXml.ReadAttributeFloat(_T("bottom"), 0) / 100;
									_stretch.m_fLeft = stretchXml.ReadAttributeFloat(_T("left"), 0) / 100;
									_stretch.m_fRight = stretchXml.ReadAttributeFloat(_T("right"), 0) / 100;
								}
							}
							void readAlign(XmlUtils::CXmlNode& propertyXml) {
								CString align = AttrToStr(propertyXml, _T("fo:position-x"), _T("align"));
								m_eAlignHorz = GetAlignHorz(align);

								align = AttrToStr(propertyXml, _T("fo:position-y"), _T("align"));
								m_eAlignVert = GetAlignVert(align);
							}
							void	FromContentXml(XmlUtils::CXmlNode& contentNode) {
								XmlUtils::CXmlNode intContentNode = contentNode;
								XmlUtils::CXmlNode alternateNode;
								if (contentNode.GetNode(_T("fo:alternate-content"), alternateNode))
									if (!alternateNode.GetNode(_T("fo:content"), intContentNode))
										intContentNode = contentNode;

								bool nodeRead = true;
								XmlUtils::CXmlNode oShapeNode;
								if (!intContentNode.GetNode(_T("shape"), oShapeNode))
									if (!intContentNode.GetNode(_T("group"), oShapeNode))
										nodeRead = false;
								
								if (nodeRead) {
									ReadAreaFromContentBounds(m_oArea, oShapeNode);
									ReadAlignFromContentBounds(m_eAlignHorz, m_eAlignVert, oShapeNode);
									ReadRelFromContentBounds(m_eRelHorz, m_eRelVert, oShapeNode);
									ReadZIndexFromContentBounds(_zIndex, oShapeNode);
								}
							}
							void	ReadAreaFromContentBounds(RectF& oArea, XmlUtils::CXmlNode& oShapeNode)
							{
								XmlUtils::CXmlNode oBoundsNode;
								if (oShapeNode.GetNode(_T("bounds"), oBoundsNode)) {
									float left = AttrToPt(oBoundsNode, _T("left"), _T("val"));
									oArea.X = AttrToPt(oBoundsNode, _T("marginLeft"), _T("val"), left);
									float top = AttrToPt(oBoundsNode, _T("top"), _T("val"));
									oArea.Y = AttrToPt(oBoundsNode, _T("marginTop"), _T("val"), top);
									oArea.Width = AttrToPt(oBoundsNode, _T("width"), _T("val"));
									oArea.Height = AttrToPt(oBoundsNode, _T("height"), _T("val"));

									_geometryProperties.loadFromBoundsXml(oBoundsNode);
								}
							}
							void	ReadAlignFromContentBounds(CAlignHorizontal& eAlignHorz, CAlignVertical& eAlignVert, XmlUtils::CXmlNode& oShapeNode)
							{
								XmlUtils::CXmlNode oBoundsNode;
								if (oShapeNode.GetNode(_T("bounds"), oBoundsNode))
								{
									CString strAlign = AttrToStr(oBoundsNode, _T("PosHor"), _T("val"));
									m_eAlignHorz = GetAlignHorz(strAlign);
									strAlign = AttrToStr(oBoundsNode, _T("PosVert"), _T("val"));
									m_eAlignVert = GetAlignVert(strAlign);
								}
							}
							void	ReadRelFromContentBounds(CRelativeFrom& relHorz, CRelativeFrom& relVert, XmlUtils::CXmlNode& shape)
							{
								XmlUtils::CXmlNode bounds;
								if (shape.GetNode(_T("bounds"), bounds))
								{
									relHorz = GetRelHorz(AttrToStr(bounds, _T("PosHorRel"), _T("val")));
									relVert = GetRelVert(AttrToStr(bounds, _T("PosVertRel"), _T("val")));
								}
							}
							void	ReadZIndexFromContentBounds(float& zIndex, XmlUtils::CXmlNode& shape)
							{
								XmlUtils::CXmlNode bounds;
								if (shape.GetNode(_T("bounds"), bounds))
									zIndex = XmlUtils::GetFloat(AttrToStr(bounds, _T("z-index"), _T("val")));
							}
							CAlignHorizontal GetAlignHorz(const CString& strAlignHorz)
							{
								CAlignHorizontal eAlignHorz = NoneAlign;
								if (strAlignHorz == _T("left"))
									eAlignHorz = LeftAlign;
								else if (strAlignHorz == _T("center"))
									eAlignHorz = CenterAlign;
								else if (strAlignHorz == _T("right"))
									eAlignHorz = RightAlign;
								return eAlignHorz;
							}
							CAlignVertical GetAlignVert(const CString& strAlignVert)
							{
								CAlignVertical eAlignVert = NoneAlignVert;
								if (strAlignVert == _T("top"))
									eAlignVert = FarAlignVert;
								else if (strAlignVert == _T("center"))
									eAlignVert = CenterAlignVert;
								else if (strAlignVert == _T("bottom"))
									eAlignVert = NearAlignVert;
								return eAlignVert;
							}
						private:
							void UpdatePosition(EActual actual) {
								if (m_eActualOfRect == ActualNone 
										&& (actual == ActualPartial || actual == ActualComplete)) {
									m_oRect = m_oArea;
									SetRectFromRelPoint(m_oRect);
									m_eActualOfRect = ActualPartial;
								}
								if (m_eActualOfRect == ActualPartial 
										&& actual == ActualComplete) {
									m_oRect.X += _contraint.X;
									m_oRect.Y += _contraint.Y;
									m_eActualOfRect = ActualComplete;
								}

							}
							void	SetRelPoint(const CPage& oPage, const CRegion& oRegion, const RectF& line) {
								SetRelPointHorz(oRegion);
								SetRelPointVert(oRegion, line);
							}
							void	SetRelPointHorz(const CRegion& oRegion)
							{
								if (m_eRelHorz == FromColumn)
									m_oRelPoint.X = oRegion.GetRectPt().X;
								else
									m_oRelPoint.X = 0;
							}
							void	SetRelPointVert(const CRegion& oRegion, const RectF& line)	{
								if (FromParagraph == m_eRelVert)
									m_oRelPoint.Y = oRegion.GetRectPt().Y;
								else if (FromLine == m_eRelVert)
									m_oRelPoint.Y = line.GetBottom();
								else
									m_oRelPoint.Y = 0;
							}
							void	Align(const CPage& page, const CRegion& region, const RectF& line) {
								AlignHorz(page, region);
								AlignVert(page, region, line);
							}
							void	AlignHorz(const CPage& page, const CRegion& oRegion)
							{
								if (m_eAlignHorz == NoneAlign)
									return;
								else if (m_eAlignHorz == LeftAlign) {
									if (m_eRelHorz == FromPage)
										m_oRelPoint.X = 0;
									else
										m_oRelPoint.X = oRegion.GetRectPt().X;
									m_oArea.X = 0;
								}
								else if (m_eAlignHorz == CenterAlign) {
									if (m_eRelHorz == FromPage)
										m_oRelPoint.X = page.GetWidthPt()/2;
									else
										m_oRelPoint.X = oRegion.GetRectPt().X + oRegion.GetRectPt().Width/2;
									m_oArea.X = -m_oArea.Width/2;
								}
								else if (m_eAlignHorz == RightAlign) {
									if (m_eRelHorz == FromPage)
										m_oRelPoint.X = page.GetWidthPt();
									else
										m_oRelPoint.X = oRegion.GetRectPt().GetRight();
									m_oArea.X = -m_oArea.Width;
								}
							}
							void	AlignVert(const CPage& page, const CRegion& oRegion, const RectF& line)	{
								if (NoneAlignVert == m_eAlignVert)
									return;
								if (FarAlignVert == m_eAlignVert) {
									if (FromPage == m_eRelVert)
										m_oRelPoint.Y = 0;
									else if (FromLine == m_eRelVert)
										m_oRelPoint.Y = line.GetBottom();
									else
										m_oRelPoint.Y = oRegion.GetOriginalRectPt().GetTop();
									m_oArea.Y = 0;
								}
								else if (m_eAlignVert == CenterAlignVert) {
									if (m_eRelVert == FromPage)
										m_oRelPoint.Y = page.GetHeightPt()/2;
									else
										m_oRelPoint.Y = oRegion.GetOriginalRectPt().Y + oRegion.GetOriginalRectPt().Height/2;
									m_oArea.Y = -m_oArea.Height/2;
								}
								else if (m_eAlignVert == NearAlignVert) {
									if (FromPage == m_eRelVert)
										m_oRelPoint.Y = page.GetHeightPt();
									else if (FromLine == m_eRelVert)
										m_oRelPoint.Y = line.GetBottom();
									else
										m_oRelPoint.Y = oRegion.GetOriginalRectPt().GetBottom();
									m_oArea.Y = -m_oArea.Height;
								}
							}

						private:
							void	SetRectFromRelPoint(RectF& oRect)
							{
								oRect.X += m_oRelPoint.X;
								oRect.Y += m_oRelPoint.Y;
							}
						public:
							CAreaProperties() 
									: m_eRelHorz(FromPage), m_eRelVert(FromPage)
									, m_eActualOfRect(ActualNone)
									, m_eAlignHorz(NoneAlign), m_eAlignVert(NoneAlignVert)
									, _zIndex(0) {}
						public:
							void	SetAreaRect(RectF& rect, const bool& onlySize = false) {
								if (onlySize) {
									m_oArea.Width = rect.Width;
									m_oArea.Height = rect.Height;
								}
								else 
									m_oArea = rect;
							}
							void	SetRect(RectF& oRect)
							{
								m_oRect = oRect;
							}
						public:
							byte	FromXml(XmlUtils::CXmlNode& alternateNode) {
								XmlUtils::CXmlNode propertyNode;
								if (!alternateNode.GetNode(_T("fo:property"), propertyNode))
									return 1;
								XmlUtils::CXmlNode contentNode;
								if (!alternateNode.GetNode(_T("fo:content"), contentNode))
									return 1;

								return FromXml(propertyNode, contentNode);
							}
							byte	FromXml(XmlUtils::CXmlNode& oPropertyNode, XmlUtils::CXmlNode& oContentNode) {
								ReadArea(m_oArea, oPropertyNode);

								m_eRelHorz = ReadRelHorz(oPropertyNode);
								m_eRelVert = ReadRelVert(oPropertyNode);
								readStretch(oPropertyNode);
								readAlign(oPropertyNode);

								//bool bIsRuntime = ReadIsRuntime(oPropertyNode);
								//if (bIsRuntime)
									FromContentXml(oContentNode);

								return 0;
							}
							void	Relate(const CPage& oPage, const CRegion& oRegion, const RectF& line) {
								SetRelPoint(oPage, oRegion, line);
								Align(oPage, oRegion, line);
								m_eActualOfRect = ActualNone;
							}
							bool checkContraints(const CPage& page ) {
								UpdatePosition(ActualPartial);

								if (m_oRect.X < 0)
									_contraint.X = -m_oRect.X;
								if (m_oRect.Y < 0)
									_contraint.Y = -m_oRect.Y;
								float deltaX = m_oRect.GetRight() - page.GetWidthPt();
								if (deltaX > 0)
									_contraint.X = -deltaX;
								if (m_oRect.GetBottom() > page.GetHeightPt())
									return false;

								return true;
							}
						public:
							const RectF&	RectPt() {
								UpdatePosition(ActualComplete);
								return m_oRect;
							}
							const RectF&	AreaRectPt() {
								return m_oArea;
							}
							const PointF&	RelPointPt()
							{
								return m_oRelPoint;
							}
							CRelativeFrom	RelHorz() const
							{
								return m_eRelHorz;
							}
							CRelativeFrom	RelVert() const
							{
								return m_eRelVert;
							}

							float getZIndex() const
							{
								return _zIndex;
							}
							RectF getDrawingRect(const RectF& rect) const {
								RectF drawingRect(rect);

								float offsetTop = rect.Height * _stretch.m_fTop;
								float offsetBottom = rect.Height * _stretch.m_fBottom;
								drawingRect.Y += offsetTop;
								drawingRect.Height -= offsetTop + offsetBottom;
								
								float offsetLeft = rect.Width * _stretch.m_fLeft;
								float offsetRight = rect.Width * _stretch.m_fRight;
								drawingRect.X += offsetLeft;
								drawingRect.Width -= offsetLeft + offsetRight;

								return drawingRect;
							}
							const GeometryProperties& getGeomPr() const {
								return _geometryProperties;
							}
							void setAnchored(const EWrapType& wrapType) {
								_geometryProperties.setAnchored(wrapType == WrapInline);
							}
						};
						class CAreaWrap : private CXmlAttributeReader2
						{
						private:
							EWrapType	m_eWrapType;
							int			m_iInlinePosition;

							CArray<PointF>	m_arrPointsOrigin;
							CArray<PointF>	m_arrPoints;
							SSidesF	m_oDistanceOrigin;
							SSidesF	m_oDistance;

						private:
							bool	ReadIsRuntime(XmlUtils::CXmlNode& oPropertyNode)
							{
								CString strType = oPropertyNode.GetAttribute(_T("type"));
								if (strType == _T("runtime"))
									return true;
								else
									return false;
							}
							byte	FromContentXml(XmlUtils::CXmlNode& oContentNode)
							{
								bool nodeRead = true;
								XmlUtils::CXmlNode oShapeNode;
								if (!oContentNode.GetNode(_T("shape"), oShapeNode))
									if (!oContentNode.GetNode(_T("group"), oShapeNode))
										nodeRead = false;
									
								if (nodeRead) {
									m_eWrapType = ReadContentWrapType(oShapeNode);
									ReadDistanceFromContentBounds(m_oDistance, oShapeNode);
									return 0;
								}

								return 1;
							}
							EWrapType	ReadWrapType(XmlUtils::CXmlNode& oPropertyNode)
							{
								CString strWrapType = oPropertyNode.GetAttribute(_T("type"));
								XmlUtils::CXmlNode oWrapNode;
								if (oPropertyNode.GetNode(_T("fo:wrap"), oWrapNode))
									strWrapType = oWrapNode.GetAttribute(_T("type"));
								
								return GetWrapType(strWrapType);
							}
							EWrapType	ReadContentWrapType(XmlUtils::CXmlNode& oShapeNode)
							{
								CString strWrapType = _T("none");
								XmlUtils::CXmlNode oWrapNode;
								if (oShapeNode.GetNode(_T("w10:wrap"), oWrapNode))
								{
									strWrapType = oWrapNode.GetAttribute(_T("type"));
									if (strWrapType == _T(""))
									{
										CString anchorX = oWrapNode.GetAttribute(_T("anchorx"));
										CString anchorY = oWrapNode.GetAttribute(_T("anchory"));
										bool wrapNoneX = false;
										if ((anchorX == _T("page")) || (anchorX == _T("margin")))
											wrapNoneX = true;
										bool wrapNoneY = false;
										if ((anchorY == _T("page")) || (anchorY == _T("margin")))
											wrapNoneY = true;
										if (wrapNoneX && wrapNoneY)
											return WrapNone;
									}
								}
								if (strWrapType == _T("none")) {
									XmlUtils::CXmlNode oBoundsNode;
									if (oShapeNode.GetNode(_T("bounds"), oBoundsNode))
									{
										CString pos = AttrToStr(oBoundsNode, _T("Pos"), _T("val"));
										if ((pos == _T("")) || (pos == _T("static")))
											strWrapType = _T("inline");
									}
								}
								
								return GetWrapType(strWrapType);
							}
							void	ReadDistance(SSidesF& oDistance, XmlUtils::CXmlNode& oPropertyNode)
							{
								XmlUtils::CXmlNode anchorNode;
								if (oPropertyNode.GetNode(_T("fo:anchor"), anchorNode))
								{
									oDistance.m_fLeft = AttrToPt(anchorNode, _T(""), _T("distance-left"), 0);
									oDistance.m_fRight = AttrToPt(anchorNode, _T(""), _T("distance-right"), 0);
									oDistance.m_fTop = AttrToPt(anchorNode, _T(""), _T("distance-top"), 0);
									oDistance.m_fBottom = AttrToPt(anchorNode, _T(""), _T("distance-bottom"), 0);
								}
							}
							void	ReadDistanceFromContentBounds(SSidesF& oDistance, XmlUtils::CXmlNode& oShapeNode)
							{
								XmlUtils::CXmlNode oBoundsNode;
								if (oShapeNode.GetNode(_T("bounds"), oBoundsNode))
								{
									oDistance.m_fLeft = AttrToPt(oBoundsNode, _T("wrapDistLeft"), _T("val"), 9);
									oDistance.m_fRight = AttrToPt(oBoundsNode, _T("wrapDistRight"), _T("val"), 9);
									oDistance.m_fTop = AttrToPt(oBoundsNode, _T("wrapDistTop"), _T("val"));
									oDistance.m_fBottom = AttrToPt(oBoundsNode, _T("wrapDistBottom"), _T("val"));
								}
							}
						private:
							void	Points(const RectF& oRect)
							{
								m_arrPoints.RemoveAll();
								m_arrPoints.Add(PointF(oRect.GetLeft(), oRect.GetTop()));
								m_arrPoints.Add(PointF(oRect.GetRight(), oRect.GetTop()));
								m_arrPoints.Add(PointF(oRect.GetRight(), oRect.GetBottom()));
								m_arrPoints.Add(PointF(oRect.GetLeft(), oRect.GetBottom()));
								m_arrPoints.Add(PointF(oRect.GetLeft(), oRect.GetTop()));
							}
							void	Points(const CArray<PointF>& arrPoints)
							{
								m_arrPoints.RemoveAll();
								m_arrPoints.Copy(arrPoints);
							}
							EWrapType	GetWrapType(const CString strWrapType)
							{
								EWrapType eReturnWrapType = WrapInline;

								if (strWrapType == _T("none"))
									eReturnWrapType = WrapNone;
								else if (strWrapType == _T("topAndBottom"))
									eReturnWrapType = WrapTopAndBottom;
								else if (strWrapType == _T("square"))
									eReturnWrapType = WrapSquare;
								else if (strWrapType == _T("through"))
									eReturnWrapType = WrapThrough;
								else if (strWrapType == _T("tight"))
									eReturnWrapType = WrapTight;
								else if (strWrapType == _T("inline"))
									eReturnWrapType = WrapInline;

								return eReturnWrapType;
							}
						private:
							void	ApplyTopAndBottom(CAreaProperties& oAreaProperties, const CRegion& oRegion)
							{
								RectF& oRegionRect = oRegion.GetOriginalRectPt();
								RectF oAreaRect = oAreaProperties.RectPt();

								float distLeft = oAreaRect.GetLeft() - oRegionRect.GetLeft();
								float distRight = oRegionRect.GetRight() - oAreaRect.GetRight();

								if ((distLeft >= 0) && (distRight >= 0))
								{
									m_oDistance.m_fLeft = distLeft;
									m_oDistance.m_fRight = distRight;
									Points(oAreaRect);
								}
								else
									ApplySquare(oAreaProperties, oRegion);
							}

							void	ApplySquare(CAreaProperties& oAreaProperties, const CRegion& oRegion)
							{
								RectF oAreaRect = oAreaProperties.RectPt();
								oAreaRect.Y -= m_oDistance.m_fTop;
								oAreaRect.Height += m_oDistance.m_fTop + m_oDistance.m_fBottom;

								Points(oAreaRect);
							}
							void	ApplyTight(CAreaProperties& oAreaProperties, const CRegion& oRegion)
							{
								RectF oAreaRect = oAreaProperties.RectPt();
								oAreaRect.Y -= m_oDistance.m_fTop;
								oAreaRect.Height += m_oDistance.m_fTop + m_oDistance.m_fBottom;

								Points(oAreaRect);
							}
						public:
							CAreaWrap() : 
							  m_eWrapType(WrapNone), m_iInlinePosition(0), 
								  m_arrPointsOrigin(), m_arrPoints(), 
								  m_oDistanceOrigin(), m_oDistance()
							  {
							  }
							  ~CAreaWrap()
							  {
							  }

						public:
							byte	FromXml(XmlUtils::CXmlNode& oPropertyNode, XmlUtils::CXmlNode& oContentNode)
							{
								m_eWrapType = ReadWrapType(oPropertyNode);
								ReadDistance(m_oDistance, oPropertyNode);

								bool bIsRuntime = ReadIsRuntime(oPropertyNode);
								if (bIsRuntime)
									FromContentXml(oContentNode);

								return 0;
							}

							int		InlinePosition()
							{
								return m_iInlinePosition;
							}
							void	InlinePosition(const int& iPosition)
							{
								m_iInlinePosition = iPosition;
							}
							EWrapType	WrapType()
							{
								return m_eWrapType;
							}
							const CArray<PointF>&	Points()
							{
								return m_arrPoints;
							}
							const SSidesF&	Distance() const
							{
								return m_oDistance;
							}
						public:
							bool	Inline()
							{
								return (m_eWrapType == WrapInline);
							}
							void	Inline(const bool& bIsInline)
							{
								if (bIsInline == true)
									m_eWrapType = WrapInline;
								else
									assert(false);
							}
						public:
							void Wrap(CAreaProperties& areaProperties, const CRegion& region) {
								areaProperties.setAnchored(m_eWrapType);

								if (m_eWrapType == WrapTopAndBottom)
									ApplyTopAndBottom(areaProperties, region);
								else if (m_eWrapType == WrapSquare)
									ApplySquare(areaProperties, region);
								else if (m_eWrapType == WrapTight)
									ApplyTight(areaProperties, region);
							}
						};

						class CAltContent {
						private:
							enum EContentType {
								ContentShape = 0, ContentPicture, ContentGroup, ContentLargeLetter, ContentNone
							};
						private:
							CContent*	m_pContent;
							CTextC* _Text;
							EContentType	m_eType;
							bool	m_bPlaced;

						private:
							byte	FromPropertyXml(XmlUtils::CXmlNode& oPropertyNode)
							{
								XmlUtils::CXmlNode graphicsNode;
								if (oPropertyNode.GetNode(_T("fo:graphic"), graphicsNode))
									m_eType = ReadContentType(graphicsNode);
								if (m_eType == ContentPicture)
									if (!PictureFromXml(graphicsNode))
										return 0;

								return 1;
							}
							EContentType	ReadContentType(XmlUtils::CXmlNode& graphicsNode)
							{
								CString strContentType = graphicsNode.GetAttribute(_T("type"));
								if (strContentType == _T("shape"))
									return ContentShape;
								else if (strContentType == _T("picture"))
									return ContentPicture;
								else if (strContentType == _T("LargeLetter"))
									return ContentLargeLetter;
								else if (strContentType == _T("group"))
									return ContentGroup;

								return ContentNone;
							}

							byte	FromContentXml(XmlUtils::CXmlNode& oContentNode, CDocumentManager& documentManager)
							{
								if (m_eType == ContentShape)
									return ShapeFromXml(oContentNode, documentManager);
								else if (m_eType == ContentLargeLetter)
									return LargeLetterFromXml(oContentNode, documentManager);
								else if (m_eType == ContentGroup)
									return GroupFromXml(oContentNode, documentManager);

								return 1;
							}
							byte	ReadContentTypeFromContent(XmlUtils::CXmlNode& alternateNode)
							{
								XmlUtils::CXmlNode contentNode;
								if (alternateNode.GetNode(_T("fo:content"), contentNode)) {
									XmlUtils::CXmlNode innerAlternateNode;
									if (contentNode.GetNode(_T("fo:alternate-content"), innerAlternateNode)) {
										XmlUtils::CXmlNode propertyNode;
										if (innerAlternateNode.GetNode(_T("fo:property"), propertyNode))
											return FromPropertyXml(propertyNode);
									}
								}

								return 1;
							}
							byte	PictureFromXml(XmlUtils::CXmlNode& oContentNode)
							{
								CPictureC* pPicture = new CPictureC();
								if (!pPicture->FromXml(oContentNode))
								{
									m_pContent = pPicture;
									return 0;
								}
								return 1;
							}
							byte	ShapeFromXml(XmlUtils::CXmlNode& oContentNode, CDocumentManager& documentManager)
							{
								XmlUtils::CXmlNode oIntContentNode = oContentNode;
								XmlUtils::CXmlNode oAlternateNode;
								if (oContentNode.GetNode(_T("fo:alternate-content"), oAlternateNode))
									if (!oAlternateNode.GetNode(_T("fo:content"), oIntContentNode))
										oIntContentNode = oContentNode;

								CShapeC* pShape = new CShapeC();
								if (!pShape->FromXml(oIntContentNode)) {
									m_pContent = pShape;
									TextFromXml(oIntContentNode, documentManager);
								}

								return (m_pContent != NULL) ? 0 : 1;
							}
							byte	LargeLetterFromXml(XmlUtils::CXmlNode& oContentNode, CDocumentManager& documentManager)
							{
								XmlUtils::CXmlNode oIntContentNode = oContentNode;
								XmlUtils::CXmlNode oAlternateNode;
								if (oContentNode.GetNode(_T("fo:alternate-content"), oAlternateNode))
									if (!oAlternateNode.GetNode(_T("fo:content"), oIntContentNode))
										oIntContentNode = oContentNode;

								CBlockC* pBlock = new CBlockC();
								if (!pBlock->FromXml(oIntContentNode, documentManager))
									m_pContent = pBlock;

								return (m_pContent != NULL) ? 0 : 1;
							}

							byte	GroupFromXml(XmlUtils::CXmlNode& contentNode, CDocumentManager& documentManager) {
								XmlUtils::CXmlNode intContentNode = contentNode;
								XmlUtils::CXmlNode alternateNode;
								if (contentNode.GetNode(_T("fo:alternate-content"), alternateNode))
									if (!alternateNode.GetNode(_T("fo:content"), intContentNode))
										intContentNode = contentNode;

								CGroupC* group = new CGroupC();
								if (!group->FromXml(intContentNode, documentManager))
									m_pContent = group;

								return (m_pContent != NULL) ? 0 : 1;
							}
							byte	TextFromXml(XmlUtils::CXmlNode& contentNode, CDocumentManager& documentManager) {
								XmlUtils::CXmlNode shapeNode;
								if (contentNode.GetNode(_T("shape"), shapeNode)) {
									XmlUtils::CXmlNode textBoxNode;
									if (shapeNode.GetNode(_T("textBox"), textBoxNode)) {
										_Text = new CTextC();
										if (_Text->FromXml(textBoxNode, documentManager))
											RELEASEOBJECT(_Text);
									}
								}

								return 0;
							}
						public:
							CAltContent()
								: m_pContent(NULL), _Text(NULL), 
								m_eType(ContentNone), 
								m_bPlaced(false)
							{
							}
							~CAltContent()
							{
								RELEASEOBJECT(m_pContent);
								RELEASEOBJECT(_Text);
							}
						public:
							byte	FromXml(XmlUtils::CXmlNode& oAlternateNode, CDocumentManager& documentManager)
							{
								RELEASEOBJECT(m_pContent);
								RELEASEOBJECT(_Text);
								bool bIsLoaded = false;

								XmlUtils::CXmlNode oPropertyNode;
								if (oAlternateNode.GetNode(_T("fo:property"), oPropertyNode))
									if (!FromPropertyXml(oPropertyNode))
										bIsLoaded = true;
								if (m_eType == ContentNone)
									ReadContentTypeFromContent(oAlternateNode);
								if (!bIsLoaded) {
									if (m_eType != ContentNone) {
										XmlUtils::CXmlNode oContentNode;
										if (oAlternateNode.GetNode(_T("fo:content"), oContentNode))
											if (!FromContentXml(oContentNode, documentManager))
												bIsLoaded = true;
									}
								}

								return (bIsLoaded) ? 0 : 1;
							}
							void	Update(CGrapher* pGrapher, RectF& oRect, float& fDescent, CAlternate2::CAreaProperties& m_oAreaProperties)
							{
								assert(m_pContent != NULL);
								m_pContent->Update(pGrapher, oRect, fDescent, m_oAreaProperties);
								if (_Text)
									_Text->Update(pGrapher, oRect, fDescent, m_oAreaProperties);
							}
							void	CalculateRect(CAlternate2::CAreaProperties& m_oAreaProperties) {
								m_pContent->CalculateRect(m_oAreaProperties);
								if (_Text)
									_Text->fitRegionIfNecessary(m_oAreaProperties);
							}

						public:
							void	Set(CContent* pContent)
							{
								RELEASEOBJECT(m_pContent);
								m_pContent = pContent;
							}
							bool	Placed()
							{
								return m_bPlaced;
							}
							void	Placed(const bool& bPlaced)
							{
								m_bPlaced = bPlaced;
							}

							bool isLetter() const {
								return dynamic_cast<CBlockC*>(m_pContent) != NULL;
							}
						public:
							void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const RectF& oRect, 
										const float& fDescent, const CAreaProperties::GeometryProperties& geomPr, 
										const float& fCompleteness)	{
								if (m_pContent != NULL) {
									IAVSRenderer2* renderer2 = NULL;
									if (!SUCCEEDED(pRenderer->QueryInterface(__UUIDOF__IAVSRENDERER2, (void**)&renderer2)))
										renderer2 = NULL;

									if (renderer2 != NULL)
										m_pContent->sendBeginCommand(renderer2, geomPr);

									m_pContent->transform(geomPr.getRotationAngle(), geomPr.getHorzFlip(), geomPr.getVertFlip());
									m_pContent->Draw(pRenderer, documentManager, oRect, fDescent, fCompleteness);
									m_pContent->clearTransform();

									if (renderer2 != NULL)
										m_pContent->sendEndCommand(renderer2, geomPr);

									RELEASEINTERFACE(renderer2);
								}
								if (_Text)
									_Text->Draw(pRenderer, documentManager, oRect, fDescent, fCompleteness);
							}
							void	MoveOn(const float& deltaX, const float& deltaY)
							{
								if (m_pContent)
									m_pContent->MoveOn(deltaX, deltaY);
								if (_Text)
									_Text->MoveOn(deltaX, deltaY);
							}
						};
						class CInlineProperties
						{
						public:
							CInlineProperties() : 
								m_VertPosition(0)
							{
							}
							~CInlineProperties()
							{
								Clear();
							}
							void	Clear()
							{
								m_VertPosition = 0;
							}
						public:
							void	FromXml(XmlUtils::CXmlNode& alternateProperty)
							{
								XmlUtils::CXmlNode inlineProperty;
								if (alternateProperty.GetNode(_T("inline"), inlineProperty))
									m_VertPosition = XmlUtils::GetFloat(inlineProperty.GetAttribute(_T("vert-pos"), _T("0")));

							}										
						public:
							float	VertPos() const 
							{
								return m_VertPosition;
							}

						private:
							float	m_VertPosition;
						};
					private:
						CAreaProperties	m_oAreaProperties;
						CAreaWrap		m_oAreaWrap;
						CAltContent		m_oAltContent;
						CInlineProperties m_oInlineProperties;

						bool m_Related;
						bool _inHeader;

					private:
						void	UpdateRect() {
							m_oRect = m_oAreaProperties.RectPt();
							if (m_oAreaWrap.Inline())
								SetOnBaseline();
						}

					public:
						CAlternate2() 
								: CItem()
								, m_oAreaProperties(), m_oAreaWrap()
								, m_oAltContent(), m_oInlineProperties()
								, m_Related(false), _inHeader(false) {}
						virtual ~CAlternate2() {}
					public:
						byte	FromXml(XmlUtils::CXmlNode& alternateNode, CDocumentManager& documentManager, const bool& bUpdate = false)	{
							#ifdef TME_NODE_XML
							CString xml = alternateNode.GetXml();
							#endif

							XmlUtils::CXmlNode oPropertyNode;
							if (!alternateNode.GetNode(_T("fo:property"), oPropertyNode))
								return 1;
							XmlUtils::CXmlNode oContentNode;
							if (!alternateNode.GetNode(_T("fo:content"), oContentNode))
								return 1;

							if (m_oAreaWrap.FromXml(oPropertyNode, oContentNode))
								return 2;
							if (m_oAreaProperties.FromXml(oPropertyNode, oContentNode))
								return 3;
							if (m_oAltContent.FromXml(alternateNode, documentManager))
								return 4;

							m_oInlineProperties.FromXml(oPropertyNode);
							m_fDescent = -m_oInlineProperties.VertPos();
							UpdateRect();

							return 0;
						}
						void	SetContent(CContent* pContent, const int& iInlinePosition = 0)
						{
							assert(pContent != NULL);
							m_oAltContent.Set(pContent);
							m_oAreaWrap.InlinePosition(iInlinePosition);
						}
						void	UpdateContent(CGrapher* pGrapher)
						{
							m_oAltContent.Update(pGrapher, m_oRect, m_fDescent, m_oAreaProperties);
							if (Inline())
								SetOnBaseline();
						}
						bool relate(CPage& page, CRegion& region, const RectF& line) {
							m_oAreaProperties.Relate(page, region, line);
							m_oAltContent.CalculateRect(m_oAreaProperties);
							/*if (!m_oAreaProperties.checkContraints(page))
								return false;*/

							UpdateRect();
							m_oAreaWrap.Wrap(m_oAreaProperties, region);

							return true;
						}
					public:
						int		InlinePosition()
						{
							return m_oAreaWrap.InlinePosition();
						}
						void	InlinePosition(const int& iInlinePosition)
						{
							assert(iInlinePosition >= 0);
							m_oAreaWrap.InlinePosition(iInlinePosition);
						}
						bool	Placed()
						{
							return m_oAltContent.Placed();
						}
						void	Placed(const bool& bPlaced)
						{
							m_oAltContent.Placed(bPlaced);
						}
						bool	Related() const 
						{
							return m_Related;
						}
						void	Related(const bool& related)
						{
							m_Related = related;
						}
						bool	AnchoredToRegion() const
						{
							if (m_oAreaProperties.RelVert() == FromParagraph)
								return true;
							else
								return false;
						}
						const CArray<PointF>&	Points()
						{
							return m_oAreaWrap.Points();
						}
						float	DistanceLeft() const
						{
							return m_oAreaWrap.Distance().m_fLeft;
						}
						float	DistanceRight() const
						{
							return m_oAreaWrap.Distance().m_fRight;
						}

						float getZIndex() const
						{
							return m_oAreaProperties.getZIndex();
						}
						void setInHeader(const bool& inHeader) {
							_inHeader = inHeader;
						}
					public:
						bool	Inline()
						{
							return m_oAreaWrap.Inline();
						}
						void	Inline(const bool& bIsInline)
						{
							m_oAreaWrap.Inline(bIsInline);
						}
					public:
						bool isLetter() const {
							return m_oAltContent.isLetter();
						}
						CItemType	GetType()
						{
							return Alternate;
						}
						void Draw(IAVSRenderer* renderer, CDocumentManager& documentManager, const float& completeness) {
							if (_inHeader)
								renderer->BeginCommand(c_nHeader);
							RectF drawingRect = m_oAreaProperties.getDrawingRect(m_oRect);

							m_oAltContent.Draw(renderer, documentManager, drawingRect, m_fDescent, 
								m_oAreaProperties.getGeomPr(), completeness);
							//CItem::drawRect(renderer, m_oRect);
							if (_inHeader)
								renderer->EndCommand(c_nHeader);
						}
						void MoveOn(const float& deltaX, const float& deltaY) {
							CItem::MoveOn(deltaX, deltaY);
							m_oAltContent.MoveOn(deltaX, deltaY);
						}
					};

					class CContent {
					protected:
						class ContentTransformer {
						private:
							bool _enabled;

							float _rotate;
							bool _horzFlip;
							bool _vertFlip;

						public:
							ContentTransformer() 
								: _enabled(false)
								, _rotate(0)
								, _horzFlip(false), _vertFlip(false) {
							}

						public:
							void setTransform(const float& rotate, const bool& horzFlip, const bool& vertFlip) {
								assert(!isEnabled());
								if (rotate != 0 || horzFlip || vertFlip) {
									_rotate = rotate;
									_horzFlip = horzFlip;
									_vertFlip = vertFlip;
									
									setEnabled(true);
								}
							}
							void clearTransform() {
								setEnabled(false);
							}

						private:
							void setEnabled(const bool& enabled) {
								_enabled = enabled;
							}

						protected:
							bool isEnabled() const {
								return _enabled;
							}
							
							float getRotate() const {
								return _rotate;
							}
							float getFlipXCoeff() const {
								return _horzFlip ? -1 : 1;
							}
							float getFlipYCoeff() const {
								return _vertFlip ? -1 : 1;
							}
						};
					public:
						CArray<PointF> m_arrPoints;

					public:
						virtual ~CContent()	{
							Clear();
						}
					public:
						void Clear() {
							m_arrPoints.RemoveAll();
						}
						virtual bool	FromXmlNode(XmlUtils::CXmlNode& oXmlNode)
						{
							return false;
						}
						virtual void	Update(CGrapher* pGrapher, RectF& oRect, REAL& fDescent, CAlternate2::CAreaProperties& m_oAreaProperties)
						{
							oRect.Y	= -oRect.Height + fDescent;
						}
						virtual BYTE	GetType()
						{
							return 0;
						}
						virtual void	CalculateRect(CAlternate2::CAreaProperties& m_oAreaProperties) {}

					public:
						void			SetPoints(const CArray<PointF>& arrPoints)
						{
							m_arrPoints.RemoveAll();
							m_arrPoints.Copy(arrPoints);
						}
						void			SetPoints(const REAL& fPositionX, const REAL& fPositionY)
						{
							for (size_t nIndex = 0; nIndex < m_arrPoints.GetCount(); ++nIndex)
							{
								m_arrPoints[nIndex].X	+= fPositionX;
								m_arrPoints[nIndex].Y	+= fPositionY;
							}
						}
						CArray<PointF>&	GetPoints()
						{
							return m_arrPoints;
						}
					public:
						virtual void	Draw(IAVSRenderer* renderer, CDocumentManager& documentManager, const RectF& rect, const float& descent, const float& completeness) {
						}
					public:
						virtual void	MoveOn(const float& deltaX, const float& deltaY) {}
					public:
						virtual void transform(const float& angle, const bool& horzFlip, const bool& vertFlip) {}
						virtual void clearTransform() {}
					public:
						virtual void sendBeginCommand(IAVSRenderer2* renderer
								, const CAlternate2::CAreaProperties::GeometryProperties& geomPr) {}
						virtual void sendEndCommand(IAVSRenderer2* renderer
								, const CAlternate2::CAreaProperties::GeometryProperties& geomPr) {}
					
					protected:
						static inline RectF convertFromPtToMm(const RectF& rect) {
							static const float multPtToMm = 25.4f / 72.0f;;

							return RectF(rect.X * multPtToMm, rect.Y * multPtToMm
								, rect.Width * multPtToMm, rect.Height * multPtToMm);
						}
					};

					class CPictureC : public CContent {
					private:
						class PictureTransformer : public ContentTransformer {
						protected:
							IAVSRenderer* _renderer;

						public:
							PictureTransformer() 
								: ContentTransformer() {
							}

						public:
							void applyTransform(IAVSRenderer* renderer, RectF& rectMm) {
								if (isEnabled()) {
									_renderer = renderer;
									
									float rotate = -getRotate();
									float cosA = cos(rotate);
									float sinA = sin(rotate);

									_renderer->SetTransform(getFlipXCoeff() * cosA, -getFlipXCoeff() * sinA
											, getFlipYCoeff() * sinA, getFlipYCoeff() * cosA
											, rectMm.X + rectMm.Width / 2, rectMm.Y + rectMm.Height / 2);

									rectMm.X = -rectMm.Width / 2;
									rectMm.Y = -rectMm.Height / 2;
								}
							}
							void clearTransform() {
								if (isEnabled())
									_renderer->ResetTransform();

								ContentTransformer::clearTransform();
							}
						} _transformer;
					public:
						CString	m_strSourceFilePath;

					public:
						CPictureC()
							: m_strSourceFilePath(_T(""))
						{
						}
						~CPictureC()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							m_strSourceFilePath	= _T("");
						}
						byte	FromXml(XmlUtils::CXmlNode &oContentNode)
						{
							XmlUtils::CXmlNode oSourceNode;
							oContentNode.GetNode(_T("fo:source"), oSourceNode);

							m_strSourceFilePath				= oSourceNode.GetTextExt();
							if ((m_strSourceFilePath == _T("")) && (m_strSourceFilePath == _T("NULL")))
							{
								m_strSourceFilePath	= _T("");
								return 1;
							}
							CString strTempDirectoryPath	= oSourceNode.GetAttributeOrValue(_T("dir"), _T(""));
							strTempDirectoryPath			= ConvertToLongPathName(strTempDirectoryPath);

							m_strSourceFilePath.Replace( _T('/'), _T('\\'));
							m_strSourceFilePath = strTempDirectoryPath + _T("\\word\\") + m_strSourceFilePath;

							return 0;
						}
						BYTE	GetType()
						{
							return 1;
						}
						void	CalculateRect(CAlternate2::CAreaProperties& m_oAreaProperties)
						{
						}
					public:
						void	Draw(IAVSRenderer* renderer, CDocumentManager &documentManager, const RectF& rect, const REAL& descent, const REAL &completeness) {
							RectF rectMm = convertFromPtToMm(rect);
							_transformer.applyTransform(renderer, rectMm);

							if (m_strSourceFilePath != _T("")) {
								BSTR bstrSourceFilePath	= m_strSourceFilePath.AllocSysString();
								renderer->DrawImageFromFile(bstrSourceFilePath, rectMm.X, rectMm.Y, rectMm.Width, rectMm.Height);
								SysFreeString(bstrSourceFilePath);
							}
							else
								DrawBorder(renderer, rect, descent, completeness);
						}

					public:
						virtual void transform(const float& angle, const bool& horzFlip, const bool& vertFlip) {
							_transformer.setTransform(angle, horzFlip, vertFlip);
						}
						virtual void clearTransform() {
							_transformer.clearTransform();
						}

					private:
						CString	ConvertToLongPathName(const CString &strShortPath)
						{
							DWORD nLength		= GetLongPathName(strShortPath, NULL, 0);
							TCHAR *pLongPath	= new TCHAR[nLength];
							GetLongPathName(strShortPath, pLongPath, nLength);
							CString strLongPath	= CString(pLongPath);
							delete[] pLongPath;

							return strLongPath;
						}
					private:
						void	DrawBorder(IAVSRenderer* renderer, const RectF& rect, const float& descent, const float &completeness)
						{
							const float ptToMm = 25.4f / 72.0f;

							renderer->put_PenColor(0x00);
							renderer->put_PenSize(0.1);
							renderer->put_PenAlpha(255);
							renderer->PathCommandStart();
							renderer->PathCommandMoveTo(rect.X * ptToMm, rect.Y * ptToMm);
							renderer->PathCommandLineTo(rect.X * ptToMm + rect.Width * ptToMm, rect.Y * ptToMm);
							renderer->PathCommandLineTo(rect.X * ptToMm + rect.Width * ptToMm, rect.Y * ptToMm + rect.Height * ptToMm);
							renderer->PathCommandLineTo(rect.X * ptToMm, rect.Y * ptToMm + rect.Height * ptToMm);
							renderer->PathCommandLineTo(rect.X * ptToMm, rect.Y * ptToMm);
							renderer->PathCommandClose();
							renderer->DrawPath(0x01);
							renderer->PathCommandEnd();
						}
					};

					class CShapeC : public CContent
					{
					public:
						CString	m_strSourceXml;
						XmlUtils::CXmlNode m_oXmlNode;
						
						CGeomShapeInfo _info;

					public:
						CShapeC()
							: m_strSourceXml(_T(""))
						{
						}
						~CShapeC()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							m_strSourceXml	= _T("");
						}
						byte	FromXml(XmlUtils::CXmlNode& oContentNode)
						{
							XmlUtils::CXmlNode oShapeNode;
							if (oContentNode.GetNode(_T("shape"), oShapeNode)) {
								m_oXmlNode = oShapeNode;
								return 0;
							}

							return 1;
						}
						BYTE	GetType()
						{
							return 2;
						}
					public:
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const RectF& oRect
								, const REAL& fDescent, const REAL &fCompleteness) {
							const REAL fPtToMm	= 25.4f / 72.0f;

							RectF oRectMm;
							oRectMm.X		= oRect.X * fPtToMm;
							oRectMm.Y		= oRect.Y * fPtToMm;
							oRectMm.Width	= oRect.Width * fPtToMm;
							oRectMm.Height	= oRect.Height * fPtToMm;

							CShape oShape(NSBaseShape::ppt, 0);
							CMetricInfo oMetric;

							oMetric.m_lMillimetresHor = (DWORD)documentManager.GetPageWidthMm();
							oMetric.m_lMillimetresVer = (DWORD)documentManager.GetPageHeightMm();

							oShape.LoadFromXML(m_oXmlNode);

							SetInfo(_info, oRectMm);

							#ifdef PPT_DEF
							oShape.ToRenderer(pRenderer, _info, oMetric, 0.0, 1.0);
							#else
							DrawNonPPTShape(pRenderer, oShape, _info, oMetric);
							#endif
						}
					private:
						void SetInfo(CGeomShapeInfo& oInfo, RectF oRectMm) {
							oInfo.m_dLeft	= (double)(oRectMm.X);
							oInfo.m_dTop	= (double)(oRectMm.Y);
							oInfo.m_dWidth	= (double)(oRectMm.Width);
							oInfo.m_dHeight	= (double)(oRectMm.Height);
						}
						void DrawNonPPTShape(IAVSRenderer* renderer, CShape& shape, CGeomShapeInfo& info, CMetricInfo& metric) {
							CString strXml = shape.ToXml(info, metric, 0.0, 1.0);

							strXml = _T("<shapes>") + strXml + _T("</shapes>");

							XmlUtils::CXmlNode oXmlNode;
							if (oXmlNode.FromXmlString(strXml))
							{
								XmlUtils::CXmlNodes oListGraphics;
								if (oXmlNode.GetNodes(_T("ImagePaint-DrawGraphicPath"), oListGraphics))
								{
									LONG lCount = oListGraphics.GetCount();
									for (LONG i = 0; i < lCount; ++i)
									{
										XmlUtils::CXmlNode oNode;
										oListGraphics.GetAt(i, oNode);

										CDrawGraphicPath oGraphicPath;
										oGraphicPath.InternalFromXmlNode(oNode);

										oGraphicPath.Draw(renderer);										
										renderer->PathCommandEnd();
									}
								}
							}
						}
					public:
						virtual void transform(const float& angle, const bool& horzFlip, const bool& vertFlip) {
							CContent::transform(angle, horzFlip, vertFlip);
							_info.m_dRotate = angle * 180 / M_PI;
							_info.m_bFlipH = horzFlip;
							_info.m_bFlipV = vertFlip;
						}
						virtual void clearTransform() {
							CContent::clearTransform();
							_info.m_dRotate = 0;
							_info.m_bFlipH = false;
							_info.m_bFlipV = false;
						}
					public:
						virtual void sendBeginCommand(IAVSRenderer2* renderer
								, const CAlternate2::CAreaProperties::GeometryProperties& geomPr) {
							IAVSRenderer* pRend = NULL;
							renderer->QueryInterface(__uuidof(IAVSRenderer), (void**)&pRend);
							pRend->BeginCommand(c_nShape);
							RELEASEINTERFACE(pRend);
							renderer->CommandLong2(c_nShapeWrap, geomPr.isAnchored());
						}
						virtual void sendEndCommand(IAVSRenderer2* renderer
								, const CAlternate2::CAreaProperties::GeometryProperties& geomPr) {
							IAVSRenderer* pRend = NULL;
							renderer->QueryInterface(__uuidof(IAVSRenderer), (void**)&pRend);
							pRend->EndCommand(c_nShape);
							RELEASEINTERFACE(pRend);
						}
					};

					class CBlockC : public CContent
					{
					public:
						CBlock*  m_Block;

					private:
						double	 m_dHeightRegion;
						double   m_dWidthRegion;

					private:
						double	 m_dHeightPage;
						double   m_dWidthPage;
						double	 m_dLeftBorder;
						double   m_dRightBorder;

					public:
						CAtlArray<CLine*> m_lines;

						CBlockFrameAttributes*	m_pBlockFrameAttributes;
					public:
						CBlockC()
							:m_dHeightRegion(0), m_dWidthRegion(0), m_pBlockFrameAttributes(NULL)
						{
							m_Block = new CBlock();
							m_pBlockFrameAttributes = new CBlockFrameAttributes();	
						}
						~CBlockC()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							delete m_Block;
							size_t nFLinesCount	= m_lines.GetCount();
							for (size_t nIndex = 0; nIndex < nFLinesCount; ++nIndex)
							{
								RELEASEOBJECT(m_lines[nIndex]);
							}
							RELEASEOBJECT(m_pBlockFrameAttributes);
						}
						void	Update(CGrapher* pGrapher, RectF& oRect, REAL& fDescent, CAlternate2::CAreaProperties& m_oAreaProperties)
						{
							m_dHeightPage = (double)pGrapher->m_DocumentManager->GetPageHeightMm();
							m_dWidthPage  = (double)pGrapher->m_DocumentManager->GetPageWidthMm();
							m_dLeftBorder = (double)pGrapher->m_DocumentManager->GetPageLeftBorderMm();
							m_dRightBorder= (double)pGrapher->m_DocumentManager->GetPageRightBorderMm();


							/*m_dHeightPage = (double)CDocumentManager::GetPageHeightMm() * 72 / 25.4;
							m_dWidthPage  = (double)CDocumentManager::GetPageWidthMm() * 72 / 25.4;
							m_dLeftBorder = (double)CDocumentManager::GetPageLeftBorderPt();
							m_dRightBorder= (double)CDocumentManager::GetPageRightBorderPt();*/

							double dWidth = 0;
							if (m_pBlockFrameAttributes->m_width > 0)
								dWidth = min((m_dRightBorder - m_dLeftBorder), m_pBlockFrameAttributes->m_width);
							else 
								dWidth = m_dRightBorder - m_dLeftBorder;


							RectF rect(0, 0, dWidth * 25.4 / 72 , m_dHeightPage* 25.4 / 72);
							//RectF rect(0, 0, (m_dRightBorder - m_dLeftBorder) * 25.4 / 72, m_dHeightPage);

							CRegion textRegion;
							textRegion.FromRectMm(rect);

							CPage page;

							page.StartPrintingFlow();
							m_Block->IgnoreAnchors(true);
							m_Block->FillRegion(textRegion, page, true, pGrapher);

							page.GetLines(m_lines);

							m_dHeightRegion = textRegion.GetFilledHeight();
							m_dWidthRegion  = GetFillWidth(dWidth);

							oRect.X		 = 0;
							oRect.Y		 = 0;
							oRect.Width  = max(m_dWidthRegion, m_pBlockFrameAttributes->m_width) + m_pBlockFrameAttributes->m_hSpace;
							oRect.Height = max(m_dHeightRegion, m_pBlockFrameAttributes->m_height) + m_pBlockFrameAttributes->m_vSpace;

							m_oAreaProperties.SetAreaRect(oRect);
						}

						byte	FromXml(XmlUtils::CXmlNode& contentNode, CDocumentManager& documentManager)
						{
							#ifdef TME_NODE_XML
							CString xml = contentNode.GetXml();
							#endif

							XmlUtils::CXmlNode oBlockNode;
							contentNode.GetNode(_T("fo:block"), oBlockNode);

							m_Block->InTable(false);
							CAtlArray<CString> curCommands;
							bool inCommandField = false; 

							m_Block->FromXmlNode(oBlockNode, documentManager, false, inCommandField, curCommands);
							m_pBlockFrameAttributes->FromXmlNode(oBlockNode);

							m_Block->m_pBlockAttributes->m_nSpaceAfter = 0;
							m_Block->m_pBlockAttributes->m_nSpaceBefore = 0;

							return 0;
						}						
						BYTE	GetType()
						{
							return 3;
						}
					public:
						void	CalculateRect(CAlternate2::CAreaProperties& m_oAreaProperties) {
							
							RectF oRect   = m_oAreaProperties.AreaRectPt();
							PointF oPoint = m_oAreaProperties.RelPointPt();
							double dX = 0;
							if (m_pBlockFrameAttributes->m_xAlign == _T("right"))
							{
								if (m_pBlockFrameAttributes->m_hAnchor == _T("margin"))
									dX = m_dRightBorder - m_dWidthRegion - oPoint.X;
								else if (m_pBlockFrameAttributes->m_hAnchor == _T("page"))
									dX = m_dWidthPage - m_dWidthRegion - oPoint.X;
							}
							else if (m_pBlockFrameAttributes->m_xAlign == _T("left"))
							{
								if (m_pBlockFrameAttributes->m_hAnchor == _T("margin"))
									dX = 0;
								else if (m_pBlockFrameAttributes->m_hAnchor == _T("page"))
									dX = -oPoint.X;
							}
							else if (m_pBlockFrameAttributes->m_x > 0)
							{
								dX = m_pBlockFrameAttributes->m_x;
								if (m_pBlockFrameAttributes->m_hAnchor == _T("page"))
									dX -= oPoint.X;
							}
							else if (m_pBlockFrameAttributes->m_dropCap == _T("drop"))
							{
								dX = oRect.GetLeft();
							}
							else if (m_dWidthRegion < m_dLeftBorder)
							{
								dX = m_dLeftBorder - m_dWidthRegion - oPoint.X;
							}

							double dY = 0;
							if (m_pBlockFrameAttributes->m_y > 0)
							{
								dY = m_pBlockFrameAttributes->m_y;
								if (m_pBlockFrameAttributes->m_vAnchor == _T("page"))
									dY -= oPoint.Y;
							}
							else 
							{
								dY = oRect.GetTop();
							}

							oRect.X = dX;
							oRect.Y = dY;
							m_oAreaProperties.SetAreaRect(oRect);

							dX = dX + oPoint.X;
							dY = dY + oPoint.Y;

							double dDeltaX = 0;
							double dDeltaY = 0;

							size_t nCount = m_lines.GetCount();
							if (nCount > 0)
							{
								CLine* pFirstLine = m_lines[0];
								dDeltaX  = dX;// - pFirstLine->GetRect().GetLeft();
								dDeltaY  = dY;// - pFirstLine->GetRect().GetTop();
							}
							for (size_t i = 0; i < nCount; ++i)
							{
								m_lines[i]->MoveOn(dDeltaX, dDeltaY);
							}					
						}
						void	Draw(IAVSRenderer* renderer, CDocumentManager& documentManager, const RectF& rect, const float& descent, const float& completeness) {	
							#ifdef TME_DRAW_LETTER_BORDER
							CItem::drawRect(renderer, rect);
							#endif
														
							size_t nCount = m_lines.GetCount();
							for (size_t i = 0; i < nCount; ++i)
								m_lines[i]->Draw(renderer, documentManager, completeness);
						}
					public:
						void	MoveOn(const float& deltaX, const float& deltaY) {
							for (size_t i = 0; i < m_lines.GetCount(); ++i)
								m_lines[i]->MoveOn(deltaX, deltaY);
						}
					private:
						double	GetFillWidth(double dWidth)
						{
							//double widthRegion = (m_dRightBorder - m_dLeftBorder)/* * 72.0f / 25.4f */;
							size_t size = m_lines.GetCount();
							double minPersist = dWidth;
							for( size_t i = 0; i < size; ++i)
							{
								double dCurrentPersist = (double)m_lines[i]->GetPersistWidth();
								if (minPersist > dCurrentPersist)
									minPersist = dCurrentPersist;
							}
							return (dWidth - minPersist);
						}
					};
					class CPageNumberC : public CContent
					{
					private:
						CString		m_strText;
						bool		m_bIsPageCount;

						CCharacter*	m_pCharacter;

					public:
						CPageNumberC()
							: m_strText(_T("")), m_bIsPageCount(false), 
							m_pCharacter(NULL)
						{
						}
						CPageNumberC(CCharacter *pCharacter, bool bIsPageCount = false)
							: m_strText(_T("")), m_bIsPageCount(bIsPageCount), 
							m_pCharacter(pCharacter)
						{
						}
						~CPageNumberC()
						{
							RELEASEOBJECT(m_pCharacter);
						}
					public:
						void	Update(CGrapher* pGrapher, RectF& oRect, REAL& fDescent, CAlternate2::CAreaProperties& m_oAreaProperties)
						{
							if (!m_bIsPageCount)
								m_strText	= pGrapher->m_DocumentManager->getPageIndexString();
							else
								m_strText	= pGrapher->m_DocumentManager->getPageCountString();

							oRect		= pGrapher->GetRectForString(m_strText, m_pCharacter);
							fDescent	= pGrapher->GetDescent(m_pCharacter);

							SetOnBaseline(oRect, fDescent);
						}
						void	CalculateRect(CAlternate2::CAreaProperties& m_oAreaProperties)
						{
						}
					public:
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const RectF& oRect , const REAL& fDescent, const REAL &fCompleteness)
						{
							if (oRect.Width == 0)
							{
								return;
							}
							BSTR bstrText	= m_strText.AllocSysString();

							m_pCharacter->m_oAttributes.m_oFont.SetToRenderer(pRenderer);
							m_pCharacter->m_oAttributes.m_oBrush.SetToRenderer(pRenderer);
							m_pCharacter->m_oAttributes.m_oShadow.SetToRenderer(pRenderer);
							m_pCharacter->m_oAttributes.m_oEdge.SetToRenderer(pRenderer);

							const float fPtToMm	= 25.4f / 72.0f;
							pRenderer->CommandDrawText(bstrText, oRect.X * fPtToMm, oRect.Y * fPtToMm, oRect.Width * fPtToMm, oRect.Height * fPtToMm, (oRect.Height - fDescent)  * fPtToMm);
							SysFreeString(bstrText);							
						}

					private:
						void	SetOnBaseline(RectF& oRect, REAL& fDescent)
						{
							MoveTo(oRect, 0, fDescent - oRect.Height);

							if (m_pCharacter->m_oAttributes.m_nBaselineShift == 1)
							{
								MoveOn(oRect, -2 * fDescent);
							}
							else if (m_pCharacter->m_oAttributes.m_nBaselineShift == 2)
							{
								MoveOn(oRect, fDescent);
							}
						}
						void	MoveTo(RectF& oRect, const REAL &fNewX, const REAL &fNewY)
						{
							oRect.X	= fNewX;
							oRect.Y	= fNewY;
						}
						void	MoveOn(RectF& oRect, const REAL &fDeltaY)
						{
							oRect.Y	+= fDeltaY;
						}
					};					
					class CGroupC : public CContent	{
						class GroupTransformer : public ContentTransformer {
						public:
							void applyTransformToChild(const RectF& parentRect, RectF& childRect
									, CAlternate2::CAreaProperties::GeometryProperties& geomPr) {
								PointF parentCenter(parentRect.X + parentRect.Width / 2
										, parentRect.Y + parentRect.Height / 2);
								PointF childCenter(childRect.X + childRect.Width / 2
										, childRect.Y + childRect.Height / 2);
								PointF childCenterRight(childCenter.X + childRect.Width
										, childCenter.Y);

								float oldDx = childCenterRight.X - childCenter.X;
								float oldDy = childCenterRight.Y - childCenter.Y;
								float oldR = sqrt(pow(oldDx, 2) + pow(oldDy, 2));

								transformPoint(parentCenter, childCenter);
								transformPoint(parentCenter, childCenterRight);

								float newDx = childCenterRight.X - childCenter.X;
								float newDy = childCenterRight.Y - childCenter.Y;
								float newR = sqrt(pow(newDx, 2) + pow(newDy, 2));

								float angle = 0;
								float r = oldR * newR;
								if (r != 0) {
									angle = acos((oldDx * newDx + oldDy * newDy) / (oldR * newR));
									if (oldDx * newDy - oldDy * newDx < 0)
										angle *= -1;
								}
								
								if (getFlipXCoeff() == -1)
									geomPr.changeHFlip();
								if (getFlipYCoeff() == -1)
									geomPr.changeVFlip();

								childRect.X = childCenter.X - childRect.Width / 2;
								childRect.Y = childCenter.Y - childRect.Height / 2;

								geomPr.setRotationAngle(geomPr.getRotationAngle() + angle);
							}
						private:
							void transformPoint(const PointF& center, PointF& point) {
								float x = point.X - center.X;
								float y = point.Y - center.Y;

								float rotate = getRotate();
								float cosA = cos(rotate);
								float sinA = sin(rotate);

								point.X = cosA * x - sinA * y + center.X;
								point.Y = sinA * x + cosA * y + center.Y;
							}

						} _transformer;

					public:
						CGroupC() {
						}
						~CGroupC() {
							Clear(true);
						}
					public:
						void Clear(const bool& complete = false) {
							if (!complete)
								_Alternates.RemoveAll();
						}
						byte FromXml(XmlUtils::CXmlNode& contentNode, CDocumentManager& documentManager) {
							XmlUtils::CXmlNode groupNode;
							if (contentNode.GetNode(_T("group"), groupNode)) {
								ReadArea(groupNode);
								ReadAlternates(groupNode, documentManager);
							}

							return 0;
						}
						void Update(CGrapher* grapher, RectF& rect, float& descent, CAlternate2::CAreaProperties& areaProperties)
						{
							int alternatesCount = (int) _Alternates.GetCount();
							for (int i = 0; i < alternatesCount; ++i) {
								RectF relatedRect = RelatedRect(_Alternates[i], _AreaProperties[i], rect);
								_Alternates[i].Update(grapher, relatedRect, descent, areaProperties);
							}
						}
						void Draw(IAVSRenderer* renderer, CDocumentManager& documentManager, const RectF& rect
								, const float& descent, const float &completeness) {
							int alternatesCount = (int) _Alternates.GetCount();
							for (int i = 0; i < alternatesCount; ++i) {
								RectF relatedRect = RelatedRect(_Alternates[i], _AreaProperties[i], rect);

								CAlternate2::CAreaProperties::GeometryProperties geomPr(_AreaProperties[i].getGeomPr());
								_transformer.applyTransformToChild(rect, relatedRect, geomPr);

								_Alternates[i].Draw(renderer, documentManager, relatedRect, descent, geomPr, completeness);
							}
						}
					public:
						virtual void transform(const float& rotate, const bool& horzFlip, const bool& vertFlip) {
							_transformer.setTransform(rotate, horzFlip, vertFlip);
						}
						virtual void clearTransform() {
							_transformer.clearTransform();
						}

					public:
						virtual void sendBeginCommand(IAVSRenderer2* renderer
								, const CAlternate2::CAreaProperties::GeometryProperties& geomPr) {
							IAVSRenderer* pRend = NULL;
							renderer->QueryInterface(__uuidof(IAVSRenderer), (void**)&pRend);
							pRend->BeginCommand(c_nShapeGroup);
							RELEASEINTERFACE(pRend);
						}
						virtual void sendEndCommand(IAVSRenderer2* renderer
								, const CAlternate2::CAreaProperties::GeometryProperties& geomPr) {
							IAVSRenderer* pRend = NULL;
							renderer->QueryInterface(__uuidof(IAVSRenderer), (void**)&pRend);
							pRend->EndCommand(c_nShapeGroup);
							RELEASEINTERFACE(pRend);
						}
					private:
						RectF _OriginArea;

						CArray<CAlternate2::CAltContent> _Alternates;
						CArray<CAlternate2::CAreaProperties> _AreaProperties;
					private:
						void ReadArea(XmlUtils::CXmlNode& groupNode) {
							XmlUtils::CXmlNode node;
							if (groupNode.GetNode(_T("originX"), node))
								_OriginArea.X = XmlUtils::GetFloat(node.GetAttribute(_T("val")));
							if (groupNode.GetNode(_T("originY"), node))
								_OriginArea.Y = XmlUtils::GetFloat(node.GetAttribute(_T("val")));
							if (groupNode.GetNode(_T("originWidth"), node))
								_OriginArea.Width = XmlUtils::GetFloat(node.GetAttribute(_T("val")));
							if (groupNode.GetNode(_T("originHeight"), node))
								_OriginArea.Height = XmlUtils::GetFloat(node.GetAttribute(_T("val")));
						}
						void ReadAlternates(XmlUtils::CXmlNode& groupNode, CDocumentManager& documentManager) {
							XmlUtils::CXmlNodes alternateNodes;
							if (groupNode.GetNodes(_T("fo:alternate-content"), alternateNodes)) {
								int alternatesCount = (int) alternateNodes.GetCount();
								for (int i = 0; i < alternatesCount; ++i) {
									XmlUtils::CXmlNode alternateNode;
									alternateNodes.GetAt(i, alternateNode);
									_Alternates.Add();
									_Alternates[_Alternates.GetCount() - 1].FromXml(alternateNode, documentManager);
									_AreaProperties.Add();
									_AreaProperties[_AreaProperties.GetCount() - 1].FromXml(alternateNode);
								}
							}
						}
					private:
						RectF RelatedRect(CAlternate2::CAltContent& alternate, CAlternate2::CAreaProperties& areaProperty, const RectF& rect) {
							float xOriginToPt = rect.Width / _OriginArea.Width;
							float yOriginToPt = rect.Height / _OriginArea.Height;

							RectF relatedRect = areaProperty.AreaRectPt();

							relatedRect.X = (relatedRect.X*20 - _OriginArea.X)*xOriginToPt + rect.X;
							relatedRect.Y = (relatedRect.Y*20 - _OriginArea.Y)*yOriginToPt + rect.Y;
							relatedRect.Width *= xOriginToPt*20;
							relatedRect.Height *= yOriginToPt*20;

							return relatedRect;
						}
					};
					class CTextC {
					private:
						CFlow* _Flow;
						CArray<CLine*> _Lines;

						RectF _filledRect;
						bool _mustFit;

					public:
						CTextC() 
								: _mustFit(false) {
							_Flow = NULL;
						}
						~CTextC()
						{
							Clear(true);
						}
					public:
						void Clear(const bool& complete = false) {
							if (_Flow != NULL)
								RELEASEOBJECT(_Flow);

							int linesCount = (int) _Lines.GetCount();
							for (int i = 0; i < linesCount; ++i)
								RELEASEOBJECT(_Lines[i]);

							if (!complete)
								_Lines.RemoveAll();
						}
						byte FromXml(XmlUtils::CXmlNode& contentNode, CDocumentManager& documentManager) {
							Clear();
							
							_Flow = new CFlow();
							_Flow->FromXmlNode(contentNode, documentManager);
							_Flow->Static(true);

							readMustFit(contentNode);

							return 0;
						}
						void readMustFit(XmlUtils::CXmlNode& contentNode) {
							CString mustFit = contentNode.GetAttribute(_T("mustFit"));
							_mustFit = mustFit == _T("t");
						}
						void Update(CGrapher* grapher, RectF& rect, float& descent, CAlternate2::CAreaProperties& areaProperties) {
							const float ptToMm	= 25.4f / 72.0f;
							RectF rectMm(0, 0, rect.Width*ptToMm, rect.Height*ptToMm);
							
							CRegion region;
							region.FromRectMm(rectMm);
							CPage page;

							page.StartPrintingFlow();
							_Flow->FillRegion(region, page, grapher);
							_filledRect = region.GetFilledRectPt();

							page.GetLines(_Lines);
							page.FinishPrintingFlow();
						}
					public:
						void MoveOn(const float& deltaX, const float& deltaY) {
							int linesCount = (int) _Lines.GetCount();
							for (int i = 0; i < linesCount; ++i)
								_Lines[i]->MoveOn(deltaX, deltaY);
						}
					public:
						void Draw(IAVSRenderer* renderer, CDocumentManager& documentManager, const RectF& rect, const float& descent, const float& completeness)
						{
							clipOn(renderer, rect);

							MoveOn(rect.X, rect.Y);
							int linesCount = (int) _Lines.GetCount();
							for (int i = 0; i < linesCount; ++i)
								_Lines[i]->Draw(renderer, documentManager, completeness);

							clipOff(renderer);
						}

					public:
						void fitRegionIfNecessary(CAlternate2::CAreaProperties& areaPr) {
							if (_mustFit)
								areaPr.SetAreaRect(_filledRect, true);
						}

					private:
						void clipOn(IAVSRenderer* renderer, const RectF& rectPt) 
						{
							RectF rect = toMm(rectPt);

							renderer->BeginCommand(c_nClipType);
							renderer->BeginCommand(c_nPathType);
							renderer->PathCommandMoveTo(rect.X, rect.Y);
							renderer->PathCommandLineTo(rect.X + rect.Width, rect.Y);
							renderer->PathCommandLineTo(rect.X + rect.Width, rect.Y + rect.Height);
							renderer->PathCommandLineTo(rect.X, rect.Y + rect.Height);
							renderer->PathCommandClose();
							renderer->EndCommand(c_nPathType);
							renderer->EndCommand(c_nClipType);
							renderer->PathCommandEnd();
						}
						void clipOff(IAVSRenderer* renderer) 
						{
							renderer->BeginCommand(c_nResetClipType);
							renderer->EndCommand(c_nResetClipType);
						}
						RectF toMm(const RectF& rect) {
							const float ptToMm = 25.4f / 72.0f;

							RectF rectMm(rect);
							rectMm.X *= ptToMm;
							rectMm.Y *= ptToMm;
							rectMm.Width *= ptToMm;
							rectMm.Height *= ptToMm;

							return rectMm;
						}
					};
					// ### ### ###
					class CBlockInputParameters
					{
					private:
						float	m_SpaceBefore;

					public:
						CBlockInputParameters() : 
						  m_SpaceBefore(0.0f)
						  {
						  }
						  void	Clear()
						  {
							  m_SpaceBefore = 0.0f;
						  }
					public:
						float	SpaceBefore()
						{
							return m_SpaceBefore;
						}
						void	SpaceBefore(const float& spaceBefore)
						{
							m_SpaceBefore = spaceBefore;
						}
					};

					class CCommonBlock {
					public:
						CCommonBlock()
							: m_InTable(false), m_InColumn(false)
						{
						}
						virtual ~CCommonBlock()
						{
						}
					public:
						virtual bool	Empty() const
						{
							return true;
						}
						virtual bool	Complete() const
						{
							return true;
						}
						virtual bool	AtBeginning() const
						{
							return false;
						}
						virtual	bool	AtEnd() const
						{
							return true;
						}
						virtual bool	UsualBlock() const
						{
							return true;
						}
						virtual byte	KeepNext() const
						{
							return 0;
						}
						bool	InTable() const
						{
							return m_InTable;
						}
						void	InTable(const bool& inTable)
						{
							m_InTable = inTable;
						}
						void	InColumn(const bool& inColumn)
						{
							m_InColumn	= inColumn;
						}
						virtual bool transferToNextPage(CGrapher* grapher) {
							Renew(grapher);

							return true;
						}
					public:
						virtual void	InputParams(CBlockInputParameters& inputParams, CDocumentManager& documentManager, const bool& update = false)
						{
							inputParams.Clear();
						}
						virtual void estimateWidth(CGrapher* grapher, float& widthMin, float& widthScore)
						{
							widthMin = 0;
							widthScore = 0;
						}
						virtual void	Renew(CGrapher* grapher, const bool& full = true)
						{
						}
					public:
						virtual bool	FillRegion(CRegion &oRegion, CPage &oPage, const bool& bIsMustRenew, CGrapher* pGrapher)
						{
							return false;
						}

					protected:
						bool	m_InTable;
						bool	m_InColumn;

					protected:
						void addCommandToPage(CPage& page, SharedPtr<RendererCommand>& command
								, const bool& toLast = false) {
							if (!command.isEmpty() && !command->isAdded()) {
								page.addRendererCommand(command, toLast);
								
								command->setAdded(true);
							}
						}
					};

					// ### ###
					class CBlock : public CCommonBlock, private CXmlAttributeReader {
					private:
						class CAlternates
						{
						private:
							CAtlArray<CAlternate2*>	m_Inlines;
							CAtlArray<CAlternate2*>	m_Anchors;

							float	m_RegionOffset;
							bool	m_Added;

						public:
							CAlternates() : 
							  m_Inlines(), m_Anchors(),
								  m_Added(false), 
								  m_RegionOffset(0.0f)
							  {
							  }
							  ~CAlternates()
							  {
								  Clear();
							  }
							  void	Clear()
							  {
								  m_Inlines.RemoveAll();
								  for (int index = 0; index < (int)m_Anchors.GetCount(); ++index)
									  RELEASEOBJECT((m_Anchors[index]));
								  m_Anchors.RemoveAll();
								  m_Added	= false;
								  m_RegionOffset = 0.0f;
							  }
						public:
							CAtlArray<CAlternate2*>&	Inlines()
							{
								return m_Inlines;
							}

							CAtlArray<CAlternate2*>&	Anchors()
							{
								return m_Anchors;
							}

						public:
							bool	HasInlines()
							{
								return (m_Inlines.GetCount() != 0);
							}
							bool	HasAnchors() {
								return (m_Anchors.GetCount() != 0);
							}
							bool isOnlyOneLetter() const {
								if (m_Anchors.GetCount() != 1)
									return false;
								return m_Anchors[0]->isLetter();
							}
							bool	Added() const 
							{
								return m_Added;
							}
						public:
							void	Add(CAlternate2* alternate)
							{
								if (alternate->Inline())
									m_Inlines.Add(alternate);
								else
									m_Anchors.Add(alternate);
							}
							void	Update(CGrapher* grapher)
							{
								for (int index = 0; index < (int)m_Inlines.GetCount(); ++index)
									m_Inlines[index]->UpdateContent(grapher);
								for (int index = 0; index < (int)m_Anchors.GetCount(); ++index)
									m_Anchors[index]->UpdateContent(grapher);
							}
							bool Place(CPage& page, CRegion region, const CBlockAttributes* blockAttrs
									, const RectF& line, const int& position = -1) {
								if (!HasAnchors())
									return true;

								if (m_RegionOffset > 0)
									region.TruncateLeftPt(m_RegionOffset);
								else if (blockAttrs->m_fStartIndent != 0)
									region.TruncateLeftPt(blockAttrs->m_fStartIndent);

								bool fullRelate = true;
								for (int index = 0; index < (int)m_Anchors.GetCount(); ++index)	{
									m_Anchors[index]->Related(false);
									if (!m_Anchors[index]->Placed()) {
										int anchorPosition = m_Anchors[index]->InlinePosition();
										if ((position < 0) || (anchorPosition <= position)) {
											m_Anchors[index]->relate(page, region, line);
											m_Anchors[index]->Related(true);
										}
									}
								}

								page.AddAnchorContent(m_Anchors);
								return fullRelate;
							}
							void	Renew()
							{
								m_Added = false;
								for (int index = 0; index < (int)m_Anchors.GetCount(); ++index)
									m_Anchors[index]->Placed(false);
							}
							void	RegionSettings(CPage& page, CRegion& region) {
								CAreaManager* area = page.GetAreaManager();
								RectF firstLine = region.GetRectPt();
								firstLine.Height = 2.0;
								CArray<RectF> rects;
								area->GetArea(firstLine, rects);
								if (rects.GetCount() != 0) {
									m_RegionOffset = rects[0].X - firstLine.X;
								}
							}
						};

						class CItems
						{
						public:
							enum ENumProcess;
						private:
							enum EPartState {
								EmptyPart = 0, SymbolsInPart, WordInPart
							};
							class CBlockState
							{
							private:
								ENumProcess	m_NumProcess;

							public:
								CBlockState() :
								  m_NumProcess(NumNone)
								  {
								  }
							public:
								void	Renew()
								{
									m_NumProcess = NumProcessed;
								}
							public:
								bool	NumProcess(const ENumProcess& numProcess)
								{
									if (m_NumProcess == NumProcessed)
										return true;
									if ((m_NumProcess == NumAddedWithTab) && (numProcess == NumNone))
									{
										m_NumProcess = NumProcessed;
										return false;
									}
									if (numProcess == NumProcessed)
									{
										m_NumProcess = NumProcessed;
										return true;
									}
									if ((m_NumProcess == NumNone) && (numProcess == NumAdded))
									{
										m_NumProcess = NumAdded;
										return true;
									}
									if ((m_NumProcess == NumAdded) && (numProcess == NumAddedWithTab))
									{
										m_NumProcess = NumAddedWithTab;
										return true;
									}
									return true;
								}
							};
						public:
							enum EBreakType {
								NoneBreak = 0, LineBreak,PageBreak, ColumnBreak
							};

							enum ENumProcess {
								NumNone = 0, NumAdded, NumAddedWithTab, NumProcessed
							};
							struct SPartProperties
							{
								bool	m_BreakBefore;
								bool	m_HeightChanged;
								bool	m_WrapBySymbol;
								bool	m_Force; 
								bool	m_Single;
								int	_items;
								bool	m_RuptureIfSingle;
								EPartState	m_State;
								bool	m_Tab;
								bool _limitTabs;
								EBreakType	m_Break;
								bool _isPpt;
								bool _ignoreWidthLimit;
								bool _firstLine;

								SPartProperties() 
									: m_BreakBefore(false), 
									m_HeightChanged(false), 
									m_WrapBySymbol(false), m_Force(false), m_Single(false), 
									_items(0),
									m_RuptureIfSingle(false), 
									m_State(EmptyPart), 
									m_Tab(false), _limitTabs(false),
									m_Break(NoneBreak),
									_isPpt(false),
									_ignoreWidthLimit(false), 
									_firstLine(false) {
								}
							};
						private:
							CString	m_Text;
							CArray<CItem*>	m_Items;
							CArray<CCharacter*>	m_Characters;

							CBlockState	m_BlockState;

							int m_CurrentItem;
							int	m_CurrentItemFill;
							std::stack<int>	m_CurrentItemsSaved;

							bool	m_Prepared;

							// ##################
							friend class CTextMeasurer;
						private:
							void		Text(const CString& text)
							{
								m_Text = text;
							}
							CString&	Text()
							{
								return m_Text;
							}
							CArray<CItem*>&	Items()
							{
								return m_Items;
							}
							CArray<CCharacter*>&	Characters()
							{
								return m_Characters;
							}
							void	AddText(const CString& text)
							{
								m_Text += text;
							}
							void	AddCharacter(CCharacter* character)
							{
								m_Characters.Add(character);
							}

							CCharacter*	GetCharacter(const int& index)
							{
								return m_Characters[index];
							}
							int		CountCharacters()
							{
								return (int)m_Characters.GetCount();
							}
							// ##################
						private:
							bool	RuptureAndAddToPart(CItem* item, RectF& area, CArray<CItem*>& items, SPartProperties& properties, CGrapher* grapher)
							{
								CItem* newItem = NULL;
								if (item->CanRupture())
									newItem = item->Rupture(area.Width, grapher, properties.m_WrapBySymbol);
								if ((newItem == NULL) && properties.m_WrapBySymbol)
									newItem = item->Rupture(area.Width, grapher, true);
								if (newItem)
								{
									m_Items.InsertAt(m_CurrentItem, newItem);
									AddToPart(newItem, area, items, properties);
									properties.m_State = WordInPart;
									if (newItem->GetType() != Space)
										return true;
									else
										return false;
								}
								else if (properties.m_Single)
								{
									if (properties.m_RuptureIfSingle && item->CanRupture(grapher, area.Width))
									{
										newItem = item->Rupture(area.Width, grapher, true);
										if (newItem != NULL)
										{
											m_Items.InsertAt(m_CurrentItem, newItem);
											AddToPart(newItem, area, items, properties);
											properties.m_State = WordInPart;
											
											return (newItem->GetType() != Space);
										}
									}
									else if (properties.m_RuptureIfSingle && properties._items != 0) {
										return false;
									}
									else if (properties.m_Force || item->GetType() == Alternate || item->IsOneSymbol()) {
										AddToPart(item, area, items, properties);
										properties.m_State = WordInPart;
										return true;
									}
									else if (properties.m_RuptureIfSingle) {
										newItem = item->Rupture(area.Width, grapher, true, true);
										if (newItem != NULL) {
											m_Items.InsertAt(m_CurrentItem, newItem);
											AddToPart(newItem, area, items, properties);
											properties.m_State = WordInPart;
											
											return (newItem->GetType() != Space);
										}
									}
								}
								return false;
							}
							void	AddToPart(CItem* item, RectF& area, CArray<CItem*>& items, SPartProperties& properties)
							{
								assert(!properties.m_HeightChanged);
								if (area.Height == 0) {
									AddToPart(item, area, items);
									++properties._items;
								}
								else
								{
									float height = item->GetHeightPt();
									if (height <= area.Height) {
										++properties._items;
										AddToPart(item, area, items);
									}
									else
									{
										area.Height = height;
										properties.m_HeightChanged = true;
									}
								}
							}
							void	AddToPart(CItem* item, RectF& area, CArray<CItem*>& items)
							{
								float width = item->GetWidthPt();
								area.Width -= width;
								area.X += width;
								items.Add(item);
								++m_CurrentItem;
							}
							void	RemoveLastItemFromPart(RectF& area, CArray<CItem*>& items)
							{
								int lastItem = (int)items.GetCount() - 1;
								float width = items[lastItem]->GetWidthPt();
								area.Width += width;
								area.X -= width;
								items.RemoveAt(lastItem);
								--m_CurrentItem;
							}

							void	UpdatePartState(const CItemType& itemType, SPartProperties& properties, CArray<CItem*>& items)
							{
								if (!properties.m_Single)
									return;
								if (itemType == Alternate) {
									properties.m_State = WordInPart;
									properties.m_Single = false;
									return;
								}
								else if (itemType == LineEnd) {
									properties.m_State = WordInPart;
									properties.m_Single = false;
									return;
								}
								if (properties.m_State == EmptyPart)
								{
									if (itemType == Symbols)
										properties.m_State = SymbolsInPart;
								}
								else if (properties.m_State == SymbolsInPart)
								{
									if (itemType == Space)
									{
										properties.m_State = WordInPart;
										properties.m_Single = false;
									}
								}
							}
							bool	ProcessItem(CItem* item, RectF& area, SPartProperties& properties, CGrapher* grapher)
							{
								bool mustBreak = false;
								CItemType itemType = item->GetType();
								if (itemType == TabStop)
								{
									CTabParams tab = grapher->m_DocumentManager->GetTabSize(area.X);
									((CTabStop*)item)->GetRect().Width	= tab.GetPosition();
									((CTabStop*)item)->m_bLeader		= tab.GetLeader();
									((CTabStop*)item)->m_bType			= tab.GetType();

									float width = item->GetWidthPt();
									if (width == 0)
										mustBreak = true;

									if (width > area.Width)
										properties.m_Tab = true;
								}
								else if (itemType == LineEnd)
								{
									if (((CLineEnd*)item)->GetCharacter()->m_nAdditionalParam == 1)
										properties.m_Break = PageBreak;
									else if (((CLineEnd*)item)->GetCharacter()->m_nAdditionalParam == 2)
										properties.m_Break = ColumnBreak;
									else
										properties.m_Break = LineBreak;
								}

								return mustBreak;
							}
							bool	CheckBreak(CItem* item, RectF& area, CArray<CItem*>& items, SPartProperties& properties)
							{
								if (properties.m_Break == NoneBreak)
									return false;
								else if (properties.m_Break == LineBreak) {
									if (properties._isPpt)
										AddToPart(item, area, items, properties);
									else
										if (items.GetCount() == 0) {
											//AddToPart(item, area, items, properties);
											properties.m_Break = NoneBreak;
											return false;
										}
								}
								else
									AddToPart(item, area, items, properties);

								properties.m_State = WordInPart;
								return true;
							}
							void	RuptureOrRemoveLastSymbolItemsInPart(CItem* item, RectF& area, CArray<CItem*>& items, SPartProperties& properties, CGrapher* grapher)
							{
								CItemType itemType = item->GetType();
								if (itemType != Space && itemType != Alternate) {
									int lastItem = (int)items.GetCount() - 1;
									int lastItemInPart = lastItem;
									while (lastItemInPart >= 0) {
										CItem* currItem = items[lastItemInPart];
										itemType = currItem->GetType();
										if (itemType != Space && itemType != Alternate && itemType != TabStop 
											&& itemType != LineEnd)
											--lastItemInPart;
										else
											break;
									}
									
									if (lastItemInPart > 0)
										for (int i = 0; i < lastItem - lastItemInPart; ++i)
											RemoveLastItemFromPart(area, items);
								}
								else
								{
									while (!AtEnd())
									{
										CItem* currItem = m_Items[m_CurrentItem];
										itemType = currItem->GetType();
										if (itemType == Space)
											++m_CurrentItem;
										else
											break;
									}
								}
							}
							bool	ProcessIfRightTab(CItem* itemTab, RectF& area, CArray<CItem*>& items, SPartProperties& properties, CGrapher* grapher)
							{
								CItemType itemType = itemTab->GetType();
								if (itemType == TabStop)
								{
									if (((CTabStop*)itemTab)->m_bType != 1)
										return false;

									RectF areaTmp = area;
									float tabWidth = ((CTabStop*)itemTab)->GetRect().Width;
									areaTmp.Width = tabWidth;
									((CTabStop*)itemTab)->GetRect().Width = 0;
									AddToPart(itemTab, area, items, properties);

									while (!AtEnd())
									{
										CItem* item = m_Items[m_CurrentItem];
										float width = item->GetWidthPt();
										if (width < areaTmp.Width)
										{
											AddToPart(item, areaTmp, items, properties);
											if (properties.m_HeightChanged)
												break;
										}
										else
											break;
									}

									((CTabStop*)itemTab)->GetRect().Width = areaTmp.Width;
									area.X += tabWidth;
									area.Width -= tabWidth;
									area.Height = areaTmp.Height;
									return true;
								}
								return false;
							}
						public:
							CItems() : 
							  m_Text(_T("")), 
								  m_Items(), m_Characters(), 
								  m_BlockState(), 
								  m_CurrentItem(0), m_CurrentItemFill(0), 
								  m_CurrentItemsSaved(),
								  m_IgnoreNegativeWidth(false),
								  m_Prepared(false)
							  {
							  }
							~CItems()
							  {
								  Clear();
							  }
							void	Clear()
							  {
								  m_Text	= _T("");

								  for (int index = 0; index < (int)m_Items.GetCount(); ++index)
									  RELEASEOBJECT(m_Items[index]);
								  m_Items.RemoveAll();

								  for (int index = 0; index < (int)m_Characters.GetCount(); ++index)
									  RELEASEOBJECT(m_Characters[index]);
								  m_Characters.RemoveAll();

								  m_CurrentItem = 0;
								  m_CurrentItemFill = 0;
								  assert(m_CurrentItemsSaved.empty());

								  m_IgnoreNegativeWidth = false;

								  m_Prepared = false;
							  }
						public:
							bool	m_IgnoreNegativeWidth;
						public:
							bool	IsEmpty() const
							{
								return ((m_Characters.GetCount() == 0) || (m_Text == _T("")));
							}
							bool	IsReady() const
							{
								return (m_Items.GetCount() != 0);
							}

							bool	AtBeginning() const
							{
								return (m_CurrentItem == 0);
							}
							bool	AtEnd() const
							{
								return m_CurrentItem >= (int)m_Items.GetCount() && (IsEmpty() || m_Prepared);
							}
							bool	Prepared() const
							{
								return m_Prepared;
							}
							void	InlineAdded()
							{
								m_BlockState.NumProcess(NumProcessed);
							}
						public:
							void	CurrentItem(const int& currentItem)
							{
								if (!Prepared())
									assert(Prepared());
								m_CurrentItem = currentItem;
							}
							int		CurrentItem()
							{
								assert(Prepared());
								return m_CurrentItem;
							}
							int		Count()
							{
								assert(Prepared());
								return (int)m_Items.GetCount();
							}
							CItem*	operator[](const int& index)
							{
								assert(Prepared());
								return m_Items[index];
							}
						public:
							void	SaveCurrentItem()
							{
								assert(Prepared());
								m_CurrentItemsSaved.push(m_CurrentItem);
							}
							void	RemoveCurrentItem()
							{
								assert(Prepared());
								assert(!m_CurrentItemsSaved.empty());
								m_CurrentItemsSaved.pop();
							}
							void	RestoreCurrentItem()
							{
								assert(Prepared());
								assert(!m_CurrentItemsSaved.empty());
								m_CurrentItem = m_CurrentItemsSaved.top();
								m_CurrentItemsSaved.pop();
							}
							bool	EmptySaves()
							{
								return m_CurrentItemsSaved.empty();
							}
							void	SaveCurrentItemFill()
							{
								m_CurrentItemFill = m_CurrentItem;
							}
							void	Renew(const bool& full = true)
							{
								if (!Prepared())
									return;
								//assert(Prepared());
								for (int index = 0; index < Count(); ++index)
								{
									m_Items[index]->RestoreRect();
									m_Items[index]->SetOnBaseline();
								}
								if (full)
								{
									m_CurrentItem = 0;
									m_CurrentItemFill = 0;
									m_BlockState.Renew();
								}
								else
									m_CurrentItem = m_CurrentItemFill;
							}
						public:
							void	AddItem(const CString& text, CCharacter* character, const ENumProcess& numProcess = NumProcessed)
							{
								assert(!Prepared());
								CString text2 = text;
								character->Transform(text2);
								character->CheckFontRange(text2);
								if (m_BlockState.NumProcess(numProcess))
								{
									m_Text += text2;
									m_Characters.Add(character);
								}
								else
								{
									m_Text = text2 + m_Text;
									m_Characters.InsertAt(0, character);
								}
							}
							void	Prepare(CGrapher* grapher, CBlockAttributes* blockAttributes, CAtlArray<CAlternate2*>& inlines, 
								CAtlArray<CAlternate2*>& anchors, CAtlArray<CFootnote*>& footnotes)
							{
								if (Prepared())
									return;
								grapher->m_DocumentManager->m_ItemManager.PrepareItems(m_Text, blockAttributes, m_Characters, 
									inlines, anchors, footnotes, m_Items, grapher);
								m_Prepared = true;
							}							
						public:
							void	FillArea(RectF& area, CArray<CItem*>& items, SPartProperties& properties, CGrapher* grapher)
							{
								bool first = AtBeginning();
								assert(!properties.m_HeightChanged);
								properties.m_State = EmptyPart;
								while (!AtEnd())
								{
									CItem* item = m_Items[m_CurrentItem];
									if (ProcessItem(item, area, properties, grapher))
										break;
									if (ProcessIfRightTab(item, area, items, properties, grapher))
									{
										if (properties.m_HeightChanged)
											break;
										continue;
									}

									if (CheckBreak(item, area, items, properties))
										break;

									float width = item->GetWidthPt();
									if (m_IgnoreNegativeWidth) {
										m_IgnoreNegativeWidth = false;
										area.Width = width;
									}
									if (width <= area.Width || properties.m_Tab || properties._ignoreWidthLimit) {
										CItemType itemType = item->GetType();
										UpdatePartState(itemType, properties, items);
										AddToPart(item, area, items, properties);
										if (properties.m_HeightChanged)
											break;
									}
									else
									{
										if (!RuptureAndAddToPart(item, area, items, properties, grapher))
											RuptureOrRemoveLastSymbolItemsInPart(item, area, items, properties, grapher);
										break;
									}
								}
								if (!first && properties.m_State == EmptyPart)
									items.RemoveAll();
							}
						};
						class State {
						public:
							static enum EStopPrintReason {
								AnyReason = 0, NotEnoughWidthReason
							};
						
						public:
							EStopPrintReason _stopPrintReason;
							bool _transferedToNextPage;

						public:
							State()
								: _stopPrintReason(AnyReason), 
								_transferedToNextPage(false) {
							}

						public:
							void reset() {
								_stopPrintReason = AnyReason;
								_transferedToNextPage = false;								
							}
						};
						
					private:
						class CComplexFieldChar
						{
						private:
							class CParam
							{
							private:
								CString	m_strName;
								CString	m_strValue;

							public:
								CParam(const CString& strName = _T(""), const CString& strValue = _T(""))
									: m_strName(strName), m_strValue(strValue)
								{
								}
								CParam(const CParam& oSrc)
								{
									m_strName = oSrc.m_strName;
									m_strValue = oSrc.m_strValue;
								}
							public:
								CString& Name()
								{
									return m_strName;
								}
								CString& Value()
								{
									return m_strValue;
								}
							};
							class CCode
							{
							private:
								CString			m_strName;
								CArray<CParam>	m_arrParams;
								bool			m_bIsContent;

							public:
								CCode(const CString& strName, const bool& bIsContent)
									: m_strName(strName), m_arrParams(), 
									m_bIsContent(bIsContent)
								{
								}
								CCode(const CCode& oSrc)
								{
									m_strName = oSrc.m_strName;
									m_arrParams.Copy(oSrc.m_arrParams);
									m_bIsContent = oSrc.m_bIsContent;
								}
							public:
								CString&	Name()
								{
									return m_strName;
								}
								void		AddParam(const CString& strName, const CString& strValue = _T(""))
								{
									CParam oParam(strName, strValue);
									m_arrParams.Add(oParam);
								}
								int			FindParam(const CString& strName)
								{
									int iParamsCount = (int)m_arrParams.GetCount();
									for (int iIndex = 0; iIndex < iParamsCount; ++iIndex)
										if (m_arrParams[iIndex].Name() == strName)
											return iIndex;
									return -1;
								}
								void		SetParam(const int& iIndex, const CString& strValue)
								{
									if (iIndex < 0)
										AddParam(_T("input"), strValue);
									else if (iIndex < (int)m_arrParams.GetCount())
										m_arrParams[iIndex].Value() = strValue;
								}
								CString		GetParam(const int& iIndex)
								{
									if ((iIndex >= 0) && (iIndex < (int)m_arrParams.GetCount()))
										return m_arrParams[iIndex].Value();
									else
										return _T("");
								}
								bool		IsOnlyString()
								{
									return !m_bIsContent;
								}
							};
							class CDateTime
							{
							private:
								SYSTEMTIME	m_oSystemTime;

							public:
								CDateTime()
								{
									GetSystemTime(&m_oSystemTime);
								}
							public:
								CString	GetDateAndTime(const CString& strFormat)
								{
									CString strDateTime = _T(" ");
									DWORD nLength = GetDateFormat(LOCALE_USER_DEFAULT, 0, NULL, strFormat, NULL, 0);
									if (nLength > 0)
									{
										TCHAR *pstrDateTime = new TCHAR[nLength];
										GetDateFormat(LOCALE_USER_DEFAULT, 0, &m_oSystemTime, strFormat,
											pstrDateTime, nLength);
										strDateTime = CString(pstrDateTime);
										RELEASEARRAYOBJECTS(pstrDateTime);
									}
									return strDateTime;
								}
							};
						private:
							CArray<CCode>	m_arrCodes;
							bool	m_isInTOC;
						public:
							byte	m_nState;
						public:
							CString	m_strCommand;
							CString m_strResult;
							int		m_iCodeIndex;
							CAtlArray<CString>	m_arrCommands;
							CCharacter *m_pCharacter;

						public:
							CComplexFieldChar()
								: m_arrCodes(), 
								m_nState(0), 
								m_strCommand(_T("")), m_strResult(_T("")), 
								m_iCodeIndex(-1),
								m_pCharacter(NULL)
							{
								InitCodes();
							}
							~CComplexFieldChar()
							{
								if (m_pCharacter != NULL)
									delete m_pCharacter;
							}
						public:
							bool	ProcessFieldCharNode(XmlUtils::CXmlNode& oFieldCharNode)
							{
								CString strType	= oFieldCharNode.GetAttribute(_T("type"));
								if (strType == _T("begin"))
								{
									Begin();
								}
								else if (strType == _T("separate"))
								{
									Separate();
									/*m_arrCommands.Add(m_strCommand);
									RecountPositionInTOC();*/
								}
								else if (strType == _T("end"))
								{
									End();

									/*size_t nCount = m_arrCommands.GetCount();
									if (nCount > 0)
									{
									m_arrCommands.RemoveAt(nCount - 1);
									}
									m_strCommand = _T("");
									RecountPositionInTOC();*/
								}
								return (m_nState == 0);
							}
							void	ProcessFieldChar()
							{
								if (IsSeparate())
								{
									int spaces = 0;
									for (; spaces < m_strCommand.GetLength(); ++spaces)
										if (m_strCommand[spaces] != _T(' '))
											break;
									m_arrCommands.Add(m_strCommand.Right(m_strCommand.GetLength() - spaces));
									RecountPositionInTOC();
								}
								else if (IsEnd())
								{									
									size_t nCount = m_arrCommands.GetCount();
									if (nCount > 0)
									{
										m_arrCommands.RemoveAt(nCount - 1);
									}
									m_strCommand = _T("");
									RecountPositionInTOC();
									//Parse();
								}
							}
							void	RecountPositionInTOC()
							{
								m_isInTOC = IsIn(_T("TOC"));
							}
							bool	IsIn(CString nameCommand)
							{
								size_t nCount = m_arrCommands.GetCount();
								for (size_t i = 0; i < nCount; ++i)
								{
									if (m_arrCommands[i].Find(nameCommand) != -1)
										return true;
								}
								return false;
							}
							bool	LastIs(CString nameCommand)
							{
								size_t nCount = m_arrCommands.GetCount();
								if (nCount == 0)
									return false;

								return (m_arrCommands[nCount - 1].Find(nameCommand) == 0);									
							}
							bool	IsInTOC()
							{
								return m_isInTOC;
							}							
							void	ProcessInstructionText(XmlUtils::CXmlNode& oInstructionTextNode)
							{
								AddText(oInstructionTextNode.GetTextExt());
							}
							bool	IsInProcess()
							{
								return (m_nState != 0);
							}
							bool	IsInCommandProcess()
							{
								return (m_nState == 1);
							}
							bool	IsInContentProcess()
							{
								return (m_nState == 2);
							}
							void	InCommandProcess()
							{
								m_nState = 1;
							}
							void	InContentProcess()
							{
								m_nState = 2;
							}
							bool	CanFillContent()
							{
								return !(IsIn(_T("PAGE")) && !IsIn(_T("PAGEREF")));
							}
							bool	IsOnlyString()
							{
								if (m_iCodeIndex == -1)
									return true;
								else
									return m_arrCodes[m_iCodeIndex].IsOnlyString();
							}
							CContent*	GetContent(CCharacter* pCharacter)
							{
								if (m_iCodeIndex == 0)
									return CreatePage(pCharacter);
								return NULL;
							}
							CString		GetString(CCharacter* pCharacter)
							{
								if (m_iCodeIndex == 1)
									return CreateMacrobutton(pCharacter);
								else if (m_iCodeIndex == 2)
									return CreateHyperlink(pCharacter);
								else if (m_iCodeIndex == 3)
									return CreateDate(pCharacter);
								pCharacter->m_lCount = 1;
								return _T(" ");
							}
							void	Interrupt()
							{
								m_strCommand = _T("");
								m_strResult = _T("");
								End();
							}
						private:
							void	Begin()
							{
								m_nState = 1;
							}
							bool	IsBegin()
							{
								return (m_nState == 1);
							}
							void	Separate()
							{
								m_nState = 2;
							}
							bool	IsSeparate()
							{
								return (m_nState == 2);
							}
							void	End()
							{
								m_nState = 0;
							}
							bool	IsEnd()
							{
								return (m_nState == 0);
							}
						private:
							void	AddText(const CString& strText)
							{
								if (IsBegin())
									m_strCommand += strText;
								else if (IsSeparate())
									m_strResult += strText;
							}
							void	Parse()
							{
								CString strCode = _T("");
								CString strParams = _T("");
								DetachCodeFromParams(m_strCommand, strCode, strParams);
								m_iCodeIndex	= FindCode(strCode);
								if (m_iCodeIndex != -1)
								{
									ParseParams(strParams);
								}
							}
							void	ParseParams(const CString& strParams)
							{
								int iParamIndex = -1;
								int iStartPos = 0;
								bool bNameNotValue = true;
								bool bCopyTheRest = false;
								int iLength = strParams.GetLength();
								while (iStartPos < iLength)
								{
									if (bNameNotValue)
									{
										int iPrevStartPos = iStartPos;
										iStartPos = FindFirstNotSpace(strParams, iStartPos);
										int iFinishPos = strParams.Find(_T(' '), iStartPos);
										CString strName = strParams.Mid(iStartPos, iFinishPos - iStartPos);
										iParamIndex = m_arrCodes[m_iCodeIndex].FindParam(strName);
										if (iParamIndex != -1)
										{
											iStartPos = iFinishPos;
											bNameNotValue = false;
										}
										else
										{
											iStartPos = iPrevStartPos;
											bNameNotValue = false;
											bCopyTheRest = true;
										}
									}
									else
									{
										if (bCopyTheRest)
										{
											CString strValue = strParams.Mid(iStartPos, iLength - iStartPos);
											m_arrCodes[m_iCodeIndex].SetParam(iParamIndex, strValue);
											break;
										}
										else
										{
											for (; iStartPos < iLength; ++iStartPos)
											{
												if (strParams[iStartPos] != _T(' '))
													break;
											}
											int iFinishPos = iStartPos;
											if (strParams[iStartPos] == _T('"'))
											{
												if (iStartPos == iLength - 1)
												{
													bCopyTheRest = true;
													continue;
												}
												CString strValue;
												iFinishPos = strParams.Find(_T('"'), ++iStartPos);
												if (iFinishPos == 0)
												{
													--iStartPos;
													iFinishPos = iLength;
													strValue = strParams.Mid(iStartPos, iFinishPos - iStartPos);
												}
												else
												{
													strValue = strParams.Mid(iStartPos, iFinishPos - iStartPos);
													++iFinishPos;
												}
												m_arrCodes[m_iCodeIndex].SetParam(iParamIndex, strValue);
												iStartPos = iFinishPos;
											}
											else
											{
												for (; iFinishPos < iLength; ++iFinishPos)
												{
													if (strParams[iFinishPos] == _T(' '))
														break;
												}
												CString strValue = strParams.Mid(iStartPos, iFinishPos - iStartPos);
												m_arrCodes[m_iCodeIndex].SetParam(iParamIndex, strValue);
												iStartPos = iFinishPos;
											}
											bNameNotValue = true;
										}
									}
								}
							}
							bool	IsParsed()
							{
								return (m_nState != 0);
							}
						private:
							int		FindFirstNotSpace(const CString& strText, int iStartIndex = 0)
							{
								int iIndex = iStartIndex;
								for (; iIndex < strText.GetLength(); ++iIndex)
									if (strText[iIndex] != _T(' '))
										break;
								return iIndex;
							}
							void	DetachCodeFromParams(CString strText, CString& strCode, CString& strParams)
							{
								int iCodeStartPosition = FindFirstNotSpace(strText);
								int iFirstAfterCodePosition = strText.Find(_T(" "), iCodeStartPosition);
								bool bCodeWithParams = true;
								if (iFirstAfterCodePosition == -1)
								{
									iFirstAfterCodePosition = strText.GetLength();
									bCodeWithParams = false;
								}
								strCode = strText.Mid(iCodeStartPosition, iFirstAfterCodePosition - iCodeStartPosition);

								if (bCodeWithParams)
								{
									int iParamsStartPosition = FindFirstNotSpace(strText, iFirstAfterCodePosition);
									strParams = strText.Mid(iParamsStartPosition, strText.GetLength() - iParamsStartPosition);
								}
								else
									strParams = _T("");
							}
							int		FindCode(const CString& strCode)
							{
								int iCodesCount = (int)m_arrCodes.GetCount();
								for (int iIndex = 0; iIndex < iCodesCount; ++iIndex)
									if (m_arrCodes[iIndex].Name() == strCode)
										return iIndex;
								return -1;
							}
						private:
							void	InitCodes()
							{
								m_arrCodes.Add(Page());
								m_arrCodes.Add(Macrobutton());
								m_arrCodes.Add(Hyperlink());
								m_arrCodes.Add(Date());
							}
							CCode	Page()
							{
								CCode oPage(_T("PAGE"), true);
								return oPage;
							}
							CContent*	CreatePage(CCharacter* pCharacter)
							{
								CPageNumberC* pPageNumberC = new CPageNumberC(pCharacter);
								return pPageNumberC;
							}
							CCode	Macrobutton()
							{
								CCode oMacrobutton(_T("MACROBUTTON"), false);
								oMacrobutton.AddParam(_T("NoMacro"));
								return oMacrobutton;
							}
							CString		CreateMacrobutton(CCharacter* pCharacter)
							{
								CString strText = _T("");
								int iParamNoMacroIndex = m_arrCodes[m_iCodeIndex].FindParam(_T("NoMacro"));
								if (iParamNoMacroIndex != -1)
								{
									strText += m_arrCodes[m_iCodeIndex].GetParam(iParamNoMacroIndex);
								}
								int iInputParamIndex = m_arrCodes[m_iCodeIndex].FindParam(_T("input"));
								if (iInputParamIndex != -1)
								{
									strText += m_arrCodes[m_iCodeIndex].GetParam(iInputParamIndex);
								}

								pCharacter->m_lCount = strText.GetLength();
								return strText;
							}
							CCode	Hyperlink()
							{
								CCode oHyperlink(_T("HYPERLINK"), false);
								return oHyperlink;
							}
							CString		CreateHyperlink(CCharacter* pCharacter)
							{
								CString strText = _T("");
								int iInputParamIndex = m_arrCodes[m_iCodeIndex].FindParam(_T("input"));
								if (iInputParamIndex != -1)
								{
									strText = m_arrCodes[m_iCodeIndex].GetParam(iInputParamIndex);
								}
								pCharacter->m_oLink.nMode = 2;
								pCharacter->m_oLink.strTarget = strText;
								pCharacter->m_oLink.strTarget.Remove('"');

								pCharacter->m_lCount = m_strResult.GetLength();
								return m_strResult;
							}
							CCode	Date()
							{
								CCode oDate(_T("DATE"), false);
								oDate.AddParam(_T("\\@"));
								return oDate;
							}
							CString		CreateDate(CCharacter* pCharacter)
							{
								CDateTime oDateTime;
								CString strFormat;
								int iParamFormatIndex = m_arrCodes[m_iCodeIndex].FindParam(_T("\\@"));
								if (iParamFormatIndex != -1)
								{
									strFormat = m_arrCodes[m_iCodeIndex].GetParam(iParamFormatIndex);
								}
								CString strDateTime = oDateTime.GetDateAndTime(strFormat);
								pCharacter->m_lCount = strDateTime.GetLength();

								return strDateTime;
							}
						};
						CComplexFieldChar	m_oComplexFieldChar;
						byte				m_nCharState;
					public:
						CBlockAttributes*	m_pBlockAttributes;

						CAlternates	m_Alternates;
						CItems	m_Items;
						State _state;

						CAtlArray<CFootnote*>	m_arrFootnotes;
						int						m_iFootnoteIndex;

						CString	m_strID;
						bool	m_mergeBordersWithNextBlock;
						bool	m_mergeBordersWithPrevBlock;

						bool m_removeSpaceBefore;
						bool m_removeSpaceAfter;
						bool m_IgnoreAnchors;

					private:
						BlockPr _blockPr;

						RCommand _blockStartCommand;
						RCommand _blockEndCommand;
						RCommand pageBreakCommand;

					public:
						CBlock() 
							: CCommonBlock(), 
							m_pBlockAttributes(NULL), 
							m_Alternates(), m_Items(), 
							m_arrFootnotes(), m_iFootnoteIndex(0), 
							m_strID(_T("")), 
							m_oComplexFieldChar(), m_nCharState(0),
							m_IgnoreAnchors(false) {
							m_mergeBordersWithNextBlock = false;
							m_mergeBordersWithPrevBlock = false;

							m_removeSpaceBefore = false;
							m_removeSpaceAfter = false;
						}
						~CBlock()
						{
							Clear();
						}
						void	Clear()
						{
							RELEASEOBJECT(m_pBlockAttributes);

							m_Items.Clear();
							m_Alternates.Clear();

							m_arrFootnotes.RemoveAll();
							m_iFootnoteIndex	= 0;

							m_strID	= _T("");

							m_nCharState	= 0;

							m_mergeBordersWithNextBlock = false;
							m_mergeBordersWithPrevBlock = false;

							m_removeSpaceBefore = false;
							m_removeSpaceAfter = false;
							m_IgnoreAnchors = false;
						}
					public:
						void	FromXmlNode(XmlUtils::CXmlNode& oXmlNode, CDocumentManager& documentManager, CBlockAttributes* pBlockAttributes = NULL, 
							CCharacter* pCharacter = NULL) {
							Clear();
							documentManager.BlockCreated();

							readHeadingLevel(oXmlNode);
							LoadID(oXmlNode);

							if (pBlockAttributes == NULL)
								m_pBlockAttributes	= new CBlockAttributes();
							else
								m_pBlockAttributes	= pBlockAttributes;
							m_pBlockAttributes->FromXmlNode2(oXmlNode);

							CCharacter *pDefaultCharacter = NULL;
							if (pCharacter == NULL)
								pDefaultCharacter	= new CCharacter();
							else {
								pDefaultCharacter	= new CCharacter();
								*pDefaultCharacter	= *pCharacter;
							}
							m_oComplexFieldChar.RecountPositionInTOC();
							pDefaultCharacter->FromXmlNode2(oXmlNode);							

							ProcessNodesWithReader(oXmlNode, pDefaultCharacter, documentManager);
							RELEASEOBJECT(pDefaultCharacter);

							initCommands();
						}
						void	FromXmlNode(XmlUtils::CXmlNode& oXmlNode, CDocumentManager& documentManager, const bool& bIsFirst, bool& inCommandField, CAtlArray<CString>&	curCommands)
						{
							if (inCommandField == true)
								m_oComplexFieldChar.InCommandProcess();
							m_oComplexFieldChar.m_arrCommands.Copy(curCommands);
							m_oComplexFieldChar.RecountPositionInTOC();

							FromXmlNode(oXmlNode, documentManager);
							if (bIsFirst)
							{
								m_pBlockAttributes->m_nBreakBeforeType	= 0;
							}

							if (m_oComplexFieldChar.IsInCommandProcess())
								inCommandField = true;
							else
								inCommandField = false;

							curCommands.Copy(m_oComplexFieldChar.m_arrCommands);
						}
						void	FromString(const CString& text, CGrapher* grapher, const NSStructures::CFont& font, const NSStructures::CBrush& brush, const NSStructures::CFormat& format)
						{
							int length = text.GetLength();
							m_pBlockAttributes = new CBlockAttributes();
							m_pBlockAttributes->m_lCount = length;
							m_pBlockAttributes->m_nTextAlignment = format.StringAlignmentHorizontal;

							CCharacter* character = new CCharacter();
							character->m_lCount = length;
							character->m_oAttributes.m_oFont.FromFont(font);
							character->m_oAttributes.m_oBrush.FromBrush(brush);

							m_Items.AddItem(text, character);
							PrepareItems(grapher);
						}
					public:
						inline bool	Empty()	const
						{
							return m_Items.IsEmpty();
						}
						inline bool	Complete() const {
							return AtEnd() || (Empty() && m_Alternates.Added())
								|| (_state._stopPrintReason == State::NotEnoughWidthReason);
						}
						inline bool	AtBeginning() const
						{
							return m_Items.AtBeginning();
						}
						inline bool	AtEnd() const
						{
							return m_Items.AtEnd();
						}
						inline bool	UsualBlock() const
						{
							return true;
						}
						inline byte KeepNext() const
						{
							return m_pBlockAttributes->m_nKeepNext;
						}
						inline void	IgnoreAnchors(const bool& ignoreAnchors)
						{
							m_IgnoreAnchors = ignoreAnchors;
						}
						void estimateWidth(CGrapher* pGrapher, float& widthMin, float& widthScore)
						{
							if (!m_Items.IsReady())
								PrepareItems(pGrapher);

							float widthMinEstimate = 0;
							float widthMinAddition = 0;

							float indentEstimate = 0;

							float& startIndent = m_pBlockAttributes->m_fStartIndent;
							float& endIndent = m_pBlockAttributes->m_fEndIndent;
							float& textIndent = m_pBlockAttributes->m_fTextIndent;

							if (startIndent > 0) {
								indentEstimate += startIndent;
								widthMinAddition += startIndent;
							}
							if (endIndent > 0) {
								indentEstimate += endIndent;
								widthMinAddition += endIndent;
							}

							widthScore = 0;

							if (textIndent > 0) {
								widthMinEstimate = textIndent;
								widthScore += textIndent;
							}

							int itemsCount = (int) m_Items.Count();
							for (int i = 0; i < itemsCount; ++i) {
								float itemWidth = m_Items[i]->GetRect().Width;
								if (itemWidth > widthMinEstimate)
									widthMinEstimate = itemWidth;
								widthScore += itemWidth;
							}

							widthMin = widthMinEstimate + widthMinAddition;
							widthScore += indentEstimate;
						}
						inline bool transferToNextPage(CGrapher* grapher) {
							if (!_state._transferedToNextPage) {
								Renew(grapher);
								_state._transferedToNextPage = true;

								return true;
							}
							else
								return false;
						}
					public:
						void	InputParams(CBlockInputParameters& inputParams, CDocumentManager& documentManager,  const bool& update = false)
						{
							if (!documentManager.UseHtmlSpacing())
								return;

							if (update)
							{
								m_pBlockAttributes->m_nSpaceBefore += inputParams.SpaceBefore();								
								inputParams.SpaceBefore(m_pBlockAttributes->m_nSpaceAfter);
							}
							else
							{
								// TODO:  ppt   -    
								if (inputParams.SpaceBefore() >= m_pBlockAttributes->m_nSpaceBefore)
								{
									inputParams.SpaceBefore(0.0f);
									m_pBlockAttributes->m_nSpaceBefore = 0.0f;
								}
								else
								{
									m_pBlockAttributes->m_nSpaceBefore -= inputParams.SpaceBefore();
								}
							}
						}
						void	Renew(CGrapher* grapher, const bool& full = true) {
							m_Alternates.Renew();
							m_Items.Renew(full);

							for (size_t nIndex = 0; nIndex < m_arrFootnotes.GetCount(); ++nIndex)
								m_arrFootnotes[nIndex]->Static(true);
							m_iFootnoteIndex = 0;

							m_Alternates.Update(grapher);

							if (full && m_pBlockAttributes->m_nBreakBeforeType < 0)
								m_pBlockAttributes->m_nBreakBeforeType *= -1;
							
							initCommands();
						}
					public:
						bool	FillRegion(CRegion &oRegion, CPage &oPage, const bool& bIsMustRenew, CGrapher* pGrapher) {
							CRegion origRegion = oRegion;
							RectF rectBefore = oRegion.GetFilledRectPt();
							if (m_removeSpaceBefore && m_pBlockAttributes->m_contextualSpacing == _T("true"))
								if (m_removeSpaceBefore)
									m_pBlockAttributes->m_nSpaceBefore = 0;

							if (m_removeSpaceAfter && m_pBlockAttributes->m_contextualSpacing == _T("true"))
								m_pBlockAttributes->m_nSpaceAfter = 0;

							if (CheckBreakBefore(oRegion, oPage))
								return true;

							if (bIsMustRenew)
								m_Alternates.Renew();

							PrepareItems(pGrapher);
							m_Alternates.Update(pGrapher);
							if (AtBeginning())
								m_Alternates.RegionSettings(oPage, oRegion);
							oPage.StartBlock();
							if (m_Items.Prepared())
								addAnchors(oPage, origRegion, m_Items.CurrentItem());
							else
								addAnchors(oPage, origRegion, 0);

							if (m_Items.IsEmpty() && !m_Alternates.HasInlines()) {
								return m_Alternates.HasAnchors();
							}
							if (bIsMustRenew && m_Items.Prepared())
								Renew(pGrapher);

							SetTabStops(oRegion, *pGrapher->m_DocumentManager);

							if (m_InColumn)
								m_Items.SaveCurrentItemFill();

							bool atBeginning = m_Items.AtBeginning();
							bool disableRemoveLastAnchors = pGrapher->m_DocumentManager->GetStaticProcessing();
							bool somePrinted = false;

							preparePrinting();

							if (m_pBlockAttributes->m_pTopSide != NULL && !m_mergeBordersWithPrevBlock)
								oRegion.TrancateRectPt(m_pBlockAttributes->m_pTopSide->m_oPen.m_oPen.Size / 0.3528f);

							if (AtBeginning() && !InTable())
								addCommandToPage(oPage, _blockStartCommand);

							do {
								CLine* line = getLine(oRegion, oPage, pGrapher);

								bool lineBefore = (line != NULL);
								if (lineBefore)
									lineBefore = (line->GetItemsCount() > 1);
								if (CheckBreakBefore(oRegion, oPage, lineBefore))
								{
									if (line) {
										oPage.AddLine(line);
										addAnchors(oPage, origRegion, line->GetRect(), m_Items.CurrentItem());
										somePrinted	= true;
										disableRemoveLastAnchors = true;
									}
									break;
								}
								if (line == NULL) {
									if (!Complete()) {
										oRegion.SetComplete();
										if ((m_pBlockAttributes->m_nKeepTogether) && atBeginning)
											if (somePrinted) {
												oPage.DeleteBlocks(1);
												Renew(pGrapher);
												disableRemoveLastAnchors = true;
											}
										if (!oPage.isWithNonDummyLines())
											disableRemoveLastAnchors = true;
									}
									break;
								}

								oPage.AddLine(line);
								addAnchors(oPage, origRegion, line->GetRect(),m_Items.CurrentItem());
								oRegion.SetProcessing();
								somePrinted = true;
							} while (true);

							if (AtEnd() && !InTable())
								addCommandToPage(oPage, _blockEndCommand, true);

							if (!AtEnd() && !disableRemoveLastAnchors)
								oPage.RemoveAnchorContent(m_Items.CurrentItem());

							RectF rectAfter = oRegion.GetFilledRectPt();

							RectF rectMetrics(rectAfter.GetLeft(), rectBefore.GetBottom(), rectAfter.GetRight() - rectAfter.GetLeft(), rectAfter.GetBottom() - rectBefore.GetBottom());							

							RectF rect = GetRectInRegion(rectMetrics);
							if (!oPage.InFootnoteProcess())	{
								DrawBorder(oPage, rect);
								DrawBackground(oPage, rect);
							}

							return somePrinted;
						}
					private:
						inline bool	Prepared()
						{
							return m_Items.Prepared();
						}
					private:
						RectF   GetRectInRegion(RectF rect)
						{

							double dStartIndent	= (double)m_pBlockAttributes->m_fStartIndent;
							double dEndIndent	= (double)m_pBlockAttributes->m_fEndIndent;
							double dTextIndent	= (double)m_pBlockAttributes->m_fTextIndent;
							double dSpaceAfter	= (double)m_pBlockAttributes->m_nSpaceAfter;
							double dSpaceBefore	= (double)m_pBlockAttributes->m_nSpaceBefore;
							if (dTextIndent < 0)
								dStartIndent += dTextIndent;
							//TODO   
							double dLeft	= rect.GetLeft() + dStartIndent - 4;
							double dRight	= rect.GetRight();
							double dTop		= rect.GetTop();
							double dBottom	= rect.GetBottom();// + 4;
							if (m_mergeBordersWithPrevBlock == false)
								dTop += dSpaceBefore;
							if (m_mergeBordersWithNextBlock == false)
								dBottom -= dSpaceAfter;

							return RectF(dLeft, dTop, dRight - dLeft, dBottom - dTop);
						}
						void	DrawBorder(CPage &oPage, RectF rect)
						{
							if (m_pBlockAttributes->m_pLeftSide != NULL)
							{
								oPage.AddGraphicLine(m_pBlockAttributes->m_pLeftSide->GetGraphicLine(rect.X, rect.Y, 
									rect.X, rect.Y + rect.Height));
							}
							if (m_pBlockAttributes->m_pRightSide != NULL)
							{
								oPage.AddGraphicLine(m_pBlockAttributes->m_pRightSide->GetGraphicLine(rect.X + rect.Width, rect.Y, 
									rect.X + rect.Width, rect.Y + rect.Height));
							}
							if ((m_pBlockAttributes->m_pTopSide != NULL) && !m_mergeBordersWithPrevBlock)
							{
								oPage.AddGraphicLine(m_pBlockAttributes->m_pTopSide->GetGraphicLine(rect.X, rect.Y, 
									rect.X + rect.Width, rect.Y));
							}
							if (m_pBlockAttributes->m_pBottomSide != NULL && !m_mergeBordersWithNextBlock)
							{
								oPage.AddGraphicLine(m_pBlockAttributes->m_pBottomSide->GetGraphicLine(rect.X, rect.Y + rect.Height, 
									rect.X + rect.Width, rect.Y + rect.Height));
							}
						}
						void	DrawBackground(CPage &oPage, RectF rect)
						{
							if (m_pBlockAttributes->m_pRect != NULL)
							{
								oPage.AddBackgroundRect(m_pBlockAttributes->GetBackgroundRect(rect.X, rect.Y, rect.Width, rect.Height));
							}
						}
					private:
						CLine* getLine(CRegion& region, CPage& page, CGrapher* grapher) {
							bool firstLine = false;
							if (AtBeginning()) {
								PrepareItems(grapher);
								firstLine = true;
							}
							else if (m_Items.AtBeginning())
								firstLine = true;
							if (m_Items.AtEnd())
								return NULL;

							grapher->m_DocumentManager->m_ItemManager.SetWrapFlags(m_pBlockAttributes->m_nWrapFlags);
							CAreaManager* areaManager = page.GetAreaManager();

							RectF lineArea = GetRectWithMargins(region.GetRectPt(), firstLine);
							if (!checkArea(lineArea))
								return NULL;

							if (!IgnoreNegativeWidth(lineArea))
								return NULL;

							m_Items.SaveCurrentItem();
							CLine* resultLine = CreateLine(lineArea, areaManager, firstLine, grapher);

							if (resultLine != NULL) {
								ApplyLineHeight(lineArea, resultLine, &grapher->m_DocumentManager->m_ItemManager);
								if (resultLine->IsContainsAlternate() && resultLine->GetHeightPt() > lineArea.Height)
									lineArea.Height = resultLine->GetHeightPt();
								
								float lineHeight = lineArea.Height;
								float lineHeightDelta = lineArea.Height - resultLine->GetHeightPt();
								float truncatedHeight = lineArea.Height + (lineArea.Y - region.GetRectPt().Y);
								if (AtEnd())
									ApplySpaceAfter(lineArea, &grapher->m_DocumentManager->m_ItemManager);

								if (region.GetRectPt().Height >= truncatedHeight || page.IsEmptyBody()
										|| !grapher->m_DocumentManager->m_ItemManager.IsFo()) {
									if (lineHeightDelta < 0) {
										float newDescent = lineHeight * (resultLine->getOriginDescent() / resultLine->GetHeightPt());
										float offset = lineHeightDelta + resultLine->GetDescent() - newDescent;
										resultLine->MoveOn(0, offset);
									}

									region.TrancateRectPt(lineArea.Height + (lineArea.Y - region.GetRectPt().Y));
									m_Items.RemoveCurrentItem();
									if (firstLine && m_strID != _T(""))
										grapher->m_DocumentManager->m_Linker.AddTarget(m_strID, resultLine->GetRect()
												, *grapher->m_DocumentManager);

									if (resultLine->GetFootnoteCount() > 0) {
										CRegion footnoteRegion	= region;

										page.StartFootnote();
										for (int i = 0; i < resultLine->GetFootnoteCount(); ++i) {
											if (m_iFootnoteIndex >= (int) m_arrFootnotes.GetCount())
												break;

											m_arrFootnotes[m_iFootnoteIndex]->FillRegion(footnoteRegion, page, grapher);
											++m_iFootnoteIndex;
										}
										page.FinishFootnote();

										float footnoteHeight = region.GetRegionHeightPt() - footnoteRegion.GetRegionHeightPt();
										region.TruncateHeightPt(footnoteHeight);
										page.changeFootnoteHeight(footnoteHeight);
									}
								}
								else {
									resultLine->RestoreItems();
									RELEASEOBJECT(resultLine);
									m_Items.RestoreCurrentItem();
								}
							}
							else
								m_Items.RemoveCurrentItem();

							return resultLine;
						}
						CLine*	CreateLine(RectF& oLineArea, CAreaManager* pAreaManager, const bool& bIsFirstLine, CGrapher* pGrapher)
						{
							CLine* pResultLine = NULL;
							RectF areaOrigin = oLineArea;

							InitLineArea(oLineArea);
							if (bIsFirstLine)
								ApplySpaceBefore(oLineArea, &pGrapher->m_DocumentManager->m_ItemManager);

							CArray<RectF> arrRests;
							REAL fAvaliableHeight	= pAreaManager->GetArea(oLineArea, arrRests);

							if (arrRests.GetCount() == 0) {
								CLine* line = new CLine();
								line->setDummy(true);
								line->GetRect().Height = oLineArea.Height;
								return line;
							}

							if (fAvaliableHeight < 0)
								pResultLine	= CreateLineInAreaNotWrap(oLineArea, bIsFirstLine, pGrapher);
							else
								pResultLine	= CreateLineInAreaWrap2(oLineArea, areaOrigin, bIsFirstLine, pAreaManager, pGrapher);

							if (pResultLine != NULL)
								pResultLine->MoveOn(arrRests[0].X, oLineArea.Y - pResultLine->GetRect().Y);
							return pResultLine;
						}
					private:
						CLine*	CreateLineInAreaWrap2(RectF& area, const RectF& areaOrigin, const bool& first, CAreaManager* areaManager, CGrapher* grapher)
						{
							CItemManager* itemManager = &grapher->m_DocumentManager->m_ItemManager;
							do
							{
								bool wrap = false;
								CArray<RectF> areas;
								areaManager->GetArea(area, areas);
								int areasCount = (int)areas.GetCount();
								if (areasCount > 0)
								{
									float wrapDelta = areas[0].Width - area.Width;
									if ((wrapDelta > 1) || (wrapDelta < -1))
										wrap = true;
									float offsetX = areas[0].X;
									CArray<CItem*>*	itemsInAreas = new CArray<CItem*>[areasCount];
									CItems::SPartProperties properties;
									properties.m_WrapBySymbol = itemManager->WrapBySymbol();
									properties.m_RuptureIfSingle = (areasCount == 1);
									properties.m_Force = m_InTable;
									m_Items.SaveCurrentItem();
									for (int index = 0; index < areasCount; ++index)
									{
										/*if (areas[index].Width <= 9)
											continue;*/
										properties.m_Single = true;
										FillArea(areas[index], itemsInAreas[index], properties, first, grapher);
										if (properties.m_HeightChanged)
										{
											area.Y = areaOrigin.Y;
											area.Height = areas[index].Height;
											area.Width = areaOrigin.Width;

											if (first)
												ApplySpaceBefore(area, itemManager);
											m_Items.RestoreCurrentItem();
											break;
										}
									}
									if (properties.m_HeightChanged)
									{
										properties.m_HeightChanged = false;
										continue;
									}

									m_Items.RemoveCurrentItem();

									if (properties.m_Break == CItems::PageBreak)
										m_pBlockAttributes->m_nBreakBeforeType = 1;
									else if ((properties.m_Break == CItems::ColumnBreak))
										m_pBlockAttributes->m_nBreakBeforeType = 2;

									if (areasCount == 1)
									{
										CArray<CItem*>& items = itemsInAreas[0];
										int itemsCount = (int)items.GetCount();
										CLine* line	= new CLine();
										for (int index = 0; index < itemsCount; ++index)
											line->AddItem(items[index]);
										if (areas[0].Width > 0)
											line->SetPersistWidth(areas[0].Width);
										line->SetAlign(GetTextAlign(), first, m_Items.AtEnd());
										return line;
									}
									else {
										CCompositeLine* compositeLine = new CCompositeLine();
										for (int index = 0; index < areasCount; ++index)
										{
											CArray<CItem*>& items = itemsInAreas[index];
											int itemsCount = (int)items.GetCount();
											CLine* line = new CLine();
											for (int index2 = 0; index2 < itemsCount; ++index2)
												line->AddItem(items[index2]);

											line->SetPersistWidth(areas[index].Width);
											line->MoveOn(areas[index].X - offsetX, 0.0f);

											compositeLine->AddItem(line);
										}
										compositeLine->SetAlign(GetTextAlign(), first, m_Items.AtEnd());
										return compositeLine;
									}
								}
								else
									return NULL;
							} 
							while (true);
						}
						CLine*	CreateLineInAreaNotWrap(RectF& area, const bool& first, CGrapher* grapher) {
							CArray<CItem*> items;
							RectF areaTmp = area;
							areaTmp.Height = 0;
							CItems::SPartProperties properties;
							properties.m_WrapBySymbol = grapher->m_DocumentManager->m_ItemManager.WrapBySymbol();
							properties.m_Force = m_InTable | !grapher->m_DocumentManager->m_ItemManager.IsFo();
							properties.m_Single = true;
							properties._limitTabs = m_InTable;
							properties.m_RuptureIfSingle = true;
							properties._isPpt = !grapher->m_DocumentManager->m_ItemManager.IsFo();
							properties._ignoreWidthLimit = properties._isPpt && m_pBlockAttributes->_oneLine;
							properties._firstLine = AtBeginning();
							m_Items.FillArea(areaTmp, items, properties, grapher);

							int itemsCount = (int)items.GetCount();
							if (itemsCount != 0)
							{
								if (properties.m_Break == CItems::PageBreak)
									m_pBlockAttributes->m_nBreakBeforeType = 1;
								else if ((properties.m_Break == CItems::ColumnBreak))
									m_pBlockAttributes->m_nBreakBeforeType = 2;

								CLine* line	= new CLine();
								for (int index = 0; index < itemsCount; ++index)
									line->AddItem(items[index]);

								area.Height	= line->GetHeightPt();
								if (areaTmp.Width > 0 || properties._ignoreWidthLimit)
									line->SetPersistWidth(areaTmp.Width);
								line->SetAlign(GetTextAlign(), first, m_Items.AtEnd());
								return line;
							}
							else
								return NULL;
						}
					private:
						void	FillArea(RectF& area, CArray<CItem*>& items, CItems::SPartProperties& properties, const bool& first, CGrapher* grapher)
						{
							RectF areaTmp = area;
							m_Items.FillArea(areaTmp, items, properties, grapher);
							area.Width = areaTmp.Width;
							area.Height = areaTmp.Height;
						}							
						void	InitLineArea(RectF& oLineArea)
						{
							oLineArea.Height	= m_Items[m_Items.CurrentItem()]->GetHeightPt();
						}

						void	SetTabStops(CRegion& oRegion, CDocumentManager& documentManager)
						{
							float fLeftBorder	= oRegion.GetRectPt().X;
							float fRightBorder	= fLeftBorder + oRegion.GetRectPt().Width;
							documentManager.SetDefaultTab(m_pBlockAttributes->m_fDefaultTabSize, fLeftBorder, fRightBorder);
							for (size_t nIndex = 0; nIndex < m_pBlockAttributes->m_arrTabs.GetCount(); ++nIndex)
								documentManager.AddTab(m_pBlockAttributes->m_arrTabs[nIndex]);							
						}
						RectF	GetRectWithMargins(const RectF &oRectF, const bool &bIsFirstLine)
						{
							RectF oRectFWithMargins	= oRectF;
							if (bIsFirstLine == true)
								if ((m_pBlockAttributes->m_pBulletProperties == NULL) || (m_pBlockAttributes->m_fTextIndent < 0))
								{
									oRectFWithMargins.X		+= m_pBlockAttributes->m_fTextIndent;
									oRectFWithMargins.Width	-= m_pBlockAttributes->m_fTextIndent;
								}
								oRectFWithMargins.X		+= m_pBlockAttributes->m_fStartIndent;
								oRectFWithMargins.Width	-= m_pBlockAttributes->m_fStartIndent + m_pBlockAttributes->m_fEndIndent;

								return oRectFWithMargins;
						}
					private:
						void	PrepareItems(CGrapher* grapher)
						{
							//m_Alternates.Update(grapher);
							m_Items.Prepare(grapher, m_pBlockAttributes, m_Alternates.Inlines(), m_Alternates.Anchors(), m_arrFootnotes);
						}

					private:
						void	ProcessNodesWithReader(XmlUtils::CXmlNode& oXmlNode, CCharacter* pDefaultCharacter, CDocumentManager& documentManager)
						{
							XmlUtils::CXmlNodes oNodes;
							if (oXmlNode.GetNodes(_T("*"), oNodes)) {
								INT iListLength	= oNodes.GetCount();

								for (INT iIndex = 0; iIndex < iListLength; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oNodes.GetAt(iIndex, oNode);

									ProcessNode(oNode, pDefaultCharacter, documentManager);
								} 
							}

							if (m_Alternates.HasAnchors() && !m_Alternates.isOnlyOneLetter() && m_Items.IsEmpty()) {
								CCharacter* settings = new CCharacter(*pDefaultCharacter);
								settings->m_lCount = 1;
								m_Items.AddItem(_T(" "), settings);
							}
						}
						void	ProcessNode(XmlUtils::CXmlNode& oNode, CCharacter* pDefaultCharacter, CDocumentManager& documentManager, const bool &bAsInline = false)	{
							CString strNodeName = oNode.GetName();
							if (m_Alternates.HasInlines())
								m_Items.InlineAdded();
							if (strNodeName == _T("field-char"))
							{		
								if (m_oComplexFieldChar.ProcessFieldCharNode(oNode)) {
									if (m_oComplexFieldChar.LastIs(_T("PAGE")) && !m_oComplexFieldChar.LastIs(_T("PAGEREF"))) {
										CCharacter *pCharacter;
										if (m_oComplexFieldChar.m_pCharacter != NULL)
											pCharacter = new CCharacter(*m_oComplexFieldChar.m_pCharacter);
										else
											pCharacter = new CCharacter(*pDefaultCharacter);
										CPageNumberC* pPageNumber	= new CPageNumberC(pCharacter, false);
										CAlternate2* pAlternate		= new CAlternate2();
										pAlternate->Inline(true);
										pAlternate->SetContent(pPageNumber, m_pBlockAttributes->m_lCount);
										m_Alternates.Add(pAlternate);
										if (m_oComplexFieldChar.m_pCharacter != NULL) {
											delete m_oComplexFieldChar.m_pCharacter;
											m_oComplexFieldChar.m_pCharacter = NULL;
										}
									} else if (m_oComplexFieldChar.LastIs(_T("NUMPAGES"))) {
										CCharacter *pCharacter;
										if (m_oComplexFieldChar.m_pCharacter != NULL)
											pCharacter = new CCharacter(*m_oComplexFieldChar.m_pCharacter);
										else
											pCharacter = new CCharacter(*pDefaultCharacter);
										CPageNumberC* pPageNumber	= new CPageNumberC(pCharacter, true);
										CAlternate2* pAlternate		= new CAlternate2();
										pAlternate->Inline(true);
										pAlternate->SetContent(pPageNumber, m_pBlockAttributes->m_lCount);
										m_Alternates.Add(pAlternate);
										if (m_oComplexFieldChar.m_pCharacter != NULL) {
											delete m_oComplexFieldChar.m_pCharacter;
											m_oComplexFieldChar.m_pCharacter = NULL;
										}
									}
								}
								m_oComplexFieldChar.ProcessFieldChar();
								/*if (m_oComplexFieldChar.IsInContentProcess() && (m_oComplexFieldChar.LastIs(_T("PAGE")) && !m_oComplexFieldChar.LastIs(_T("PAGEREF"))))
								{
								CCharacter *pCharacter	= new CCharacter(*pDefaultCharacter);
								CPageNumberC* pPageNumber	= new CPageNumberC(pCharacter, false);
								CAlternate2* pAlternate		= new CAlternate2();
								pAlternate->Inline(true);
								pAlternate->SetContent(pPageNumber, m_pBlockAttributes->m_lCount);
								m_Alternates.Add(pAlternate);	
								}	*/							
							}
							else if (strNodeName == _T("fo:inline"))
							{									
								CCharacter *pCharacter	= new CCharacter(*pDefaultCharacter);
								pCharacter->FromXmlNode3(oNode, m_oComplexFieldChar.IsInTOC());

								if (m_oComplexFieldChar.m_pCharacter == NULL)
									m_oComplexFieldChar.m_pCharacter = new CCharacter(*pCharacter);
								if (!m_oComplexFieldChar.IsInContentProcess() || m_oComplexFieldChar.CanFillContent())
								{
									ProcessNodesWithReader(oNode, pCharacter, documentManager);
									RELEASEOBJECT(pCharacter);
								}
							}
							else if (strNodeName == _T("text"))
							{
								/*if (m_oComplexFieldChar.IsInProcess())
								m_oComplexFieldChar.ProcessInstructionText(oNode);*/
								if (m_oComplexFieldChar.IsInCommandProcess())
									m_oComplexFieldChar.ProcessInstructionText(oNode);
								else if (!m_oComplexFieldChar.IsInContentProcess() || m_oComplexFieldChar.CanFillContent())
								{
									CCharacter *pCharacter	= new CCharacter(*pDefaultCharacter);
									pCharacter->FromXmlNode3(oNode, m_oComplexFieldChar.IsInTOC());
									if (pCharacter->m_lCount != 0)
									{
										m_pBlockAttributes->m_lCount	+= pCharacter->m_lCount;
										m_Items.AddItem(oNode.GetTextExt(), pCharacter);
									}
									else
										RELEASEOBJECT(pCharacter);
								}
							}
							else if (strNodeName == _T("fo:numbering")) {
								CString id = oNode.GetAttribute(_T("id"));
								CString numId = oNode.GetAttribute(_T("numId"));
								int level = oNode.ReadAttributeOrValueInt(_T("level"), -1);
								if (id == _T("") || level == -1)
									return;
								CCharacter* character = new CCharacter(*pDefaultCharacter);
								character->FromXmlNode2(oNode);
								CString numbering = documentManager.getListElement(id, numId, level);
								character->m_lCount = numbering.GetLength();
								if (character->m_lCount != 0) {
									_blockPr.setNumberingLevel(level);

									character->setIsLabel(true);
									m_pBlockAttributes->m_lCount += character->m_lCount;
									m_Items.AddItem(numbering, character, CItems::NumAdded);
								}
								else
									RELEASEOBJECT(character);
							}
							else if (strNodeName == _T("fo:tab"))
							{
								CCharacter *pCharacter = new CCharacter(*pDefaultCharacter);
								pCharacter->m_lCount = 1;
								m_pBlockAttributes->m_lCount += pCharacter->m_lCount;
								m_Items.AddItem(_T("\t"), pCharacter, CItems::NumAddedWithTab);
							}
							else if (strNodeName == _T("fo:leader"))
							{
								if (!m_oComplexFieldChar.IsInCommandProcess()) {
									CCharacter *pCharacter = new CCharacter(*pDefaultCharacter);
									pCharacter->FromXmlNode3(oNode, m_oComplexFieldChar.IsInTOC());
									pCharacter->m_lCount = 1;
									m_pBlockAttributes->m_lCount += 1;
									m_Items.AddItem(_T(" "), pCharacter);
								}
							}
							else if (strNodeName == _T("fo:basic-link"))
							{
								m_oComplexFieldChar.Interrupt();
								CLinkProperties oLink;
								oLink.FromXmlNode2(oNode);
								if (oLink.nMode != 0)
								{
									CLinkProperties oPrevLink	= pDefaultCharacter->m_oLink;
									pDefaultCharacter->m_oLink	= oLink;
									ProcessNodesWithReader(oNode, pDefaultCharacter, documentManager);
									pDefaultCharacter->m_oLink	= oPrevLink;
								}
							}
							else if (strNodeName == _T("fo:break"))
							{
								CCharacter *pCharacter	= new CCharacter(*pDefaultCharacter);
								pCharacter->m_lCount	= 1;
								CString strBreak		= oNode.GetAttributeOrValue(_T("break-before"), _T(""));
								if (strBreak == _T("page"))
									pCharacter->m_nAdditionalParam	= 1;
								else if (strBreak == _T("column"))
									pCharacter->m_nAdditionalParam	= 2;
								if (m_InTable)
									pCharacter->m_nAdditionalParam	= 0;
								m_pBlockAttributes->m_lCount += 1;
								m_Items.AddItem(_T("\n"), pCharacter, CItems::NumNone);
							}
							else if (strNodeName == _T("fo:alternate-content"))
							{
								CAlternate2	*pAlternate	= new CAlternate2();
								if (!pAlternate->FromXml(oNode, documentManager))
								{
									pAlternate->InlinePosition(m_pBlockAttributes->m_lCount);
									m_Alternates.Add(pAlternate);
								}
								else
									RELEASEOBJECT(pAlternate);
							}
							else if (strNodeName == _T("fo:footnote"))
							{
								ProcessNodesWithReader(oNode, pDefaultCharacter, documentManager);
							}
							else if (strNodeName == _T("fo:footnote-body"))
							{
								CFootnote* pFootnote = new CFootnote();
								pFootnote->FromXmlNode(oNode, documentManager);
								pFootnote->SetInlinePosition(m_pBlockAttributes->m_lCount);
								m_arrFootnotes.Add(pFootnote);
							}
							else if (strNodeName == _T("fo:page-number"))
							{
								CCharacter *pCharacter	= new CCharacter(*pDefaultCharacter);
								CPageNumberC* pPageNumber	= new CPageNumberC(pCharacter, false);
								CAlternate2* pAlternate		= new CAlternate2();
								pAlternate->Inline(true);
								pAlternate->SetContent(pPageNumber, m_pBlockAttributes->m_lCount);
								m_Alternates.Add(pAlternate);								
							}
							else if (strNodeName == _T("fo:page-number-citation"))
							{
								CCharacter *pCharacter	= new CCharacter(*pDefaultCharacter);
								CPageNumberC* pPageNumber	= new CPageNumberC(pCharacter, true);
								CAlternate2* pAlternate		= new CAlternate2();
								pAlternate->Inline(true);
								pAlternate->SetContent(pPageNumber, m_pBlockAttributes->m_lCount);
								m_Alternates.Add(pAlternate);
							}
						}
						void	LoadID(XmlUtils::CXmlNode& oXmlNode)
						{
							m_strID	= oXmlNode.GetAttributeOrValue(_T("id"), _T(""));
						}
						void readHeadingLevel(XmlUtils::CXmlNode& blockXml) {
							_blockPr.setHeadingLevel(blockXml.ReadAttributeInt(_T("headingLvl"), 0));
						}
						bool	CreateHyperlink(XmlUtils::CXmlNode& oXmlNode, CLinkProperties& oLink)
						{
							static CString strHyperlink	= _T("HYPERLINK");
							CString strText	= oXmlNode.GetText();
							INT iIndex		= 0;
							while (strText[iIndex] == _T(' '))
							{
								++iIndex;
							}
							INT iIndex2	= 0;
							for (; iIndex2 < 9; ++iIndex2)
							{
								if (strText[iIndex + iIndex2] != strHyperlink[iIndex2])
								{
									break;
								}
							}
							if (iIndex2 == 9)
							{
								INT iPosL	= strText.Find(_T('"'), 0);
								INT iPosR	= -1;
								if (iPosL >= 0)
								{
									++iPosL;
									iPosR	= strText.Find(_T('"'), iPosL);
								}
								if (iPosR >= 0)
								{
									CString strID	= strText.Mid(iPosL, iPosR - iPosL);
									oLink.strTarget		= strID;
								}

								return true;
							}
							else
							{
								return false;
							}
						}
						void addAnchors(CPage& page, CRegion& region, const int& position = -1) {
							RectF line = region.GetRectPt();
							line.Height = 0;
							
							addAnchors(page, region, line, position);
						}
						void addAnchors(CPage& page, CRegion& region, const RectF& line, const int& position = -1) {
							if (!m_IgnoreAnchors)
								m_Alternates.Place(page, region, m_pBlockAttributes, line, position);
						}
					private:
						void preparePrinting() {
							_state._stopPrintReason = State::AnyReason;
						}
					private:
						bool checkArea(const RectF& area) {
							if (area.Width <= 0) {
								_state._stopPrintReason = State::NotEnoughWidthReason;
								return false;
							}

							return true;
						}
						bool	CheckBreakBefore(CRegion& oRegion, CPage &oPage, const bool& lineBefore = false)
						{
							if ((m_pBlockAttributes->m_nBreakBeforeType > 0))
							{
								if (oPage.IsEmptyBody() && !lineBefore) {
									m_pBlockAttributes->m_nBreakBeforeType = 0;
									return false;
								}
								oRegion.SetComplete();
								oRegion.BreakType(m_pBlockAttributes->m_nBreakBeforeType);
								m_pBlockAttributes->m_nBreakBeforeType *= -1;

								addCommandToPage(oPage, pageBreakCommand);

								return true;
							}
							else
								return false;
						}
						CAlignHorizontal	GetTextAlign()
						{
							CAlignHorizontal eTextAlign	= LeftAlign;							
							switch (m_pBlockAttributes->m_nTextAlignment)
							{
							case 1:
								eTextAlign = CenterAlign;
								break;
							case 2:
								eTextAlign = RightAlign;
								break;
							case 3:
								if (!m_Items.AtEnd())
									eTextAlign = WideAlign;
								break;
							}

							return eTextAlign;
						}
						inline void		ApplySpaceBefore(RectF& oLineArea, CItemManager* pItemManager)
						{
							oLineArea.Y += pItemManager->GetPlcOrPxl(m_pBlockAttributes->m_nSpaceBefore, oLineArea.Height);
						}
						inline void		ApplySpaceAfter(RectF& oLineArea, CItemManager* pItemManager)
						{
							oLineArea.Height += pItemManager->GetPlcOrPxl(m_pBlockAttributes->m_nSpaceAfter, oLineArea.Height);
						}
						inline void		ApplyLineHeight(RectF& oLineArea, CLine *pLine, CItemManager* pItemManager)
						{
							if (m_pBlockAttributes->m_fLineHeight != 0)
							{
								if (pLine->IsContainsAlternate())
								{
									REAL fSpaceAfter	= pItemManager->GetPlcOrPxl(m_pBlockAttributes->m_fLineHeight, pLine->GetTextHeight()) - pLine->GetTextHeight();
									oLineArea.Height	+= fSpaceAfter;
								}
								else
								{
									oLineArea.Height = pItemManager->GetPlcOrPxl(m_pBlockAttributes->m_fLineHeight, oLineArea.Height);
								}
							}
							else if ((m_pBlockAttributes->m_nLineSpacing != 0))
							{
								oLineArea.Height = pItemManager->GetPlcOrPxl(m_pBlockAttributes->m_nLineSpacing, oLineArea.Height, 1);
							}
						}
					private:
						bool	IgnoreNegativeWidth(const RectF& area)
						{
							if ((area.Width <= 0) && (!InTable()))
								m_Items.m_IgnoreNegativeWidth = true;
							else
								m_Items.m_IgnoreNegativeWidth = false;
							return true;
						}
					private:
						void initCommands() {
							_blockStartCommand = SharedPtr<RendererCommand>(
									new BlockStartRendererCommand(
									_blockPr.getHeadingLevel(), _blockPr.getNumberingLevel(), 
									m_pBlockAttributes->m_nTextAlignment));
							_blockEndCommand = SharedPtr<RendererCommand>(
									new BlockEndRendererCommand(_blockStartCommand));
							pageBreakCommand = SharedPtr<RendererCommand>(new PageBreakRendererCommand());
						}
					};

					class CTable : public CCommonBlock, private CXmlAttributeReader	{
					private:
						class CCell
						{
						public:
							CFlow	*m_pFlow;

							INT	m_iNumberColumnsSpanned;
							INT	m_iNumberRowsSpanned;
							REAL	m_fWidth;

							INT	m_bCarring;
							bool _negativeRect;

							RectF	m_oRectF;

							CPaddingProperties		m_oPaddingProperties;
							CBorderProperties		m_oBorderProperties;
							CBackgroundProperties	m_oBackgroundProperties;
						
						private:
							float _widthMin;
							float _widthScore;

						public:
							CCell() 
								: m_pFlow(NULL), 
								m_iNumberColumnsSpanned(1), m_iNumberRowsSpanned(1), 
								m_fWidth(0.0f),
								m_bCarring(0), _negativeRect(false), 
								m_oRectF(), 
								m_oPaddingProperties(), m_oBorderProperties(), m_oBackgroundProperties(),
								_widthMin(-1), _widthScore(-1)
							{
							}
							~CCell()
							{
								Clear();
							}
							void	Clear()
							{
								RELEASEOBJECT(m_pFlow);

								m_iNumberColumnsSpanned	= 1;
								m_iNumberRowsSpanned	= 1;
								m_fWidth	= 0.0f;

								m_bCarring	= 0;

								m_oRectF	= RectF();

								m_oPaddingProperties.Clear();
								m_oBackgroundProperties.Clear();
								m_oBorderProperties.Clear();

								_widthMin = -1;
								_widthScore = -1;
							}
						public:
							bool	FromXmlNode(XmlUtils::CXmlNode &oXmlNode, CDocumentManager& documentManager)
							{
								CString strVMerge	= oXmlNode.GetAttributeOrValue(_T("v-merge"), _T("reset"));
								if (strVMerge == _T("continue"))
								{
									Clear();
									return false;
								}

								m_pFlow	= new CFlow();
								m_pFlow->FromXmlNode(oXmlNode, documentManager, TRUE);

								m_iNumberColumnsSpanned	= oXmlNode.ReadAttributeOrValueInt(_T("number-columns-spanned"), 1);
								m_iNumberRowsSpanned	= oXmlNode.ReadAttributeOrValueInt(_T("number-rows-spanned"), 1);

								m_oPaddingProperties.FromXmlNode(oXmlNode);
								m_oBorderProperties.FromXmlNode2(oXmlNode);
								m_oBackgroundProperties.FromXmlNode2(oXmlNode);

								return true;
							}
						public:
							bool	Complete()
							{
								return m_pFlow->Complete() || _negativeRect;
							}
							bool	IsEmpty()
							{
								return m_pFlow->Empty();
							}
							void estimateWidth(CGrapher* grapher, float& widthMin, float& widthScore)
							{
								if ((_widthMin >= 0) || (_widthScore >= 0)) {
									widthMin = _widthMin;
									widthScore = _widthScore;
								}
								else if (m_pFlow) {
									m_pFlow->estimateWidth(grapher, widthMin, widthScore);
								} else {
									widthMin = _widthMin = 0;
									widthScore = _widthScore = 0;
								}
							}							
						public:
							bool	FillRegion(CRegion& region, CPage& page, const bool& isMustRenew, CGrapher* grapher)
							{
								float fSize = 0.0f;
								if (m_oBorderProperties.m_pLeftSide != NULL)
									fSize = (REAL)m_oBorderProperties.m_pLeftSide->m_oPen.m_oPen.Size;

								CBounds oPaddings;
								oPaddings.SetAsMarginPt(m_oPaddingProperties.m_fPaddingLeft + fSize, m_oPaddingProperties.m_fPaddingTop, 
									m_oPaddingProperties.m_fPaddingRight, m_oPaddingProperties.m_fPaddingBottom);

								oPaddings.SetAsRectPt(region.GetRectPt());
								RectF rect = oPaddings.GetRectPt();
								region.SetRect(rect);

								page.beginCell();

								bool result = true;
								if (rect.Width > 0) {
									region.SetReady();
									result = m_pFlow->FillRegion(region, page, grapher);
								}
								else {
									_negativeRect = true;
									region.SetComplete();
								}

								page.endCell();

								return result;
							}							
							void	DrawBorder(CPage &oPage)
							{
								if (m_oBorderProperties.m_pLeftSide != NULL)
								{
									oPage.AddGraphicLine(m_oBorderProperties.m_pLeftSide->GetGraphicLine(m_oRectF.X, m_oRectF.Y, 
										m_oRectF.X, m_oRectF.Y + m_oRectF.Height));
								}
								if (m_oBorderProperties.m_pRightSide != NULL)
								{
									oPage.AddGraphicLine(m_oBorderProperties.m_pRightSide->GetGraphicLine(m_oRectF.X + m_oRectF.Width, m_oRectF.Y, 
										m_oRectF.X + m_oRectF.Width, m_oRectF.Y + m_oRectF.Height));
								}
								if ((m_oBorderProperties.m_pTopSide != NULL) )
								{
									oPage.AddGraphicLine(m_oBorderProperties.m_pTopSide->GetGraphicLine(m_oRectF.X, m_oRectF.Y, 
										m_oRectF.X + m_oRectF.Width, m_oRectF.Y));
								}
								if (m_oBorderProperties.m_pBottomSide != NULL)
								{
									oPage.AddGraphicLine(m_oBorderProperties.m_pBottomSide->GetGraphicLine(m_oRectF.X, m_oRectF.Y + m_oRectF.Height, 
										m_oRectF.X + m_oRectF.Width, m_oRectF.Y + m_oRectF.Height));
								}
								/*/
								oPage.AddGraphicLine(m_oBorderProperties.m_pBottomSide->GetGraphicLine(m_oRectF.X, m_oRectF.Y, 
								m_oRectF.X + m_oRectF.Width, m_oRectF.Y + m_oRectF.Height));
								//*/

								--m_bCarring;
							}
							void	DrawBackground(CPage &oPage)
							{
								if (m_oBackgroundProperties.m_pRect != NULL)
								{
									oPage.AddBackgroundRect(m_oBackgroundProperties.GetBackgroundRect(m_oRectF.X, m_oRectF.Y, m_oRectF.Width, m_oRectF.Height));
								}
							}
						};

					private:
						CAtlArray<float> m_arrColumnWidth;
						bool _colsCalculated;

						CAtlArray<float> m_arrRowHeight;
						INT				m_iColumnCount;
						INT				m_iRowCount;

						REAL			m_fWidth;
						REAL			m_fSummaryWidth;

						INT				m_iCurrentRow;
						INT				m_iPageStartRow;

						CAtlArray<CCell*>	m_arrCells;

						CBlockAttributes _blockAttributes;

						RCommand _tableStartCommand;
						RCommand _tableEndCommand;

					public:
						CTable()
							: CCommonBlock()
							, _colsCalculated(false)
							, m_iColumnCount(0), m_iRowCount(0)
							, m_fWidth(0.0f), m_fSummaryWidth(0.0f)
							, m_iCurrentRow(-1), m_iPageStartRow(0) {
						}
						~CTable() {
							Clear();
						}
						void	Clear() {
							m_arrColumnWidth.RemoveAll();
							m_arrRowHeight.RemoveAll();
							m_iColumnCount	= 0;
							m_iRowCount		= 0;

							m_fWidth		= 0.0f;
							m_fSummaryWidth	= 0.0f;

							m_iCurrentRow	= -1;
							m_iPageStartRow	= 0;

							for (size_t nIndex1 = 0; nIndex1 < m_arrCells.GetCount(); ++nIndex1)
							{
								if (m_arrCells[nIndex1] != NULL)
								{
									for (size_t nIndex2 = nIndex1 + 1; nIndex2 < m_arrCells.GetCount(); ++nIndex2)
									{
										if (m_arrCells[nIndex2] == m_arrCells[nIndex1])
										{
											m_arrCells[nIndex2]	= NULL;
										}
									}
									RELEASEOBJECT(m_arrCells[nIndex1]);									
								}
							}

							m_arrCells.RemoveAll();

							_blockAttributes.Clear();

							initCommands();
						}
					public:
						bool	FromXmlNode(XmlUtils::CXmlNode &oXmlNode, CDocumentManager& documentManager) {
							Clear();
							documentManager.BlockCreated();
							documentManager.SetStaticProcessing(true);

							setCommands(oXmlNode.GetXml());

							m_fWidth = FloatPtAttributeFromXml(oXmlNode, _T("width"), -1.0f);

							m_iCurrentRow	= 0;
							_blockAttributes.FromXmlNode2(oXmlNode);

							if (!TryLoadCols(oXmlNode)) {
								m_iColumnCount = CalculateMaxCols(oXmlNode);
								if (m_iColumnCount > 0)
									m_arrColumnWidth.InsertAt(0, -1.0f, m_iColumnCount);
							}

							XmlUtils::CXmlNode oBodyNode;
							if (oXmlNode.GetNode(_T("fo:table-body"), oBodyNode))
							{
								XmlUtils::CXmlNodes oRowNodes;
								if (oBodyNode.GetNodes(_T("fo:table-row"), oRowNodes))
								{
									m_iRowCount	= oRowNodes.GetCount();
									if (m_iRowCount == 0)
									{
										documentManager.SetStaticProcessing(false);
										return false;
									}

									//m_arrCells.SetCount(m_iColumnCount * m_iRowCount);
									//for (int iIndex = 0; iIndex < (int)m_arrCells.GetCount(); ++iIndex)
									//	m_arrCells[iIndex]	= NULL;
									m_arrCells.InsertAt(0, NULL, m_iColumnCount * m_iRowCount);
										
									for (INT iIndex = 0; iIndex < m_iRowCount; ++iIndex)
									{
										XmlUtils::CXmlNode oRowNode;
										oRowNodes.GetAt(iIndex, oRowNode);
										LoadNewRow(oRowNode, documentManager);

										REAL fRowHeight	= oRowNode.ReadAttributeOrValueFloat(_T("height"), 0);
										m_arrRowHeight.Add(fRowHeight);
									}
								}
							}

							m_iCurrentRow	= 0;
							documentManager.SetStaticProcessing(false);

							return true;
						}
					public:
						bool	Empty()	const
						{
							return (m_iCurrentRow == -1);
						}
						bool	Complete() const
						{
							return (m_iCurrentRow == -1);							
						}
						bool	UsualBlock() const
						{
							return false;
						}
						void estimateWidth(CGrapher* grapher, float& widthMin, float& widthScore)
						{
							widthMin = 0;
							widthScore = 0;

							int rowsCount = m_iRowCount;
							int colsCount = m_iColumnCount;

							int index = 0;
							for (int i = 0; i < rowsCount; ++i) {
								float rowWidthMin = 0;
								for (int j = 0; j < colsCount; ++j) {
									if (!m_arrCells[index])
										continue;

									float cellWidthMin = 0;
									float cellWidthScore = 0;
									m_arrCells[index]->estimateWidth(grapher, cellWidthMin, cellWidthScore);

									rowWidthMin += cellWidthMin;
									widthScore += cellWidthScore;

									++index;
								}
							}
						}
					public:
						void	Renew(CGrapher* pGrapher, const bool& full = true) {
							_colsCalculated = false;
							m_iCurrentRow	= 0;
							m_iPageStartRow	= 0;

							for (size_t nIndex1 = 0; nIndex1 < m_arrCells.GetCount(); ++nIndex1)
								if  ((m_arrCells[nIndex1] != NULL) && (m_arrCells[nIndex1]->m_pFlow != NULL))
									m_arrCells[nIndex1]->m_pFlow->Static(true);

							initCommands();
						}
					public:
						bool	FillRegion(CRegion &oRegion, CPage &oPage, const bool& bIsMustRenew, CGrapher* pGrapher) {
							if (m_fWidth < 0)
								m_fWidth *= -oRegion.GetRectPt().Width;

							if (!InTable())
								addCommandToPage(oPage, _tableStartCommand);
							
							normalizeWidth();

							if (bIsMustRenew)
								Renew(pGrapher);

							CRegion oRegionWithMargins = makeRegionWithSettings(oRegion);

							bool bIsSomePrinted	= false;

							if (!_colsCalculated) {
								calcColsWidths(m_arrColumnWidth, m_fWidth, *pGrapher);
								_colsCalculated = true;
							}

							pGrapher->m_DocumentManager->SetStaticProcessing(true);
							int iPreviousRow = 0;
							while (m_iCurrentRow != -1) {
								iPreviousRow	= m_iCurrentRow;
								oRegion.SetProcessing();

								if (!OutputRow(oRegionWithMargins, oPage, pGrapher)) {
									bIsSomePrinted	= true;
									oRegion.SetComplete();
									break;
								}
							}
							pGrapher->m_DocumentManager->SetStaticProcessing(false);

							if (!InTable() && m_iCurrentRow == -1)
								addCommandToPage(oPage, _tableEndCommand, true);

							m_iPageStartRow	= iPreviousRow;

							oRegion.TrancateRectPt(oRegion.GetRegionHeightPt() - oRegionWithMargins.GetRegionHeightPt());

							return bIsSomePrinted;
						}
					private:
						bool	OutputRow(CRegion &oRegion, CPage &oPage, CGrapher* pGrapher)
						{
							bool bIsCompletePrinted	= true;
							bool bIsSomePrinted		= false;

							REAL fRowHeight	= 0.0f;
							REAL fOffsetX	= 0.0f;

							CAtlArray<CCell*> arrRowCells;
							CAtlArray<CCell*> arrUnrowCells;
							CAtlArray<CCell*> arrLastUnrowCells;

							INT iCurrentCellIndex	= 0;
							INT iRawStartIndex		= m_iCurrentRow * m_iColumnCount;
							CCell *pCell			= NULL;

							while (iCurrentCellIndex < m_iColumnCount)
							{
								pCell				= m_arrCells[iRawStartIndex + iCurrentCellIndex];
								if (!pCell)
								{
									++iCurrentCellIndex;
									continue;
								}

								if (m_arrColumnWidth[iCurrentCellIndex] == 0.0f)
								{
									++iCurrentCellIndex;
									continue;
								}

								BOOL bIsLastRow	= FALSE;
								if (m_iCurrentRow == m_iRowCount - 1)
								{
									bIsLastRow	= TRUE;
								}
								else if (pCell != m_arrCells[iRawStartIndex + m_iColumnCount + iCurrentCellIndex])
								{
									bIsLastRow	= TRUE;
								}

								if (bIsLastRow == TRUE)
								{
									arrRowCells.Add(pCell);
								}
								else
								{
									arrUnrowCells.Add(pCell);
								}

								BOOL bIsDrawing	= FALSE;
								if (m_iCurrentRow == m_iPageStartRow)
								{
									bIsDrawing	= TRUE;
								}
								else if (pCell != m_arrCells[iRawStartIndex - m_iColumnCount + iCurrentCellIndex])
								{
									bIsDrawing	= TRUE;
								}
								else
								{
									arrLastUnrowCells.Add(pCell);
									if (!pCell->Complete())
									{
										bIsDrawing	= TRUE;
									}
								}

								REAL fCellHeight	= 0.0f;

								if (bIsDrawing == TRUE)
								{
									RectF	oCellRect	= oRegion.GetRectPt();
									oCellRect.X			+= fOffsetX;
									oCellRect.Width		= 0.0f;

									while (pCell == m_arrCells[iRawStartIndex + iCurrentCellIndex])
									{
										oCellRect.Width	+= m_arrColumnWidth[iCurrentCellIndex];
										++iCurrentCellIndex;
										if (iCurrentCellIndex == m_iColumnCount)
										{
											break;
										}
									}
									pCell->m_oRectF	= oCellRect;
									CRegion oCellRegion;
									oCellRegion.SetReady();
									oCellRegion.SetRect(oCellRect);
									if (pCell->FillRegion(oCellRegion, oPage, false, pGrapher))
									{
										bIsSomePrinted	= true;
										pCell->m_oRectF.Height	= oRegion.GetRegionHeightPt() - oCellRegion.GetRegionHeightPt();
									}
									else
									{
										pCell->m_oRectF.Height	= 0.0f;
									}

									if (bIsLastRow == TRUE)
									{
										fCellHeight	= pCell->m_oRectF.Height;
									}
									else
									{
										fCellHeight	= 0.0f;
									}
								}
								else 
								{
									iCurrentCellIndex += pCell->m_iNumberColumnsSpanned;

									if (bIsLastRow == TRUE)
									{
										fCellHeight	= pCell->m_oRectF.Height;
									}
								}

								fOffsetX	+= pCell->m_oRectF.Width;

								if (fRowHeight < fCellHeight)
								{
									fRowHeight	= fCellHeight;
								}

								if (!pCell->Complete())
								{
									bIsCompletePrinted	= FALSE;
									pCell->m_bCarring	= 2;
								}
							}

							if (fRowHeight < m_arrRowHeight[m_iCurrentRow])
							{
								fRowHeight	= m_arrRowHeight[m_iCurrentRow];
							}
							if (fRowHeight == 0)
								fRowHeight = 12;

							if (bIsSomePrinted == TRUE)
							{
								for (size_t nIndex = 0; nIndex < arrRowCells.GetCount(); ++nIndex)
								{
									if (bIsCompletePrinted == FALSE)
									{
										arrRowCells[nIndex]->m_bCarring	= 2;
									}
									arrRowCells[nIndex]->m_oRectF.Height	=  fRowHeight + oRegion.GetRectPt().Y - arrRowCells[nIndex]->m_oRectF.Y;
									arrRowCells[nIndex]->DrawBorder(oPage);
									arrRowCells[nIndex]->DrawBackground(oPage);
								}
							}

							if (bIsCompletePrinted == FALSE)
							{
								for (size_t nIndex = 0; nIndex < arrUnrowCells.GetCount(); ++nIndex)
								{
									REAL fFullHeight	= arrUnrowCells[nIndex]->m_oRectF.Height;

									arrUnrowCells[nIndex]->m_oRectF.Height	=  fRowHeight + oRegion.GetRectPt().Y - arrUnrowCells[nIndex]->m_oRectF.Y;
									arrUnrowCells[nIndex]->DrawBorder(oPage);
									arrUnrowCells[nIndex]->DrawBackground(oPage);

									arrUnrowCells[nIndex]->m_oRectF.Height	= 0;
								}
								if (m_iCurrentRow != 0)
								{
									for (size_t nIndex = 0; nIndex < arrLastUnrowCells.GetCount(); ++nIndex)
									{
										arrLastUnrowCells[nIndex]->m_oRectF.Height	= oRegion.GetRectPt().Y - arrLastUnrowCells[nIndex]->m_oRectF.Y;
										arrLastUnrowCells[nIndex]->DrawBorder(oPage);
										arrLastUnrowCells[nIndex]->DrawBackground(oPage);

										arrLastUnrowCells[nIndex]->m_oRectF.Height	= 0;
									}
								}
							}
							else
							{
								for (size_t nIndex = 0; nIndex < arrUnrowCells.GetCount(); ++nIndex)
								{
									arrUnrowCells[nIndex]->m_oRectF.Height	-= fRowHeight;
								}
							}

							oRegion.TrancateRectPt(fRowHeight);

							arrRowCells.RemoveAll();
							arrUnrowCells.RemoveAll();
							arrLastUnrowCells.RemoveAll();

							if (bIsCompletePrinted == TRUE)
							{
								++m_iCurrentRow;
								if (m_iCurrentRow == m_iRowCount)
								{
									m_iCurrentRow	= -1;
								}
							}

							return bIsCompletePrinted;
						}
					private:
						bool	TryLoadCols(XmlUtils::CXmlNode &oXmlNode)
						{
							XmlUtils::CXmlNodes oColumnNodes;
							if (oXmlNode.GetNodes(_T("fo:table-column"), oColumnNodes))
							{
								m_iColumnCount	= oColumnNodes.GetCount();
								if (m_iColumnCount == 0)
								{
									return false;
								}

								for (INT nIndex = 0; nIndex < m_iColumnCount; ++nIndex)
								{
									XmlUtils::CXmlNode oNode;
									oColumnNodes.GetAt(nIndex, oNode);

									REAL fColumnWidth	= FloatPtAttributeFromXml(oNode, _T("column-width"), -1.0f);
									m_fSummaryWidth	+= fColumnWidth;

									m_arrColumnWidth.Add(fColumnWidth);
								}

								m_fWidth	= m_fSummaryWidth;

								return true;
							}

							return false;
						}
						INT		CalculateMaxCols(XmlUtils::CXmlNode &oXmlNode)
						{
							XmlUtils::CXmlNode oBodyNode;
							if (oXmlNode.GetNode(_T("fo:table-body"), oBodyNode))
							{
								XmlUtils::CXmlNodes oRowNodes;
								if (oBodyNode.GetNodes(_T("fo:table-row"), oRowNodes))
								{
									INT iMaxColsCount	= 0;

									INT iRowCount	= oRowNodes.GetCount();
									for (INT iRowIndex = 0; iRowIndex < iRowCount; ++iRowIndex)
									{
										INT iColsCount	= 0;

										XmlUtils::CXmlNode oRowNode;
										oRowNodes.GetAt(iRowIndex, oRowNode);
										XmlUtils::CXmlNodes oCellNodes;
										if (oRowNode.GetNodes(_T("fo:table-cell"), oCellNodes))
										{
											INT iCellCount	= oCellNodes.GetCount();
											for (INT iCellIndex = 0; iCellIndex < iCellCount; ++iCellIndex)
											{
												XmlUtils::CXmlNode oCellNode;
												oCellNodes.GetAt(iCellIndex, oCellNode);

												iColsCount	+= oCellNode.ReadAttributeOrValueInt(_T("number-columns-spanned"), 1);
											}
										}

										if (iColsCount > iMaxColsCount)
										{
											iMaxColsCount	= iColsCount;
										}
									}

									return iMaxColsCount;
								}
							}

							return 0;
						}
						void	LoadNewRow(XmlUtils::CXmlNode &oXmlNode, CDocumentManager& documentManager)
						{
							++m_iCurrentRow;
							INT iCurrentCell	= m_iColumnCount * (m_iCurrentRow - 1);
							int iFreeCellsCount	= m_iColumnCount;

							XmlUtils::CXmlNodes oCellNodes;
							if (oXmlNode.GetNodes(_T("fo:table-cell"), oCellNodes))
							{
								INT iCellCount	= oCellNodes.GetCount();
								iFreeCellsCount	-= iCellCount;
								for (INT iIndex = 0; iIndex < iCellCount; ++iIndex)
								{
									XmlUtils::CXmlNode oCellNode;
									oCellNodes.GetAt(iIndex, oCellNode);

									CCell *pNewCell	= new CCell();
									pNewCell->m_oBorderProperties	= _blockAttributes;
									if (pNewCell->FromXmlNode(oCellNode, documentManager))
									{
										for (; iCurrentCell < m_iColumnCount * m_iCurrentRow; ++iCurrentCell)
										{
											if (m_arrCells[iCurrentCell] == NULL)
												break;
										}
									}
									else
									{
										if (iCurrentCell >= m_iColumnCount * m_iCurrentRow)
										{
											RELEASEOBJECT(pNewCell);
											return;
										}
										if ((m_arrCells[iCurrentCell] == NULL) && (m_iCurrentRow != 1))
										{
											m_arrCells[iCurrentCell]	= m_arrCells[iCurrentCell - m_iColumnCount];
										}
										++iCurrentCell;
										RELEASEOBJECT(pNewCell);
										continue;
									}

									if (iCurrentCell == m_iColumnCount * m_iCurrentRow)
										return;

									if (pNewCell->m_iNumberColumnsSpanned > iFreeCellsCount + 1)
									{
										pNewCell->m_iNumberColumnsSpanned	= iFreeCellsCount + 1;
										iFreeCellsCount	= 0;
									}

									INT iCellIndex	= iCurrentCell;
									for (INT iSpanRowIndex = 0; iSpanRowIndex < pNewCell->m_iNumberRowsSpanned; ++iSpanRowIndex)
									{
										for (INT iSpanColIndex = 0; iSpanColIndex < pNewCell->m_iNumberColumnsSpanned; ++iSpanColIndex)
										{
											m_arrCells[iCellIndex]	= pNewCell;
											iCellIndex++;
										}

										iCellIndex += m_iColumnCount - pNewCell->m_iNumberColumnsSpanned;
									}

									iCurrentCell += pNewCell->m_iNumberColumnsSpanned;
								}
							}
						}
					private:
						CRegion makeRegionWithSettings(const CRegion& region) {
							float widthDelta = region.GetRectPt().Width - m_fWidth;
							float offsetX = calcAlignOffset(widthDelta);
							
							CBounds bounds;
							bounds.SetAsMarginPt(_blockAttributes.m_fStartIndent + offsetX
								, _blockAttributes.m_nSpaceBefore, _blockAttributes.m_fEndIndent, 0.0f);
							
							CRegion regionWithSettings = region;
							regionWithSettings.ChangeRect(bounds);

							return regionWithSettings;
						}

						float calcAlignOffset(const float& widthDelta) {
							switch (_blockAttributes.m_nTextAlignment) {
							case 1:
								return widthDelta / 2;
							case 2:
								return widthDelta;
							}

							return 0;
						}
					private:
						void calcColsWidths(CAtlArray<float>& colsWidths, const float& widthMax
								, CGrapher& grapher) {
							int& colsCount = m_iColumnCount;
							int& rowsCount = m_iRowCount;
							
							CAtlArray<float> colsScores;
							colsScores.InsertAt(0, 1, colsCount);

							CAtlArray<float> colsWidthsMin;
							colsWidthsMin.InsertAt(0, 0, colsCount);

							CAtlArray<float> rowScores;
							rowScores.InsertAt(0, 0, colsCount);

							CAtlArray<float> rowWidthsMin;
							rowWidthsMin.InsertAt(0, 0, colsCount);
							
							for (int row = 0; row < rowsCount; ++row) {
								calcRowWidths(rowWidthsMin, rowScores, row, widthMax,grapher);

								for (int col = 0; col < colsCount; ++col) {
									int colsSpanned = 1;
									while (isSpanned(row, col + colsSpanned, 1))
										++colsSpanned;

									float spanColsWidthMin = rowWidthsMin[col] / colsSpanned;
									float spanColsScore = rowScores[col] / colsSpanned;
									for (int i = col; i < col + colsSpanned; ++i) {
										if (colsWidthsMin[i] < spanColsWidthMin)
											colsWidthsMin[i] = spanColsWidthMin;
										colsScores[i] += spanColsScore;
									}

									col += colsSpanned - 1;
								}
							}

							float width = 0;
							float score = 0;
							int colsAutoCount = 0;
							for (int i = 0; i < colsCount; ++i)
								if (m_arrColumnWidth[i] > 0) {
									width += m_arrColumnWidth[i];
								}
								else {
									width += colsWidthsMin[i];
								score += colsScores[i];
								++colsAutoCount;
								}

							colsWidths.SetCount(colsCount);

							float widthDelta = widthMax - width;
							for (int i = 0; i < colsCount; ++i)
								if (m_arrColumnWidth[i] > 0)
									colsWidths[i] = m_arrColumnWidth[i];
								else {
									colsWidths[i] = colsWidthsMin[i];
								
									float coeff = colsScores[i] / score;
									colsWidths[i] += coeff * widthDelta;
								}
						}

						void calcRowWidths(CAtlArray<float>& colsWidths, CAtlArray<float>& colsScores
								, const int& row, const float& rowWidthMax, CGrapher& grapher) {
							int& colsCount = m_iColumnCount;
							float rowWidth = 0;
							int colsAutoCount = 0;

							for (int i = 0; i < colsCount; ++i) {
								float colWidth = m_arrColumnWidth[i];
								if (colWidth > 0) {
									colsWidths[i] = colWidth;
									rowWidth += colWidth;
								}
								else {
									colsWidths[i] = -1;
									++colsAutoCount;
								}

								colsScores[i] = 0;
							}

							for (int i = 0; i < colsCount; ++i) {
								if (colsWidths[i] != -1)
									continue;
								
								CCell* cell	= m_arrCells[row * colsCount + i];
								if (!cell || isSpanned(row, i)) {
									colsWidths[i] = 0;
									colsScores[i] = 0;
									continue;
								}

								float cellWidth = cell->m_fWidth;
								if (cellWidth > 0) {
									colsWidths[i] = cellWidth;
									rowWidth += cellWidth;

									--colsAutoCount;
								}
								else {
									float widthMin = 0;
									float widthScore = 0;
									cell->estimateWidth(&grapher, widthMin, widthScore);

									colsScores[i] = widthScore;
									
									cellWidth = widthMin;
									if (cellWidth >= 0) {
										colsWidths[i] = -cellWidth;
										rowWidth += cellWidth;
									}
								}
							}
							
							if (colsAutoCount > 0) {
								float colWidthReduction	= (rowWidth - rowWidthMax) / colsAutoCount;
								for (int i = 0; i < colsCount; ++i) {
									if (colsWidths[i] < 0)
										colsWidths[i] = -colsWidths[i];
									if (colWidthReduction > 0)
										colsWidths[i] -= colWidthReduction;
								}
							}
						}

					private:
						bool isSpanned(const int& row, const int& col, const char& type = 0)
						{
							if (row >= m_iRowCount || col >= m_iColumnCount)
								return false;

							bool spanned = false;

							CCell* cell = m_arrCells[row * m_iColumnCount + col];
							if (!cell)
								return false;

							if (row > 0 && type != 1)
								if (cell == m_arrCells[(row - 1) * m_iColumnCount + col])
									spanned = true;

							if (col > 0 && type != 2)
								if (cell == m_arrCells[row * m_iColumnCount + col - 1])
									spanned = true;

							return spanned;
						}
						void normalizeWidth()
						{
							if (m_fWidth <= 0)
								return;

							if (m_fSummaryWidth > m_fWidth)
							{
								REAL fDeltaPct	= m_fWidth / m_fSummaryWidth;

								for (INT iIndex = 0; iIndex < m_iColumnCount; ++iIndex)
								{
									m_arrColumnWidth[iIndex] *= fDeltaPct;
								}

								m_fSummaryWidth	= m_fWidth;
							}
						}
					private:
						void initCommands() {
							if (!_tableStartCommand.isEmpty())
								_tableStartCommand->setAdded(false);
							if (!_tableEndCommand.isEmpty())
								_tableEndCommand->setAdded(false);
						}
						void setCommands(const CString& xml) {
							_tableStartCommand = SharedPtr<RendererCommand>(new TableStartRendererCommand(xml));
							_tableEndCommand = SharedPtr<RendererCommand>(new TableEndRendererCommand());
						}
					};
					// ### ### ###
					class CFlow
					{
					public:
						enum EPosPageType {
							OddPageType = 0, EvenPageType, FirstPageType							
						};
					public:
						CFlow() 
							: m_strName(_T("")), m_Static(false), m_Complete(false), 
							m_arrBlocks(), m_nCurrentBlock(0), 
							m_eTextAlignVertical(FarAlignVert)
						{
						}
						~CFlow()
						{
							Clear();
						}
						void	Clear()
						{
							m_strName = _T("");
							m_Static = false;
							m_Complete = false;

							for (size_t nIndex = 0; nIndex < m_arrBlocks.GetCount(); ++nIndex)
								RELEASEOBJECT(m_arrBlocks[nIndex]);
							m_arrBlocks.RemoveAll();
							m_nCurrentBlock = 0;

							m_eTextAlignVertical = FarAlignVert;
						}
					public:
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode, CDocumentManager& documentManager, const bool& inTable = false)
						{
							m_strName = oXmlNode.GetAttributeOrValue(_T("flow-name"), _T(""));
							m_PageType = ReadPosPageType(oXmlNode);

							XmlUtils::CXmlNodes oNodes;
							if (oXmlNode.GetNodes(_T("*"), oNodes))
							{
								INT iListLenght	= oNodes.GetCount();
								bool bIsFirst	= true;
								bool inCommandField = false;
								CAtlArray<CString>	curCommands;

								for (INT iIndexNode = 0; iIndexNode < iListLenght; ++iIndexNode)
								{
									XmlUtils::CXmlNode oBlockNode;
									oNodes.GetAt(iIndexNode, oBlockNode);

									CString strBlockName = oBlockNode.GetName();									
									if (strBlockName == _T("fo:block"))
									{
										CBlock *pBlock	= new CBlock;
										pBlock->InTable(inTable);
										pBlock->FromXmlNode(oBlockNode, documentManager, bIsFirst, inCommandField, curCommands);
										m_arrBlocks.Add(pBlock);

										bIsFirst = false;
									}
									else if (strBlockName == _T("fo:table"))
									{
										CTable *pTable	= new CTable();
										pTable->InTable(inTable);
										if (pTable->FromXmlNode(oBlockNode, documentManager))
											m_arrBlocks.Add(pTable);
										else
											RELEASEOBJECT(pTable);
									}
								}
							}
						}
					public:
						inline bool	Empty()
						{
							return (m_arrBlocks.GetCount() == 0);
						}
						inline void	Complete(const bool& complete)
						{
							m_Complete = complete;
						}
						inline bool	Complete() const
						{
							return m_Complete;
						}
						inline void	Static(const bool& staticFlow)
						{
							m_Static = staticFlow;
						}
						inline bool	Static() const
						{
							return m_Static;
						}
						inline const CString&	Name() const
						{
							return m_strName;
						}
						inline const EPosPageType	PageType() const
						{
							return m_PageType;
						}
					public:
						void estimateWidth(CGrapher* grapher, float& widthMin, float& widthScore) const
						{
							widthMin = 0;
							widthScore = 0;
							
							int blocksCount = (int) m_arrBlocks.GetCount();
							for (int i = 0; i < blocksCount; ++i) {
								float blockWidthMin = 0;
								float blockWidthScore = 0;
								m_arrBlocks[i]->estimateWidth(grapher, blockWidthMin, blockWidthScore);
								
								if (blockWidthMin > widthMin)
									widthMin = blockWidthMin;
								widthScore += blockWidthScore;
							}
						}
						inline size_t	GetCurrentBlock() const
						{
							return m_nCurrentBlock;
						}
						inline void		SetCurrentBlock(size_t currentBlock, CGrapher* grapher)
						{
							for (size_t nIndex = currentBlock; nIndex < m_arrBlocks.GetCount(); ++nIndex)
								m_arrBlocks[nIndex]->Renew(grapher, false);
							m_nCurrentBlock = currentBlock;
						}
					public:
						bool	FillRegion(CRegion &oRegion, CPage &oPage, CGrapher* pGrapher, const bool& inColumn = false)
						{
							oPage.StartPrintingFlow();

							if (Complete() && !Static())
								return false;
							if (oRegion.IsComplete())
								return false;

							if (Static() && !inColumn)
								m_nCurrentBlock = 0;

							pGrapher->m_DocumentManager->SetBorders(oRegion);

							Complete(true);
							bool somePrinted = false;
							CBlockInputParameters blockParams;
							for (size_t nIndex = m_nCurrentBlock; nIndex < m_arrBlocks.GetCount(); ++nIndex)
							{
								CCommonBlock *pBlock = m_arrBlocks[nIndex];

								if (pBlock->UsualBlock())
								{
									CCommonBlock *pPrevBlock;
									bool mergeWithPrev = false;
									bool removeSpaceBefore = false;
									if (nIndex != 0)
									{
										pPrevBlock = m_arrBlocks[nIndex - 1];
										if (pPrevBlock->UsualBlock())
										{
											mergeWithPrev = ((CBlock*)pPrevBlock)->m_mergeBordersWithNextBlock;
											removeSpaceBefore = ((CBlock*)pPrevBlock)->m_removeSpaceAfter;
										}
									}
									((CBlock*)pBlock)->m_mergeBordersWithPrevBlock = mergeWithPrev;
									((CBlock*)pBlock)->m_removeSpaceBefore		   = removeSpaceBefore;

									CCommonBlock *pNextBlock;
									bool mergeWithNext = false;
									bool removeSpaceAfter = false;
									if (nIndex != m_arrBlocks.GetCount() - 1)
									{
										pNextBlock = m_arrBlocks[nIndex + 1];
										if (pNextBlock->UsualBlock())
										{
											mergeWithNext	 = EqualsAreas(pBlock, pNextBlock);
											removeSpaceAfter = EqualsStyles(pBlock, pNextBlock);
										}
									}
									((CBlock*)pBlock)->m_mergeBordersWithNextBlock = mergeWithNext;
									((CBlock*)pBlock)->m_removeSpaceAfter		   = removeSpaceAfter;
								}

								bool blockSomePrinted = false;
								pBlock->InColumn(inColumn);
								pBlock->InputParams(blockParams, *pGrapher->m_DocumentManager);
								if (pBlock->FillRegion(oRegion, oPage, m_Static, pGrapher))
								{
									blockSomePrinted = true;
									somePrinted = true;
								}
								pBlock->InputParams(blockParams, *pGrapher->m_DocumentManager, true);
								if (pBlock->Complete())
									pGrapher->m_DocumentManager->BlockProcessed();
								else
									Complete(false);

								if (oRegion.IsComplete()) {
									if (nIndex != m_nCurrentBlock) {
										if (!blockSomePrinted && (m_arrBlocks[nIndex - 1]->KeepNext())
											&& oRegion.BreakType() == 0)
											if (m_arrBlocks[nIndex - 1]->transferToNextPage(pGrapher)) {
												oPage.DeleteBlocks(2);
												--nIndex;
											}
									}

									m_nCurrentBlock	= nIndex;
									if (pBlock->Complete())
										++m_nCurrentBlock;
									Complete(false);
									break;
								}

								if (nIndex == m_arrBlocks.GetCount() - 1)
									m_nCurrentBlock = nIndex;
							}

							AlignInRegion(oRegion, oPage, m_eTextAlignVertical);

							return somePrinted;
						}
						void	AlignInRegion(CRegion &oRegion, CPage &oPage, 
							CAlignVertical eTextAlignVertical)
						{
							REAL fOffsetPt = oRegion.GetRegionHeightPt();
							switch(eTextAlignVertical)
							{
							case CenterAlignVert :
								fOffsetPt /= 2;
								break;
							case FarAlignVert :
								fOffsetPt = 0;
								break;
							}

							oPage.MoveFlowOn(0, fOffsetPt);
						}
					public:
						bool	EqualsAreas(CCommonBlock* block1, CCommonBlock* block2)
						{
							CBlockAttributes* blockAttr1 = ((CBlock*)block1)->m_pBlockAttributes;
							CBlockAttributes* blockAttr2 = ((CBlock*)block2)->m_pBlockAttributes;

							if (blockAttr1->m_fStartIndent == ((CBlock*)block2)->m_pBlockAttributes->m_fStartIndent
								&& blockAttr1->m_fEndIndent == blockAttr2->m_fEndIndent
								&& ((blockAttr1->m_oBrush.m_oBrush.Alpha1 != 0 && blockAttr2->m_oBrush.m_oBrush.Alpha1 != 0)
								||(blockAttr1->m_oBrush.m_oBrush.Alpha1 == 0 && blockAttr2->m_oBrush.m_oBrush.Alpha1 == 0))
								&& blockAttr2->GetBorderType() == blockAttr1->GetBorderType())
								return true;
							return false;
						}

						bool	EqualsStyles(CCommonBlock* block1, CCommonBlock* block2)
						{
							if (((CBlock*)block1)->m_pBlockAttributes->m_pStyle == ((CBlock*)block2)->m_pBlockAttributes->m_pStyle)
								return true;
							return false;
						}
					public:
						CAtlArray<CCommonBlock*>&	GetBlocks()
						{
							return m_arrBlocks;
						}
						void	SetAlignVertical(const CAlignVertical& alingVertical)
						{
							m_eTextAlignVertical = alingVertical;
						}

					private:
						CString	m_strName;
						bool	m_Static;
						bool	m_Complete;
						EPosPageType	m_PageType;

						CAtlArray<CCommonBlock*>	m_arrBlocks;
						size_t						m_nCurrentBlock;

						CAlignVertical	m_eTextAlignVertical;

					private:
						EPosPageType	ReadPosPageType(XmlUtils::CXmlNode& flow)
						{
							CString type = flow.GetAttribute(_T("type"), _T("odd"));
							EPosPageType pageType = OddPageType;
							if (type == _T("odd"))
								pageType = OddPageType;
							else if (type == _T("even"))
								pageType = EvenPageType;
							else if (type == _T("first"))
								pageType = FirstPageType;
							return pageType;
						}
					};

					class CFootnote : public CFlow, public CItem
					{
					private:
						INT	m_iInlinePosition;

					public:
						CFootnote()
							: CFlow(), CItem(), 
							m_iInlinePosition(-1)
						{
						}
						~CFootnote()
						{
							Clear();
						}
					public:
						void	Clear()
						{
							m_iInlinePosition	= -1;

							CItem::Clear();
							CFlow::Clear();
						}
						void	FromXmlNode(XmlUtils::CXmlNode& oXmlNode, CDocumentManager& documentManager)
						{
							CFlow::FromXmlNode(oXmlNode, documentManager);
						}
						CItemType	GetType()
						{
							return Footnote;
						}
						INT			GetInilinePosition()
						{
							return m_iInlinePosition;
						}
						void		SetInlinePosition(const INT& iInlinePosition)
						{
							m_iInlinePosition	= iInlinePosition;
						}
						void		SetOnBaseline(const bool& bIsInit = true)
						{
							m_oRect	= RectF(0.0f, 0.0f, 0.0f, 0.0f);
						}
					public:
						bool	FillRegion(CRegion& oRegion, CPage &oPage, CGrapher* pGrapher)
						{
							return CFlow::FillRegion(oRegion, oPage, pGrapher);
						}
						void	Draw(IAVSRenderer *pRenderer, CDocumentManager& documentManager, const float &fCompleteness)
						{
						}
					};

					class CPageSequence {
					private:
						CLayoutMasterSet*		m_pLayoutMasterSet;
						CFlowMap*				m_pFlowMap;
						CPageSequenceMaster*	m_pPageSequenceMaster;

						CPageSequence* _prev;

						CString	m_strMasterReference;

						CAtlArray<CFlow>	m_arrFlows;
						CAtlArray<CFlow>	m_arrStaticContent;

						bool	m_Complete;
						bool	m_reWriteColumns;

					public:
						CPageSequence(CLayoutMasterSet *pLayoutMasterSet = NULL) 
							: m_pLayoutMasterSet(pLayoutMasterSet),
							_prev(NULL),
							m_pFlowMap(NULL), 
							m_pPageSequenceMaster(NULL), 
							m_strMasterReference(_T("")),  
							m_arrFlows(), m_arrStaticContent(), 
							m_Complete(true),
							m_reWriteColumns(true) {
						}
						~CPageSequence()
						  {
							  Clear();
						  }
						void	Clear()
						  {
							  m_pLayoutMasterSet = NULL;
							  m_pFlowMap = NULL;
							  m_pPageSequenceMaster = NULL;

							  m_strMasterReference = _T("");

							  m_arrFlows.RemoveAll();
							  m_arrStaticContent.RemoveAll();

							  m_Complete = true;
							  m_reWriteColumns = true;

							  _prev = NULL;
						  }
					public:
						void	loadFromXml(XmlUtils::CXmlNode& pageSequenceXml, CDocumentManager& documentManager)
						{
							CString strFlowMapName	= pageSequenceXml.GetAttributeOrValue(_T("flow-map-reference"), _T(""));
							m_pFlowMap				= m_pLayoutMasterSet->FindFlowMap(strFlowMapName);

							m_strMasterReference	= pageSequenceXml.GetAttributeOrValue(_T("master-reference"), _T(""));
							m_pPageSequenceMaster	= m_pLayoutMasterSet->FindPageSequenceMaster(m_strMasterReference);

							documentManager.SetStaticProcessing(true);
							XmlUtils::CXmlNodes oStaticContentNodes;
							if (pageSequenceXml.GetNodes(_T("fo:static-content"), oStaticContentNodes))
							{
								INT iCount	= oStaticContentNodes.GetCount();
								for (INT iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oStaticContentNodes.GetAt(iIndex, oNode);
									m_arrStaticContent.Add();
									m_arrStaticContent[iIndex].FromXmlNode(oNode, documentManager);
									m_arrStaticContent[iIndex].Static(true);
								}
							}
							documentManager.SetStaticProcessing(false);

							XmlUtils::CXmlNodes oFlowNodes;
							if (pageSequenceXml.GetNodes(_T("fo:flow"), oFlowNodes))
							{
								INT iCount	= oFlowNodes.GetCount();
								for (INT iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oFlowNodes.GetAt(iIndex, oNode);
									m_arrFlows.Add();
									m_arrFlows[iIndex].FromXmlNode(oNode, documentManager);
								}
							}
						}
					public:
						void	SetLayoutMasterSet(CLayoutMasterSet* layoutMasterSet)
						{
							m_pLayoutMasterSet = layoutMasterSet;
						}
						bool	Continuous()
						{
							CSimplePageMaster* simplePageMaster = m_pLayoutMasterSet->FindSimplePageMaster(GetPageMasterName());
							assert(simplePageMaster != NULL);
							return simplePageMaster->Continuous();
						}
						void	Complete(const bool& complete)
						{
							m_Complete = complete;
						}
						bool	Complete()
						{
							return m_Complete;
						}
					public:
						CPage*	NewPage(CGrapher* grapher, const CPage* prevPage)
						{
							CSimplePageMaster* pageMaster = m_pLayoutMasterSet->FindSimplePageMaster(GetPageMasterName());

							CPage *page = CPage::createNew(prevPage);
							page->SetPageMaster(pageMaster);

							CItemManager* itemManager = &grapher->m_DocumentManager->m_ItemManager;
							itemManager->SetWidthL(page->GetWidthL());
							itemManager->SetHeightL(page->GetHeightL());
							itemManager->SetMultiplierX(page->GetWidthPt());
							itemManager->SetMultiplierY(page->GetHeightPt());

							if (Complete())
								grapher->m_DocumentManager->setPageNumbering(pageMaster->getPageNumbering());

							grapher->m_DocumentManager->nextPage();

							return page;
						}
						void	ContinuePage(CPage& page)
						{
							page.SetPageMaster(m_pLayoutMasterSet->FindSimplePageMaster(GetPageMasterName()));
							page.Continuous(true);
						}
						bool	FillPage(CPage& page, CGrapher* grapher) {
							grapher->m_DocumentManager->SetPage(page);

							if (!page.Continuous()) {
								#ifndef TME_DONT_OUTPUT_HEADER_FOOTER
								addHeaderCommandToPage(page);

								FillHeader(page, grapher);
								FillFooter(page, grapher);

								addHeaderCommandToPage(page, false);
								#endif
								TruncateBody(page);
							}
							else {
								float filledHeight = page.FilledHeight();
								TruncateBodyTop(page, filledHeight);
								TruncateBodyBottom(page, page.getFootnoteHeight());
								float footerHeight = page.FooterHeight();
							}

							FillBody(page, grapher);
							CalculateFilledHeight(page);

							return Complete();
						}
						void	ReWriteColumns(bool flag)
						{
							m_reWriteColumns = flag;
						}
					public:
						CFlow*	GetFirstFlow()
						{
							return &m_arrFlows[0];
						}

					private:
						void	FillBody(CPage& page, CGrapher* grapher)
						{
							Complete(true);
							page.StartBody();
							for (int index = 0; index < (int)m_arrFlows.GetCount(); ++index) {
								CFlow& flow = m_arrFlows[index];
								PrintFlow(page, &flow, grapher);
							}
							page.FinishBody();
						}
						void	FillHeader(CPage& page, CGrapher* grapher) {
							int pageIndex = grapher->m_DocumentManager->getPageIndex();
							FillStatic(page, grapher, _T("xsl-region-before"), PageType(pageIndex));
						}
						void	FillFooter(CPage& page, CGrapher* grapher) {
							int pageIndex = grapher->m_DocumentManager->getPageIndex();
							FillStatic(page, grapher, _T("xsl-region-after"), PageType(pageIndex));
						}
						void	FillStatic(CPage& page, CGrapher* grapher, const CString& name, const CFlow::EPosPageType& pageType)
						{
							grapher->m_DocumentManager->SetStaticProcessing(true);
							bool found = false;
							for (int index = 0; index < (int) m_arrStaticContent.GetCount(); ++index)
							{
								CFlow& flow = m_arrStaticContent[index];
								if ((flow.Name() == name) && (flow.PageType() == pageType))
								{
									PrintFlow(page, &flow, grapher);
									found = true;
									break;
								}
							}
							if (!found) {
								if (!FillStatic(page, grapher, name) && _prev != NULL)
									_prev->FillStatic(page, grapher, name, pageType);

							}
							grapher->m_DocumentManager->SetStaticProcessing(false);
						}

						bool FillStatic(CPage& page, CGrapher* grapher, const CString& name)
						{
							bool found = false;

							grapher->m_DocumentManager->SetStaticProcessing(true);
							for (int index = 0; index < (int) m_arrStaticContent.GetCount(); ++index)
							{
								CFlow& flow = m_arrStaticContent[index];
								if ((flow.Name() == name) && (flow.PageType() == CFlow::OddPageType)) {
									found = true;
									PrintFlow(page, &flow, grapher);
									break;
								}
							}
							grapher->m_DocumentManager->SetStaticProcessing(false);

							return found;
						}
					private:
						void	PrintFlow(CPage& oPage, CFlow* pFlow, CGrapher* pGrapher)
						{
							CAtlArray<CString> arrRegionNames;
							GetRegionNames(pFlow->Name(), arrRegionNames);

							for (size_t nRegionIndex = 0; nRegionIndex < arrRegionNames.GetCount(); ++nRegionIndex)
							{
								CString name = arrRegionNames[nRegionIndex];
								if (name == _T("xsl-region-after"))
									pFlow->SetAlignVertical(NearAlignVert);
								size_t iLength;
								double dSizeBlocksInColumns	 = 0;
								double dWidthBlocksInColumns = 0;
								size_t sBlockInBeginColumns = 0;
								size_t sLineInBeginColumns = 0;
								size_t sFirstColumn;
								int footLineInBeginColumns = 0;
								int graphLineInBeginColumns = 0;
								int backgroundInBeginColumns = 0;
								bool completeRegions = false;
								CRegion **ppRegion	= oPage.GetRegions(arrRegionNames[nRegionIndex], iLength);
								if (ppRegion != NULL) {	
									addColumnCommandToPage(oPage, (int) iLength);

									size_t i = 0;
									for (size_t i = 0; i < iLength;i++)
									{
										CRegion *pRegion = ppRegion[i];
										if (pRegion != NULL)
										{
											if (!pRegion->IsComplete())
											{
												if (pRegion->IsColumn() && (i == 0 || !ppRegion[i -1]->IsColumn()))
												{
													sBlockInBeginColumns = pFlow->GetCurrentBlock();
													sLineInBeginColumns = oPage.GetLastLine();
													graphLineInBeginColumns = oPage.GetLastGraphLine();
													backgroundInBeginColumns = oPage.GetLastBackground();
													sFirstColumn = i;
												}

												if (!pRegion->IsColumn())
												{
													pFlow->FillRegion(*pRegion, oPage, pGrapher);
													if (pRegion->BreakType() == 1)
														completeRegions = true;
												}
												else
												{
													if (completeRegions)
														continue;
													if (i == 0)
														pFlow->FillRegion(*pRegion, oPage, pGrapher, true);
													else
														pFlow->FillRegion(*pRegion, oPage, pGrapher);
													if (pRegion->BreakType() == 1)
														completeRegions = true;
													double dWidth = pRegion->GetFilledWidth();
													float delta = 0;
													float filledHeight = oPage.FilledHeight();
													float top = pRegion->GetOriginalRectPt().GetTop();
													if (filledHeight > top)
														delta = filledHeight - top;
													dSizeBlocksInColumns  += (pRegion->GetFilledHeight() - delta) * dWidth;
													dWidthBlocksInColumns += dWidth;
													if (pFlow->Complete() && m_reWriteColumns)
													{
														size_t sLastColumn;
														double dHeightRegion = pRegion->GetOriginalRectPt().GetBottom() - top - delta;
														dWidthBlocksInColumns += GetWidthNextColumns(ppRegion, iLength, i, sLastColumn);
														double dNewHeight = dSizeBlocksInColumns / dWidthBlocksInColumns;
														bool flowIsEmpty = false;
														int iStep = 5;														

														do
														{
															pFlow->Complete(false);
															oPage.ClearDerivedLines((int) sLineInBeginColumns);
															oPage.ClearDerivedGraphLines(graphLineInBeginColumns);
															oPage.ClearDerivedBackgrounds(backgroundInBeginColumns);
															pFlow->SetCurrentBlock(sBlockInBeginColumns, pGrapher);
															ReWriteColumns(ppRegion, sFirstColumn, sLastColumn, dNewHeight, pFlow, oPage, pGrapher);
															flowIsEmpty = pFlow->Complete();
															if (flowIsEmpty == false)
																dNewHeight += iStep;
															else
																break;
														}
														while (dNewHeight <= dHeightRegion);
														i = sLastColumn;
													}
												}
											}
										}
										else
										{
											break;
										}
									}
									if (!pFlow->Complete())
										Complete(false);
								}
								RELEASEARRAYOBJECTS(ppRegion);
							}
						}
						double  GetWidthNextColumns(CRegion **ppRegion, size_t iLength, size_t position, size_t& sLastColumn)
						{
							double dWidth = 0;
							size_t i;
							for(i = position  + 1; i < iLength; i++)
							{
								CRegion *pRegion = ppRegion[i];
								if (pRegion != NULL && pRegion->IsColumn())
								{
									dWidth += pRegion->GetFilledWidth();
								}
								else 
								{
									sLastColumn = i - 1;
									break;
								}
							}
							if (i == iLength )
								sLastColumn = iLength - 1;
							return dWidth;
						}
						void	ReWriteColumns(CRegion **ppRegion, size_t sFirstColumn, size_t sLastColumn, double dNewHeight, CFlow* pFlow, CPage& oPage, CGrapher* pGrapher, const float& prevSectionBottom = 0.0f)
						{
							bool completeRegions = false;
							for (size_t i = sFirstColumn; i <= sLastColumn; i++)
							{
								CRegion *pRegion = ppRegion[i];
								if (completeRegions)
									continue;
								if (pRegion != NULL)
								{
									pRegion->SetComplete();
									pRegion->CheckRect();
									float filledHeight = oPage.FilledHeight();
									float deltaY = filledHeight - pRegion->GetRectPt().GetTop();
									if (deltaY > 0)
										pRegion->TrancateRectPt(deltaY);
									pRegion->TruncateHeightPt(pRegion->GetRectPt().GetBottom() - pRegion->GetRectPt().GetTop() - dNewHeight);

									pFlow->FillRegion(*pRegion, oPage, pGrapher);
									if (pRegion->BreakType() == 1)
										completeRegions = true;
								}
							}
						}						
					private:
						void	TruncateBody(CPage& page)
						{
							CRegion* regionBefore = page.GetRegion(_T("xsl-region-before"));
							if ((regionBefore != NULL) && !regionBefore->IsReady())
							{
								float headerBottom = regionBefore->GetRectPt().GetTop();
								TruncateBodyTop(page, headerBottom);
							}
							CRegion* regionAfter = page.GetRegion(_T("xsl-region-after"));
							if ((regionAfter != NULL) && !regionAfter->IsReady())
							{
								float footerHeightEmpty = regionAfter->GetRectPt().GetBottom() - regionAfter->GetRectPt().GetTop();
								float footerTop = regionAfter->GetOriginalRectPt().GetTop() + footerHeightEmpty;
								TruncateBodyBottom(page, footerTop, true);
							}
						}
						void	TruncateBodyTop(CPage& page, const float& y)
						{
							size_t count = 0;
							CRegion** bodyRegions = page.GetRegions(_T("xsl-region-body"), count);
							for (int i = 0; i < (int)count; ++i)
								if (bodyRegions[i])
								{
									float bodyTop = bodyRegions[i]->GetRectPt().GetTop();
									float deltaY = y - bodyTop;
									if (deltaY > 0)
										bodyRegions[i]->TrancateRectPt(deltaY);
								}
								delete[] bodyRegions;
						}
						void	TruncateBodyBottom(CPage& page, const float& y, bool bSaveFooterPos = false)
						{
							size_t count = 0;
							CRegion** bodyRegions = page.GetRegions(_T("xsl-region-body"), count);
							for (int i = 0; i < (int) count; ++i)
								if (bodyRegions[i])
								{
									float bodyBottom = bodyRegions[i]->GetRectPt().GetBottom();
									float deltaY = bodyBottom - y;
									if (deltaY > 0)
									{
										bodyRegions[i]->TruncateHeightPt(deltaY);
										if (bSaveFooterPos == true)
											page.FooterHeight(y);
									}
								}
							delete[] bodyRegions;
						}
						void	CalculateFilledHeight(CPage& page)
						{
							float filledHeight = page.FilledHeight();
							size_t count = 0;
							CRegion** bodyRegions = page.GetRegions(_T("xsl-region-body"), count);
							for (int i = 0; i < (int) count; ++i)
								if (bodyRegions[i])
								{
									float bodyTop = bodyRegions[i]->GetRectPt().GetTop();
									if (bodyTop > filledHeight)
										filledHeight = bodyTop;
								}
								delete[] bodyRegions;
								page.FilledHeight(filledHeight);
						}
					private:
						void	GetRegionNames(const CString &strFlowName, CAtlArray<CString> &arrRegionNames)
						{
							if (m_pFlowMap != NULL)
							{
								m_pFlowMap->GetRegionNames(strFlowName, arrRegionNames);
							}
							if (arrRegionNames.GetCount() == 0)
							{
								arrRegionNames.Add(strFlowName);
							}
						}
						CString	GetPageMasterName()
						{
							if (m_pPageSequenceMaster != NULL)
							{
								return m_pPageSequenceMaster->GetPageMasterName();
							}
							else
							{
								return m_strMasterReference;
							}
						}
						CFlow::EPosPageType	PageType(const int& pageIndex) const
						{
							if (pageIndex % 2 == 0)
								return CFlow::EvenPageType;
							else if (pageIndex == 1)
								return CFlow::FirstPageType;
							else
								return CFlow::OddPageType;
						}

					public:
						void setPrev(CPageSequence* prev) {
							_prev = prev;
						}
					private:
						void addHeaderCommandToPage(CPage& page, const bool& beginCommand = true) {
							RCommand command;
							if (beginCommand)
								command = SharedPtr<RendererCommand>(new HeaderStartRendererCommand());
							else
								command = SharedPtr<RendererCommand>(new HeaderEndRendererCommand());
							page.addRendererCommand(command, !beginCommand);
						}
						void addColumnCommandToPage(CPage& page, const int columnCount) {
							page.addRendererCommand(
									SharedPtr<RendererCommand>(new ColumnCountRendererCommand(columnCount)));
						}
					};

					class CPageMasterAlternatives
					{
					public:
						CString	m_strOddPageMasterReference;
						CString	m_strEvenPageMasterReference;

					public:
						// ---
						CPageMasterAlternatives() 
							: m_strOddPageMasterReference(_T("")), 
							m_strEvenPageMasterReference(_T(""))
						{
						}
						CPageMasterAlternatives(const CPageMasterAlternatives &oSrc)
						{
							m_strOddPageMasterReference		= oSrc.m_strOddPageMasterReference;
							m_strEvenPageMasterReference	= oSrc.m_strEvenPageMasterReference;
						}
						// ---
						~CPageMasterAlternatives()
						{
							Clear();
						}
						// ---
						void	Clear()
						{
							m_strOddPageMasterReference		= _T("");
							m_strEvenPageMasterReference	= _T("");
						}
						// ---
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
							XmlUtils::CXmlNodes oPageMasterReferenceNodes;
							if (oXmlNode.GetNodes(_T("fo:conditional-page-master-reference"), oPageMasterReferenceNodes))
							{
								INT iCount	= oPageMasterReferenceNodes.GetCount();
								for (INT iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oPageMasterReferenceNode;
									oPageMasterReferenceNodes.GetAt(iIndex, oPageMasterReferenceNode);
									CString strOddOrEven	= oPageMasterReferenceNode.GetAttributeOrValue(_T("odd-or-even"), _T(""));
									if (strOddOrEven == _T("odd"))
									{
										m_strOddPageMasterReference	= oPageMasterReferenceNode.GetAttributeOrValue(_T("master-reference"), _T(""));
									}
									else if (strOddOrEven == _T("even"))
									{
										m_strEvenPageMasterReference	= oPageMasterReferenceNode.GetAttributeOrValue(_T("master-reference"), _T(""));
									}
								}
							}
						}

					};
					class CPageSequenceMaster
					{
					public:
						CString	m_strName;

						CAtlArray<CPageMasterAlternatives>	m_arrPageMasterAlternatives;

					public:
						// ---
						CPageSequenceMaster() 
							: m_strName(_T("")), 
							m_arrPageMasterAlternatives()
						{
						}
						CPageSequenceMaster(const CPageSequenceMaster &oSrc)
						{
							m_strName	= oSrc.m_strName;

							m_arrPageMasterAlternatives.Copy(oSrc.m_arrPageMasterAlternatives);
						}
						// ---
						~CPageSequenceMaster()
						{
							Clear();
						}
						// ---
						void	Clear()
						{
							m_strName	= _T("");

							m_arrPageMasterAlternatives.RemoveAll();
						}
						// ---
						void	FromXmlNode(XmlUtils::CXmlNode& oXmlNode)
						{
							m_strName	= oXmlNode.GetAttributeOrValue(_T("master-name"), _T(""));

							XmlUtils::CXmlNodes oPageMasterAlternativesNodes;
							if (oXmlNode.GetNodes(_T("fo:repeatable-page-master-alternatives"), oPageMasterAlternativesNodes))
							{
								INT iCount	= oPageMasterAlternativesNodes.GetCount();
								for (INT iIndex = 0; iIndex < iCount; ++ iIndex)
								{
									XmlUtils::CXmlNode oPageMasterAlternativesNode;
									oPageMasterAlternativesNodes.GetAt(iIndex, oPageMasterAlternativesNode);

									m_arrPageMasterAlternatives.Add();
									m_arrPageMasterAlternatives[iIndex].FromXmlNode(oPageMasterAlternativesNode);
								}
							}							
						}
						// ---
						CString	GetPageMasterName()
						{
							if (!m_arrPageMasterAlternatives.IsEmpty())
							{
								return m_arrPageMasterAlternatives[0].m_strEvenPageMasterReference;
							}
							else
							{
								return _T("");
							}
						}
					};
					class CFlowAssignment
					{
					private:
						CAtlArray<CString>	m_arrSources;
						CAtlArray<CString>	m_arrTargets;

					public:
						// ---
						CFlowAssignment() 
							: m_arrSources(), m_arrTargets()
						{
						}
						CFlowAssignment(const CFlowAssignment &oFlowAssignment)
						{
							m_arrSources.Copy(oFlowAssignment.m_arrSources);
							m_arrTargets.Copy(oFlowAssignment.m_arrTargets);
						}
						// ---
						~CFlowAssignment()
						{
							Clear();							
						}
						// ---
						CFlowAssignment& operator=(const CFlowAssignment &oFlowAssignment)
						{
							m_arrSources.Copy(oFlowAssignment.m_arrSources);
							m_arrTargets.Copy(oFlowAssignment.m_arrTargets);

							return *this;
						}
						// ---
						void	Clear()
						{
							m_arrSources.RemoveAll();
							m_arrTargets.RemoveAll();
						}
						// ---
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
							XmlUtils::CXmlNode oSourceNode;
							oXmlNode.GetNode(_T("fo:flow-source-list"), oSourceNode);
							XmlUtils::CXmlNodes oSpecifierNodes;
							if (oSourceNode.GetNodes(_T("fo:flow-name-specifier"), oSpecifierNodes))
							{
								int iCount = oSpecifierNodes.GetCount();
								for (int iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oSpecifierNodes.GetAt(iIndex, oNode);
									CString strFlowNameReference = oNode.GetAttributeOrValue(_T("flow-name-reference"), _T(""));
									if (strFlowNameReference != _T(""))
									{
										m_arrSources.Add(strFlowNameReference);
									}
								}
							}
							XmlUtils::CXmlNode oTargetNode;
							oXmlNode.GetNode(_T("fo:flow-target-list"), oTargetNode);
							if (oTargetNode.GetNodes(_T("fo:region-name-specifier"), oSpecifierNodes))
							{
								int iCount = oSpecifierNodes.GetCount();
								for (int iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oSpecifierNodes.GetAt(iIndex, oNode);
									CString strRegionNameReference = oNode.GetAttributeOrValue(_T("region-name-reference"), _T(""));
									if (strRegionNameReference != _T(""))
									{
										m_arrTargets.Add(strRegionNameReference);
									}
								}
							}
						}
						// ---
						CAtlArray<CString>*	Find(const CString& strSource)
						{
							for (size_t nIndex = 0; nIndex < m_arrSources.GetCount(); ++nIndex)
							{
								if (m_arrSources[nIndex] == strSource)
								{
									return &m_arrTargets;
								}
							}

							return NULL;
						}
					};

					class CFlowMap
					{
					private:
						CString	m_strName;

						CAtlArray<CFlowAssignment>	m_arrAssignments;

					public:
						// ---
						CFlowMap() 
							: m_strName(_T("")), 
							m_arrAssignments()
						{
						}
						CFlowMap(const CFlowMap &oPageMap)
						{
							m_strName	= oPageMap.m_strName;

							m_arrAssignments.Copy(oPageMap.m_arrAssignments);
						}
						// ---
						~CFlowMap()
						{
							Clear();
						}
						// ---
						void	FromXmlNode(XmlUtils::CXmlNode &oXmlNode)
						{
							m_strName	= oXmlNode.GetAttributeOrValue(_T("flow-map-name"), _T(""));
							if (m_strName != _T(""))
							{
								XmlUtils::CXmlNodes oAssignmentNodes;
								if (oXmlNode.GetNodes(_T("fo:flow-assignment"), oAssignmentNodes))
								{
									INT iCount	= oAssignmentNodes.GetCount();
									for (INT iIndex = 0; iIndex < iCount; ++iIndex)
									{
										XmlUtils::CXmlNode oNode;
										oAssignmentNodes.GetAt(iIndex, oNode);

										CFlowAssignment oFlowAssignment;
										oFlowAssignment.FromXmlNode(oNode);

										m_arrAssignments.Add(oFlowAssignment);
									}
								}
							}
						}
						// ---
						void	Clear()
						{
							m_strName	= _T("");

							m_arrAssignments.RemoveAll();
						}
						// ---
						inline BOOL	IsEqualName(const CString& strName)
						{
							return (m_strName == strName);
						}
						// ---
						void	GetRegionNames(const CString& strFlowName, CAtlArray<CString>& arrRegionNames)
						{
							for (size_t nIndex = 0; nIndex < m_arrAssignments.GetCount(); ++nIndex)
							{
								CAtlArray<CString>* pArrTargets	= m_arrAssignments[nIndex].Find(strFlowName);
								if (pArrTargets)
								{
									arrRegionNames.Copy(*pArrTargets);
								}
							}
						}
					};

					class CSimplePageMaster : private CXmlAttributeReader
					{
					private:
						CString	m_strName;

						REAL	m_fWidthPt;
						REAL	m_fHeightPt;

						REAL	m_fWidthL;
						REAL	m_fHeightL;

						CBounds	m_oBounds;
						CBrush  m_oBrush;

						CAtlArray<CRegion>	m_arrRegions;

						PageNumbering _pageNum;

						bool	m_Continuous;

					private:
						void	LoadAttributesFromXml(XmlUtils::CXmlNode& attributes)
						{
							CString continuous = attributes.GetAttribute(_T("continuous"), _T("false"));
							if (continuous == _T("true"))
								m_Continuous = true;
						}

					public:
						CSimplePageMaster() 
							: m_strName(_T("")), 
							m_fWidthPt(0.0f), m_fHeightPt(0.0f), 
							m_fWidthL(0.0f), m_fHeightL(0.0f), 
							m_oBounds(), 
							m_oBrush(), m_arrRegions(), 
							m_Continuous(false)
						{
						}
						~CSimplePageMaster()
						{
							Clear();							
						}
					public:
						void	Clear()
						{
							m_strName	= _T("");

							m_fWidthPt	= 0.0f;
							m_fHeightPt	= 0.0f;

							m_fWidthL	= 0.0f;
							m_fHeightL	= 0.0f;

							m_oBounds.Clear();
							m_arrRegions.RemoveAll();

							m_Continuous = false;
						}
						void	loadFromXml(XmlUtils::CXmlNode& oXmlNode, CDocumentManager& documentManager)
						{
							m_strName	= oXmlNode.GetAttributeOrValue(_T("master-name"), _T(""));

							if (documentManager.m_ItemManager.IsFo())
							{
								m_fWidthPt	= FloatPtAttributeFromXml(oXmlNode, _T("page-width"), 612.0f);
								m_fHeightPt	= FloatPtAttributeFromXml(oXmlNode, _T("page-height"), 792.0f);
							}
							else
							{
								m_fWidthPt	= FloatPtAttributeFromXml(oXmlNode, _T("page-width"));
								m_fHeightPt	= FloatPtAttributeFromXml(oXmlNode, _T("page-height"));
							}

							m_fWidthL	= m_fWidthPt;
							m_fHeightL	= m_fHeightPt;

							m_oBounds.FromXmlNodeFo2(oXmlNode);
							ReadRegions(oXmlNode);

							XmlUtils::CXmlNode pageNumberingXml;
							if (oXmlNode.GetNode(_T("pageNumbering"), pageNumberingXml))
								_pageNum.loadFromXml(pageNumberingXml);

							LoadAttributesFromXml(oXmlNode);
						}
					public:
						inline REAL	GetWidthPt()
						{
							return m_fWidthPt;
						}
						inline REAL	GetHeightPt()
						{
							return m_fHeightPt;
						}
						inline REAL	GetWidthL()
						{
							return m_fWidthL;
						}
						inline REAL	GetHeightL()
						{
							return m_fHeightL;
						}
						inline RectF	GetRectPt()
						{
							return m_oBounds.GetRectPt();
						}
						const PageNumbering& getPageNumbering() const {
							return _pageNum;
						}
						inline bool	Continuous()
						{
							return m_Continuous;
						}
					public:
						inline BOOL	IsEqualName(const CString& strName)
						{
							return (m_strName == strName);
						}
					public:
						void		ResetRegions()
						{
							for (size_t nIndex = 0; nIndex < m_arrRegions.GetCount(); ++nIndex)
							{
								m_arrRegions[nIndex].SetComplete();
								m_arrRegions[nIndex].CheckRect();
							}
						}
						CRegion*	GetRegion(const CString& strRegionName)
						{
							CRegion *pRegion	= NULL;

							for (size_t nIndex = 0; nIndex < m_arrRegions.GetCount(); ++nIndex)
							{
								if (m_arrRegions[nIndex].IsEqualName(strRegionName))
								{
									pRegion	= &m_arrRegions[nIndex];
									break;
								}
							}

							return pRegion;
						}
						CRegion**	GetRegions(const CString& strRegionName, size_t& length)
						{
							CRegion **ppRegion	= new CRegion*[m_arrRegions.GetCount()];
							size_t i = 0;

							for (size_t nIndex = 0; nIndex < m_arrRegions.GetCount(); ++nIndex)
							{
								if (m_arrRegions[nIndex].IsEqualName(strRegionName))
								{
									ppRegion[i++]	= &m_arrRegions[nIndex];
								}
							}
							length = i;

							return ppRegion;
						}
					public:
						// --- non-fo
						void	Init(const REAL& fWidthL, const REAL& fHeightL, 
							const REAL& fWidthMm, const REAL& fHeightMm, const CBounds& oBounds, const CBrush& oBrush)
						{
							m_fWidthL	= fWidthL;
							m_fHeightL	= fHeightL;

							m_oBounds.SetAsRectMm(fWidthMm, fHeightMm);
							m_fWidthPt	= m_oBounds.GetRectPt().Width;
							m_fHeightPt	= m_oBounds.GetRectPt().Height;

							for (size_t nIndex = 0; nIndex < m_arrRegions.GetCount(); ++nIndex)
							{
								m_arrRegions[nIndex].SetBounds(oBounds);
							}

							m_oBrush = oBrush;
						}
					private:
						void	ReadRegions(XmlUtils::CXmlNode &oXmlNode, const bool& bMustInitRegions = true)
						{
							bool bSkip = true;
							m_oBounds.SetAsRectPt(m_fWidthPt, m_fHeightPt);

							RectF oPrevRectPt	= RectF();

							XmlUtils::CXmlNodes oNodes;
							if (oXmlNode.GetNodes(_T("*"), oNodes))
							{
								INT iListLength	= oNodes.GetCount();

								for (INT iIndex = 0; iIndex < iListLength; ++iIndex)
								{									
									XmlUtils::CXmlNode oNode;
									oNodes.GetAt(iIndex, oNode);

									if (oNode.GetAttribute(_T("hasCols")) != _T(""))
									{
										XmlUtils::CXmlNode oNodeCols;
										oNode.GetNode(_T("w:cols"), oNodeCols);										

										int  iColsCount	 = oNodeCols.ReadAttributeInt(_T("w:num"), 1);
										BOOL bEqualWidth = XmlUtils::GetBoolean(oNodeCols.GetAttribute(_T("w:equalWidth"), _T("true")));
										double  dSpace	 = oNodeCols.ReadAttributeInt(_T("w:space"), 720) / 20;

										double*  dWidthCols = new double[iColsCount];
										double*  dSpaceCols = new double[iColsCount];
										if (iColsCount != 1)
										{
											if (bEqualWidth == FALSE)
											{
												XmlUtils::CXmlNodes oNodeColGroup;
												if (oNodeCols.GetNodes(_T("w:col"), oNodeColGroup))
												{
													int iGroupLength	= oNodeColGroup.GetCount();
													double dMarginLeft = 0;
													for (int iInd = 0; iInd < iGroupLength; ++iInd)
													{
														XmlUtils::CXmlNode oNodeCol;
														oNodeColGroup.GetAt(iInd, oNodeCol);

														dWidthCols[iInd] = oNodeCol.ReadAttributeDouble(_T("w:w"), 0) / 20;
														dSpaceCols[iInd] = oNodeCol.ReadAttributeDouble(_T("w:space"), 0) / 20;
													}
												}
											}
											else 
											{
												double dWidth = (m_oBounds.GetRectPt().GetRight() - m_oBounds.GetRectPt().GetLeft() - dSpace * (iColsCount - 1)) / iColsCount;												
												for (int iInd = 0; iInd < iColsCount; ++iInd)
												{
													dWidthCols[iInd] = dWidth;
													dSpaceCols[iInd] = dSpace;
												}
											}
											double dMarginLeft = 0;
											for (int iInd = 0; iInd < iColsCount; ++iInd)
											{
												AddRegion(oNode, dMarginLeft, dWidthCols[iInd], oPrevRectPt);

												dMarginLeft += (dWidthCols[iInd] + dSpaceCols[iInd]);	
											}											
										}
										else
										{
											AddRegion(oNode, oPrevRectPt);											
										}	
										delete [] dWidthCols;
										delete [] dSpaceCols;
									}
									else
									{
										AddRegion(oNode, oPrevRectPt);										
									}
								} 
							}							
							/*XmlUtils::CXmlReader oReader;
							if (oReader.SetXmlString(oXmlNode.GetXml()) && oReader.ReadNodeList(_T("*")))
							{
							INT iListLength	= oReader.GetLengthList();

							for (INT iIndex = 0; iIndex < iListLength; ++iIndex)
							{
							XmlUtils::CXmlNode oNode;
							oNode.FromXmlString(oReader.ReadNodeXml(iIndex));

							m_arrRegions.Add();
							m_arrRegions[iIndex].FromXmlNodeFo(oNode);

							m_arrRegions[iIndex].SetBounds(m_oBounds);
							m_arrRegions[iIndex].ApplyDisplayAlign(oPrevRectPt);
							}
							}*/
						}
						void	AddRegion(XmlUtils::CXmlNode oNode, double dMarginLeft, double dWidth, RectF& oPrevRectPt)
						{
							size_t iCount = m_arrRegions.GetCount();
							m_arrRegions.Add();
							m_arrRegions[iCount].FromXmlNodeFo(oNode);							
							m_arrRegions[iCount].SetIsColumn();

							CBounds cBounds = m_arrRegions[iCount].GetBounds();
							cBounds.SetAsRectPt(m_oBounds.GetRectPt());
							m_arrRegions[iCount].AddBounds(dMarginLeft, 0, cBounds.GetRectPt().GetRight() - cBounds.GetRectPt().GetLeft()- dMarginLeft - dWidth, 0);
							m_arrRegions[iCount].SetBounds(m_oBounds);
							m_arrRegions[iCount].ApplyDisplayAlign(oPrevRectPt);
						}
						void	AddRegion(XmlUtils::CXmlNode oNode, RectF& oPrevRectPt)
						{
							size_t iCount = m_arrRegions.GetCount();
							m_arrRegions.Add();
#ifdef AVS_LOG_DEBUG
							CRegion *p1 = &m_arrRegions[iCount];
#endif
							m_arrRegions[iCount].FromXmlNodeFo(oNode, true);

							m_arrRegions[iCount].SetBounds(m_oBounds);
							//m_arrRegions[iCount].ApplyDisplayAlign(oPrevRectPt);
						}
					};

					class CLayoutMasterSet
					{
					private:
						CAtlArray<CSimplePageMaster>	m_arrSimplePageMasters;
						CAtlArray<CFlowMap>				m_arrFlowMaps;
						CAtlArray<CPageSequenceMaster>	m_arrPageSequenceMasters;

					public:
						// ---
						CLayoutMasterSet()
							: m_arrSimplePageMasters(), 
							m_arrFlowMaps(), 
							m_arrPageSequenceMasters()
						{
						}
						// ---
						~CLayoutMasterSet()
						{
							Clear();
						}
						// ---
						void	Clear()
						{
							m_arrSimplePageMasters.RemoveAll();
							m_arrFlowMaps.RemoveAll();
							m_arrPageSequenceMasters.RemoveAll();
						}
						// ---
						void	FromXmlNode(XmlUtils::CXmlNode& oXmlNode, CDocumentManager& documentManager)
						{
							XmlUtils::CXmlNodes oPageTypeNodes;
							if (oXmlNode.GetNodes(_T("fo:simple-page-master"), oPageTypeNodes))
							{
								INT iCount = oPageTypeNodes.GetCount();
								for (INT iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oPageTypeNodes.GetAt(iIndex, oNode);

									m_arrSimplePageMasters.Add();
									m_arrSimplePageMasters[iIndex].loadFromXml(oNode, documentManager);
								}
							}

							XmlUtils::CXmlNodes oPageMapNodes;
							if (oXmlNode.GetNodes(_T("fo:flow-map"), oPageMapNodes))
							{
								INT iCount = oPageMapNodes.GetCount();
								for (INT iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oPageMapNodes.GetAt(iIndex, oNode);

									m_arrFlowMaps.Add();
									m_arrFlowMaps[m_arrFlowMaps.GetCount() - 1].FromXmlNode(oNode);
								}
							}

							XmlUtils::CXmlNodes oPageSequenceMasterNodes;
							if (oXmlNode.GetNodes(_T("fo:page-sequence-master"), oPageSequenceMasterNodes))
							{
								INT iCount = oPageSequenceMasterNodes.GetCount();
								for (INT iIndex = 0; iIndex < iCount; ++iIndex)
								{
									XmlUtils::CXmlNode oNode;
									oPageSequenceMasterNodes.GetAt(iIndex, oNode);

									m_arrPageSequenceMasters.Add();
									m_arrPageSequenceMasters[m_arrPageSequenceMasters.GetCount() - 1].FromXmlNode(oNode);
								}
							}
						}
						// ---
						CSimplePageMaster*		FindSimplePageMaster(const CString& strName)
						{
							size_t nPageTypesCount	= m_arrSimplePageMasters.GetCount();
							for (size_t nIndex = 0; nIndex < nPageTypesCount; ++nIndex)
							{
								if (m_arrSimplePageMasters[nIndex].IsEqualName(strName))
								{
									return &m_arrSimplePageMasters[nIndex];
								}
							}

							return NULL;
						}
						CFlowMap*				FindFlowMap(const CString& strName)
						{
							size_t nPageMapsCount	= m_arrFlowMaps.GetCount();
							for (size_t nIndex = 0; nIndex < nPageMapsCount; ++nIndex)
							{
								if (m_arrFlowMaps[nIndex].IsEqualName(strName))
								{
									return &m_arrFlowMaps[nIndex];
								}
							}

							return NULL;
						}
						CPageSequenceMaster*	FindPageSequenceMaster(const CString& strName)
						{
							size_t nPageSequenceMastersCount	= m_arrPageSequenceMasters.GetCount();
							for (size_t nIndex = 0; nIndex < nPageSequenceMastersCount; ++nIndex)
							{
								if ( m_arrPageSequenceMasters[nIndex].m_strName == strName )
								{
									return &m_arrPageSequenceMasters[nIndex];
								}
							}

							return NULL;
						}
					};

					class CPage	{
					private:
						CSimplePageMaster*	m_pSimplePageMaster;

						CAtlArray<CLine*>	m_arrLines;
						CAtlArray<size_t>	m_arrBlockBeginIndexes;
						int				m_nFlowBeginIndex;
						int				m_nFlowEndIndex;

						CAtlArray<CLine*>	m_arrFLines;
						CAtlArray<size_t>	m_arrBlockFBeginIndexes;
						REAL				m_fFootnoteStart;
						int					m_iCurrentFootnoteIndex;

						CAtlArray<size_t>			m_arrGraphicLinesBeginIndexes;
						CAtlArray<CGraphicLine*>	m_arrGraphicLines;
						int						m_nGraphicLinesBeginIndex;
						int						m_nGraphicLinesEndIndex;

						CAtlArray<size_t>			m_arrBackgroundBeginIndexes;
						CAtlArray<CBackgroundRect*> m_arrBackgroundsRects;
						int						m_nBackgroundBeginIndex;
						int						m_nBackgroundEndIndex;

						CAreaManager			m_oAreaManager;
						CAtlArray<CAlternate2*>	m_arrAnchors;
						int	m_AnchorFirst;
						int m_AnchorBlockFirst;
						int	m_AnchorLast;

						bool	m_bFootnoteProcessing;
						bool	m_bBodyProcessing;

						bool m_bIsEmptyBody;
						bool _withNonDummyLines;

						bool	m_Continuous;
						float	m_FilledHeight;
						float	m_FooterHeight;
						float _footnoteHeight;

						bool _beginCell;

						CArray<RCommand> _lineCommands;

					public:
						CPage() 
							: m_pSimplePageMaster(NULL), 
							m_arrLines(), m_arrBlockBeginIndexes(), 
							m_nFlowBeginIndex(0), m_nFlowEndIndex(0), 
							m_nGraphicLinesBeginIndex(0), m_nGraphicLinesEndIndex(0),
							m_nBackgroundBeginIndex(0),	m_nBackgroundEndIndex(0),
							m_arrFLines(), m_arrBlockFBeginIndexes(), m_fFootnoteStart(0.0f), m_iCurrentFootnoteIndex(-1), 
							m_arrGraphicLines(), m_arrBackgroundsRects(), 
							m_oAreaManager(), m_arrAnchors(), 
							m_AnchorFirst(0), m_AnchorLast(0), m_AnchorBlockFirst(0), 
							m_bFootnoteProcessing(false), m_bBodyProcessing(false), 
							m_bIsEmptyBody(true), _withNonDummyLines(false), 
							m_Continuous(false), m_FilledHeight(0.0f), m_FooterHeight(-1), _footnoteHeight(0), 
							_beginCell(false) {
						}
						~CPage()
						{
							Clear();
						}
						void	Clear()
						{	
							m_pSimplePageMaster	= NULL;

							size_t nLinesCount	= m_arrLines.GetCount();
							for (size_t nIndex = 0; nIndex < nLinesCount; ++nIndex) {
								RELEASEOBJECT(m_arrLines[nIndex]);
							}
							m_arrLines.RemoveAll();
							m_arrBlockBeginIndexes.RemoveAll();
							m_nFlowBeginIndex	= 0;
							m_nFlowEndIndex		= 0;

							size_t nFLinesCount	= m_arrFLines.GetCount();
							for (size_t nIndex = 0; nIndex < nFLinesCount; ++nIndex)
							{
								RELEASEOBJECT(m_arrFLines[nIndex]);
							}
							m_arrFLines.RemoveAll();
							m_arrBlockFBeginIndexes.RemoveAll();
							m_fFootnoteStart	= 0.0f;
							m_iCurrentFootnoteIndex = -1;

							size_t nGraphicLinesCount	= m_arrGraphicLines.GetCount();
							for (size_t nIndex = 0; nIndex < nGraphicLinesCount; ++nIndex)
							{
								RELEASEOBJECT(m_arrGraphicLines[nIndex]);
							}
							m_nGraphicLinesBeginIndex = 0;
							m_nGraphicLinesEndIndex   = 0;
							m_arrGraphicLines.RemoveAll();

							size_t nBackgroundsRectsCount	= m_arrBackgroundsRects.GetCount();
							for (size_t nIndex = 0; nIndex < nBackgroundsRectsCount; ++nIndex)
							{
								RELEASEOBJECT(m_arrBackgroundsRects[nIndex]);
							}
							m_nBackgroundBeginIndex = 0;
							m_nBackgroundEndIndex	= 0;
							m_arrBackgroundsRects.RemoveAll();

							m_oAreaManager.Clear();
							m_arrAnchors.RemoveAll();
							m_AnchorFirst = 0;
							m_AnchorLast = 0;
							m_AnchorBlockFirst = 0;

							m_bFootnoteProcessing	= false;

							m_Continuous = false;
							m_FilledHeight = 0.0f;
							m_FooterHeight = -1;
							_footnoteHeight = 0;

							_beginCell = false;
						}
					public:
						void	ClearDerivedLines(int from)
						{
							for (size_t i = m_nFlowEndIndex; i != from; i--)
								m_arrLines.RemoveAt(i - 1);
							m_nFlowEndIndex = from;
						}
						void	ClearDerivedGraphLines(int startIndex)
						{
							for (int i = m_nGraphicLinesEndIndex; i != startIndex; --i)
								m_arrGraphicLines.RemoveAt(i - 1);
							m_nGraphicLinesEndIndex = startIndex;
						}
						void	ClearDerivedBackgrounds(int startIndex)
						{
							for (int i = m_nBackgroundEndIndex; i != startIndex; --i)
								m_arrBackgroundsRects.RemoveAt(i - 1);
							m_nBackgroundEndIndex = startIndex;
						}
						inline size_t GetLastLine()
						{
							return m_nFlowEndIndex;
						}
						inline int	GetLastGraphLine() const
						{
							return (int)m_nGraphicLinesEndIndex;
						}
						inline int	GetLastBackground() const
						{
							return (int)m_nBackgroundEndIndex;
						}
						inline void	SetPageMaster(CSimplePageMaster* pSimplePageMaster)
						{
							m_pSimplePageMaster	= pSimplePageMaster;
							m_pSimplePageMaster->ResetRegions();
						}
						inline REAL	GetWidthPt() const
						{
							if (m_pSimplePageMaster)
								return m_pSimplePageMaster->GetWidthPt();
							else
								return 0;

						}
						inline REAL	GetHeightPt() const
						{
							if (m_pSimplePageMaster)
								return m_pSimplePageMaster->GetHeightPt();
							else
								return 0;
						}
						inline REAL	GetWidthL()
						{
							return m_pSimplePageMaster->GetWidthL();
						}
						inline REAL	GetHeightL()
						{
							return m_pSimplePageMaster->GetHeightL();
						}
						inline REAL	GetWidthMm() const
						{
							return GetWidthPt() * (25.4f / 72.0f);
						}
						inline REAL	GetHeightMm() const
						{
							return GetHeightPt() * (25.4f / 72.0f);
						}
						inline CAreaManager*	GetAreaManager()
						{
							return &m_oAreaManager;
						}
						inline CAtlArray<CLine*>& GetRefLines ()
						{
							return m_arrLines;
						}
						int getBlockCount() const {
							return (int)m_arrBlockBeginIndexes.GetCount();
						}
						void getBlockMetric(const int& block, float& height, float& offset) {
							height = 0;
							offset = 0;

							int blockCount = (int)m_arrBlockBeginIndexes.GetCount();
							if (block < 0 || block >= blockCount)
								return;

							int firstLine = m_arrBlockBeginIndexes[block];
							int lastLine = block + 1 == blockCount ? m_arrLines.GetCount() - 1 : m_arrBlockBeginIndexes[block + 1] - 1;

							if (firstLine >= (int)m_arrLines.GetCount())
								return;

							float bottom = m_arrLines[lastLine]->GetRect().GetBottom();
							offset = m_arrLines[firstLine]->GetRect().GetTop();
							height =  bottom - offset;
						}
					public:
						inline void	StartFootnote()
						{
							m_bFootnoteProcessing	= true;
							m_iCurrentFootnoteIndex = -1;
							if (m_arrFLines.GetCount() != 0)
							{
								m_iCurrentFootnoteIndex	= (int)m_arrFLines.GetCount() - 1;
							}
						}
						inline void	FinishFootnote()
						{
							m_bFootnoteProcessing	= false;
							size_t nLastIndex = m_arrFLines.GetCount() - 1;
							if (nLastIndex - m_iCurrentFootnoteIndex > 0)
							{
								REAL fOffset	= m_arrFLines[m_iCurrentFootnoteIndex + 1]->GetRect().Y - m_fFootnoteStart;

								for (size_t nIndex = m_iCurrentFootnoteIndex + 1; nIndex <= nLastIndex; ++nIndex)
								{
									m_arrFLines[nIndex]->MoveOn(0, -fOffset);
								}
								m_fFootnoteStart	+= m_arrFLines[nLastIndex]->GetRect().GetBottom() - m_arrFLines[m_iCurrentFootnoteIndex + 1]->GetRect().Y;
							}
						}
						inline void	StartBlock()
						{
							if (!m_bFootnoteProcessing)
							{
								m_arrBlockBeginIndexes.Add((unsigned int)m_arrLines.GetCount());
								m_arrBlockFBeginIndexes.Add((unsigned int)m_arrFLines.GetCount());

								m_arrGraphicLinesBeginIndexes.Add((unsigned int)m_arrGraphicLines.GetCount());
								m_arrBackgroundBeginIndexes.Add((unsigned int)m_arrBackgroundsRects.GetCount());

								m_AnchorBlockFirst = m_AnchorLast;
							}
						}
						inline void	FinishBlock()
						{
						}
						inline void StartBody()
						{
							m_bBodyProcessing	= true;
						}
						inline void	FinishBody()
						{
							m_bBodyProcessing	= false;
						}
						inline bool IsEmptyBody() {
							return (m_bIsEmptyBody && !m_bFootnoteProcessing);
						}
						inline bool isWithNonDummyLines() const {
							return _withNonDummyLines;
						}
						inline void	DeleteBlocks(int number)
						{
							while (number-- > 0)
							{
								int lastBlock = (int)m_arrBlockBeginIndexes.GetCount() - 1;
								if (lastBlock < 0)
									break;

								int blockFirstLine = (int)m_arrBlockBeginIndexes[lastBlock];
								int lineCount = (int)m_arrLines.GetCount();
								if (blockFirstLine < lineCount)
								{
									for (int index = blockFirstLine; index < (int)lineCount; ++index)
										RELEASEOBJECT(m_arrLines[index]);

									m_arrLines.RemoveAt(blockFirstLine, lineCount - blockFirstLine);
									m_nFlowEndIndex	= blockFirstLine;
								}
								m_arrBlockBeginIndexes.RemoveAt(lastBlock);

								int blockFirstFootLine = (int)m_arrBlockFBeginIndexes[lastBlock];
								int footLineCount = (int)m_arrFLines.GetCount();
								if (blockFirstFootLine < footLineCount)
								{
									for (int index = blockFirstFootLine; index < footLineCount; ++index)
										RELEASEOBJECT(m_arrFLines[index]);

									m_arrFLines.RemoveAt(blockFirstFootLine, footLineCount - blockFirstFootLine);
								}
								m_arrBlockFBeginIndexes.RemoveAt(lastBlock);

								int blockFirstGraphLine = (int)m_arrGraphicLinesBeginIndexes[lastBlock];
								int graphLineCount = (int)m_arrGraphicLines.GetCount();
								if (blockFirstGraphLine < graphLineCount)
								{
									for (int index = blockFirstGraphLine; index < graphLineCount; ++index)
										RELEASEOBJECT(m_arrGraphicLines[index]);

									m_arrGraphicLines.RemoveAt(blockFirstGraphLine, graphLineCount - blockFirstGraphLine);
									m_nGraphicLinesEndIndex	= blockFirstGraphLine;
								}

								int blockFirstBackground = (int)m_arrBackgroundBeginIndexes[lastBlock];
								int backgroundCount = (int)m_arrBackgroundsRects.GetCount();
								if (blockFirstBackground < backgroundCount)
								{
									for (int index = blockFirstBackground; index < backgroundCount; ++index)
										RELEASEOBJECT(m_arrBackgroundsRects[index]);

									m_arrBackgroundsRects.RemoveAt(blockFirstBackground, backgroundCount - blockFirstBackground);
									m_nBackgroundEndIndex = blockFirstBackground;
								}
							}
						}
						inline void	AddLine(CLine* line) {
							if (m_bFootnoteProcessing)
								m_arrFLines.Add(line);
							else {
								if (_beginCell) {
									_beginCell = false;
									line->setStartCell();
								}

								if (m_bBodyProcessing && !line->isDummy()) {
									m_bIsEmptyBody = false;
									_withNonDummyLines = true;
								}
								
								setRendererCommandsToLine(line);
								m_arrLines.Add(line);

								++m_nFlowEndIndex;
							}
						}
						void		AddAnchorContent(CAtlArray<CAlternate2*> &arrAnchors) {
							size_t anchorCount = arrAnchors.GetCount();
							if (anchorCount && !m_bFootnoteProcessing && m_bBodyProcessing)
								m_bIsEmptyBody = false;

							size_t nAnchorIndex	= m_arrAnchors.GetCount();
							RectF oPageRectPt	= m_pSimplePageMaster->GetRectPt();

							for (size_t nIndex = 0; nIndex < anchorCount; ++nIndex)	{
								CAlternate2* anchor = arrAnchors[nIndex];
								if (!arrAnchors[nIndex]->Related())
									continue;

								float zIndex = arrAnchors[nIndex]->getZIndex();
								int count = (int) m_arrAnchors.GetCount();
								int insIndex = 0;
								for (; insIndex < count; ++insIndex)
									if (zIndex < m_arrAnchors[insIndex]->getZIndex())
										break;
								if (insIndex == count)
									m_arrAnchors.Add(arrAnchors[nIndex]);
								else
									m_arrAnchors.InsertAt((size_t) insIndex, arrAnchors[nIndex]);
								arrAnchors[nIndex]->setInHeader(!m_bBodyProcessing);

								m_oAreaManager.AddWrapPolygon(arrAnchors[nIndex]->Points(), 
									arrAnchors[nIndex]->DistanceLeft(), arrAnchors[nIndex]->DistanceRight());
								arrAnchors[nIndex]->Placed(true);

								++m_AnchorLast;
							}
						}
						void		RemoveAnchorContent(int position)
						{
							if (m_AnchorBlockFirst == m_AnchorLast)
								return;
							int index = m_AnchorLast - 1;
							while (index >= m_AnchorBlockFirst) {
								if (m_arrAnchors[index]->InlinePosition() != position)
									break;
								m_arrAnchors[index]->Placed(false);
								--index;
							}
							++index;
							if (index != m_AnchorLast) {
								m_arrAnchors.RemoveAt(index, m_AnchorLast - index);
								m_AnchorLast = (int)m_arrAnchors.GetCount();
							}

						}
						void		AddGraphicLine(CGraphicLine *pGraphicLine)
						{
							m_arrGraphicLines.Add(pGraphicLine);
							++m_nGraphicLinesEndIndex;
						}
						void		AddBackgroundRect(CBackgroundRect *pBackgroundRect)
						{
							m_arrBackgroundsRects.Add(pBackgroundRect);
							++m_nBackgroundEndIndex;
						}
						// ---
						inline void	StartPrintingFlow()
						{
							if (!m_bFootnoteProcessing)
							{
								m_nFlowBeginIndex = (int) m_arrLines.GetCount();
								m_nFlowEndIndex = (int) m_arrLines.GetCount();

								m_nGraphicLinesBeginIndex = (int) m_arrGraphicLines.GetCount();
								m_nGraphicLinesEndIndex   = (int) m_arrGraphicLines.GetCount();

								m_nBackgroundBeginIndex = (int) m_arrBackgroundsRects.GetCount();
								m_nBackgroundEndIndex	= (int) m_arrBackgroundsRects.GetCount();
								m_AnchorFirst = (int) m_arrAnchors.GetCount();
								m_AnchorLast = (int) m_arrAnchors.GetCount();
							}
						}
						inline void	FinishPrintingFlow()
						{
							if (!m_bFootnoteProcessing)
							{
								m_nFlowBeginIndex	= 0;
								m_nFlowEndIndex		= 0;

								m_nGraphicLinesBeginIndex = 0;
								m_nGraphicLinesEndIndex   = 0;

								m_nBackgroundBeginIndex = 0;
								m_nBackgroundEndIndex	= 0;

								m_AnchorFirst = 0;
								m_AnchorLast = 0;
							}
						}

						void		MoveFlowOn(const REAL &fDeltaX, const REAL &fDeltaY)
						{
							if (!m_bFootnoteProcessing)
							{
								for (int nIndex = m_nGraphicLinesBeginIndex; nIndex < (int) m_arrGraphicLines.GetCount(); ++nIndex)
								{
									m_arrGraphicLines[nIndex]->MoveOn(fDeltaX * 25.4 / 72, fDeltaY * 25.4 / 72);
								}

								for (int nIndex = m_nBackgroundBeginIndex; nIndex < (int) m_arrBackgroundsRects.GetCount(); ++nIndex)
								{
									m_arrBackgroundsRects[nIndex]->MoveOn(fDeltaX * 25.4 / 72, fDeltaY * 25.4 / 72);
								}

								for (int nIndex = m_nFlowBeginIndex; nIndex < m_nFlowEndIndex; ++nIndex)
								{
									m_arrLines[nIndex]->MoveOn(fDeltaX, fDeltaY);
								}
								for (int i = m_AnchorFirst; i < m_AnchorLast; ++i)
									if (m_arrAnchors[i]->AnchoredToRegion())
										m_arrAnchors[i]->MoveOn(fDeltaX, fDeltaY);
							}
						}
					public:
						void beginCell() {
							_beginCell = true;							
						}
						void endCell() {
							_beginCell = false;
							if (m_arrLines.GetCount() > 0) {
								int last = (int) m_arrLines.GetCount() - 1;
								m_arrLines[last]->setFinishCell();
							}
						}
						// ---
						void	Draw(IAVSRenderer* pRenderer, CDocumentManager& documentManager, const float& fCompleteness)
						{
							documentManager.SetPage(*this);
							for (size_t nIndex = 0; nIndex < m_arrBackgroundsRects.GetCount(); ++nIndex)
								m_arrBackgroundsRects[nIndex]->Draw(pRenderer, fCompleteness);

							for (size_t nIndex = 0; nIndex < m_arrAnchors.GetCount(); ++nIndex) {
								CAlternate2* anchor = m_arrAnchors[nIndex];
								if (anchor->getZIndex() < 0)
									anchor->Draw(pRenderer, documentManager, fCompleteness);
							}
							
							DrawLines(pRenderer, documentManager, fCompleteness);
							drawFootnoteLines(pRenderer, documentManager, fCompleteness);

							for (size_t nIndex = 0; nIndex < m_arrAnchors.GetCount(); ++nIndex) {
								CAlternate2* anchor = m_arrAnchors[nIndex];
								if (anchor->getZIndex() >= 0)
									anchor->Draw(pRenderer, documentManager, fCompleteness);
							}

							for (size_t nIndex = 0; nIndex < m_arrGraphicLines.GetCount(); ++nIndex)
								m_arrGraphicLines[nIndex]->Draw(pRenderer, fCompleteness);
						}
						void Draw(IAVSRenderer* renderer, CDocumentManager& documentManager, const int& block, const float& completeness) {
							int blockCount = (int)m_arrBlockBeginIndexes.GetCount();
							if (block < 0 || block >= blockCount)
								return;

							int firstLine = m_arrBlockBeginIndexes[block];
							int lastLine = block + 1 == blockCount ? m_arrLines.GetCount() - 1 : m_arrBlockBeginIndexes[block + 1] - 1;

							if (firstLine >= (int)m_arrLines.GetCount())
								return;

							for (int i = firstLine; i <= lastLine; ++i)
								m_arrLines[i]->Draw(renderer, documentManager, completeness);
						}
						void DrawLines(IAVSRenderer* renderer, CDocumentManager& documentManager, const float& completeness) {
							for (size_t index = 0; index < m_arrLines.GetCount(); ++index)
								m_arrLines[index]->Draw(renderer, documentManager, completeness);
						}
						void drawFootnoteLines(IAVSRenderer* renderer, CDocumentManager& documentManager, const float& completeness) {
							IAVSRenderer2* renderer2 = NULL;
							if (!SUCCEEDED(renderer->QueryInterface(__UUIDOF__IAVSRENDERER2, (void**)&renderer2)))
								renderer2 = NULL;

							if (renderer2 != NULL)
								renderer->BeginCommand(c_nFootnote);

							if (m_fFootnoteStart != 0.0f) {
								CRegion* pRegionBody	= GetRegion(_T("xsl-region-body"));
								RectF originalRect		= pRegionBody->GetOriginalRectPt();
								REAL fRegionBottom		= originalRect.GetBottom();
								if ((m_FooterHeight >= 0) && (m_FooterHeight < fRegionBottom))
									fRegionBottom = m_FooterHeight;

								CGraphicLine* grL = new CGraphicLine();
								double koef = 25.4f / 72.0f;
								//TODO   
								grL->SetStartPoint( originalRect.GetLeft() * koef, (fRegionBottom - m_fFootnoteStart)*koef - 1);
								grL->SetFinishPoint( originalRect.GetLeft() * koef + 50, (fRegionBottom - m_fFootnoteStart)*koef - 1);
								CPen pen;
								pen.m_oPen.Size = 0.2;
								grL->SetPen(pen);
								AddGraphicLine(grL);

								for (size_t nIndex = 0; nIndex < m_arrFLines.GetCount(); ++nIndex)
									m_arrFLines[nIndex]->MoveOn(0, fRegionBottom - m_fFootnoteStart);								

								m_fFootnoteStart = 0.0f;
							}

							for (size_t nIndex = 0; nIndex < m_arrFLines.GetCount(); ++nIndex)
								m_arrFLines[nIndex]->Draw(renderer, documentManager, completeness);

							if (renderer2 != NULL)
								renderer->EndCommand(c_nFootnote);

							RELEASEINTERFACE(renderer2);
						}
						// ---
						void GetLines(CAtlArray<CLine*>& lines)
						{
							lines.Copy(m_arrLines);
							m_arrLines.RemoveAll();
						}

						inline CRegion*		GetRegion(const CString& strRegionName)
						{
							return m_pSimplePageMaster->GetRegion(strRegionName);
						}
						inline CRegion**	GetRegions(const CString& strRegionName, size_t& iLength)
						{
							return m_pSimplePageMaster->GetRegions(strRegionName, iLength);
						}

					public:
						bool	Continuous() const 
						{
							return m_Continuous;
						}
						void	Continuous(const bool& continuous)
						{
							m_Continuous = continuous;
						}
						float	FilledHeight() const 
						{
							return m_FilledHeight;
						}
						void	FilledHeight(const float& filledHeight)
						{
							m_FilledHeight = filledHeight;
						}
						float	FooterHeight()
						{
							return m_FooterHeight;
						}
						void	FooterHeight(const float& footerHeight)
						{
							m_FooterHeight = footerHeight;
						}
						void	Merge(CPage* page)
						{
							m_arrLines.Append(page->m_arrLines);
							m_arrFLines.Append(page->m_arrFLines);

							m_arrGraphicLines.Append(page->m_arrGraphicLines);
							m_arrBackgroundsRects.Append(page->m_arrBackgroundsRects);
							m_arrAnchors.Append(page->m_arrAnchors);
						}
						void changeFootnoteHeight(const float& footnoteHeight) {
							_footnoteHeight += footnoteHeight;
						}
						float getFootnoteHeight() const {
							return _footnoteHeight;
						}
					public:
						bool	InFootnoteProcess()
						{
							return m_bFootnoteProcessing;
						}


					public:
						void addRendererCommand(const SharedPtr<RendererCommand>& command
								, const bool& toLast = false) {
							if (toLast)
								if (removeEmptyCommands(command))
									return;
							
							_lineCommands.Add(command);
							if (toLast) {
								int last = (int) m_arrLines.GetCount() - 1;
								if (last >= 0)
									setRendererCommandsToLine(m_arrLines[last]);
							}
						}
						bool removeEmptyCommands(const SharedPtr<RendererCommand>& command) {
							int commandCount = (int) _lineCommands.GetCount();
							if (commandCount > 0 && command->getType() == RendererCommand::END 
									&& command->getName() != RendererCommand::COMMON) {
								RendererCommand::RendererCommandName name = command->getName();
								for (int i = commandCount - 1; i >= 0; --i)
									if (_lineCommands[i]->getName() == name)
										if (_lineCommands[i]->getType() == RendererCommand::BEGIN) {
											_lineCommands.RemoveAt(i, commandCount - i);
											return true;
										}
							}
							return false;
						}
						void setRendererCommandsToLine(CLine* line) {
							if (_lineCommands.GetCount() != 0) {
								setAttrsOfRendererCommands(line);
								line->setRendererCommands(_lineCommands);
								_lineCommands.RemoveAll();
							}
						}
						void setAttrsOfRendererCommands(CLine* line) {
							for (int i = 0; i < (int) _lineCommands.GetCount(); ++i)
								_lineCommands[i]->setRect(line->GetRect());
						}

					public:
						static CPage* createNew(const CPage* prevPage = NULL) {
							CPage* page = new CPage();
							if (prevPage != NULL) {
								page->_lineCommands.Copy(prevPage->_lineCommands);
								page->_footnoteHeight = prevPage->_footnoteHeight;
							}

							return page;
						}
					};
				public:

					class TextMeasurer2 {
						CTextMeasurer* tm;
						int block;

						float height;
						float offset;

					public:
						TextMeasurer2(CTextMeasurer* tm = NULL, const int& block = 0, const float& height = 0, const float& offset = 0)
								: tm(tm), block(block)
								, height(height), offset(offset) {}
						void DrawFirstPage(IAVSRenderer* renderer, const float& completeness) {
							if (tm)
								tm->DrawFirstPage(renderer, completeness, block);
						}

						float GetHeight() const {
							return height;
						}
						float GetOffset() const {
							return offset;
						}
					};
					
					CLayoutMasterSet		m_oLayoutMasterSet;
					CArray<CPageSequence*>	m_arrPageSequence;

					INT		m_iPageSequenceIndex;
					bool	m_bIsFo;
					REAL	m_fCompleteness;

					IAVSRenderer*		m_pRenderer;
					CDocumentManager	m_DocumentManager;

					IAVSFontManager*	m_pFontManager;
					bool handlesFontManager;

					CAtlArray<CPage*>	m_arrPages;
					size_t				m_nCurrentPage;

					REAL	m_fWidthMm;
					REAL	m_fHeightMm;

					CString	m_strText;
					bool	m_bIsFormated;

					bool	m_bVertical;
					bool	m_bRightToLeft;

					double	m_dAngle;
					long	m_lFlags;
					RectF	m_oLayoutRect;
					CBrush  m_oBrush;
					CBackgroundProperties m_oBGPage;

				public:
					CTextMeasurer() 
						: m_oLayoutMasterSet(), m_arrPageSequence(), 
						m_iPageSequenceIndex(0), m_bIsFo(false), m_fCompleteness(1.0f), 
						m_pRenderer(NULL), m_DocumentManager(), 
						m_pFontManager(NULL), handlesFontManager(true), 
						m_arrPages(), m_nCurrentPage(0), 
						m_fWidthMm(0), m_fHeightMm(0), 
						m_strText(_T("")), m_bIsFormated(false), 
						m_bVertical(false), m_bRightToLeft(false), 
						m_dAngle(0.0), m_lFlags(0), m_oBGPage(),
						m_oLayoutRect()
					{
						InitFontManager();
					}
					CTextMeasurer(IAVSFontManager* fm) 
						: m_oLayoutMasterSet(), m_arrPageSequence(), 
						m_iPageSequenceIndex(0), m_bIsFo(false), m_fCompleteness(1.0f), 
						m_pRenderer(NULL), m_DocumentManager(), 
						m_pFontManager(fm), handlesFontManager(false), 
						m_arrPages(), m_nCurrentPage(0), 
						m_fWidthMm(0), m_fHeightMm(0), 
						m_strText(_T("")), m_bIsFormated(false), 
						m_bVertical(false), m_bRightToLeft(false), 
						m_dAngle(0.0), m_lFlags(0), m_oBGPage(),
						m_oLayoutRect() {}
					~CTextMeasurer()
					{
						InternalClear();
						if (handlesFontManager)
							RELEASEINTERFACE(m_pFontManager);
					}
				public:
					virtual INT		InternalGetRequiredStreamSize()
					{
						return 0;
					}
					virtual void	InternalToXmlAttributes(XmlUtils::CXmlWriter& oXmlWriter)
					{
					}
					virtual void	InternalFromXmlNode(XmlUtils::CXmlNode &oXmlNode) {
						InternalClear();
						
						#ifdef TME_DEBUG
						CString strXml	= oXmlNode.GetXml();
						FILE *pDebugInfoFile;
						fopen_s(&pDebugInfoFile, "c:\\temp\\debug_fo_doc.xml", "w");
						fwprintf_s(pDebugInfoFile, L"%s", strXml);
						fclose(pDebugInfoFile);
						#endif
						IWorker_OnProgress(0.0f);

						CItemManager *pItemManager	= &m_DocumentManager.m_ItemManager;
						m_DocumentManager.m_FontManager = m_pFontManager;

						#ifdef TME_DEBUG_VSXML
						oXmlNode.FromXmlFile(_T("c:\\temp\\vs.xml"));
						#endif

						if (oXmlNode.GetAttributeOrValue(_T("xmlns:fo"), _T("")) == _T("http://www.w3.org/1999/XSL/Format"))
						{
							pItemManager->SetIsFo(TRUE);
							InternalFromFoXml(oXmlNode);
						}
						else
						{
							pItemManager->SetIsFo(FALSE);
							InternalFromNonFoXml(oXmlNode);
						}

						IWorker_OnProgress(0.1f);
					}
					void			InternalFromNonFoXml2(XmlUtils::CXmlNode &oXmlNode, LONG& lMode, double dWidthMM, double dHeightMM)
					{
						InternalClear();
						IWorker_OnProgress(0.0f);

						CItemManager *pItemManager	= &m_DocumentManager.m_ItemManager;
						pItemManager->SetIsFo(FALSE);

						m_bIsFo	= FALSE;

						SetDefaultLayoutMasterSet(m_oLayoutMasterSet);

						m_strText = oXmlNode.GetAttributeOrValueExt(_T("text"), _T(""));
						FromXmlString(m_strText);

						if (m_strText == _T(""))
						{
							m_bIsFormated	= TRUE;

							return;
						}

						m_dAngle		= 0;
						m_lFlags		= 0;

						m_bVertical		= 0;
						m_bRightToLeft	= 0;

						REAL fWidthL	= 1000;
						REAL fHeightL	= 1000;

						m_fWidthMm	= (REAL)dWidthMM;
						m_fHeightMm	= (REAL)dHeightMM;

						pItemManager->SetWidthL(fWidthL);
						pItemManager->SetHeightL(fHeightL);
						REAL fMmToPt	= 72.0f / 25.4f;
						pItemManager->SetMultiplierX(m_fWidthMm * fMmToPt);
						pItemManager->SetMultiplierY(m_fHeightMm * fMmToPt);

						CSimplePageMaster *pSimplePageMaster	= m_oLayoutMasterSet.FindSimplePageMaster(_T("SPM"));

						m_oLayoutRect.X			= (REAL)(dWidthMM / 2.0 - 10000);
						m_oLayoutRect.Width		= (REAL)(20000);
						m_oLayoutRect.Y			= (REAL)(dHeightMM / 2.0 - 10000);
						m_oLayoutRect.Height	= (REAL)(20000);

						if ((m_oLayoutRect.Width == 0) || (m_oLayoutRect.Height == 0))
						{
							InternalClear();

							m_bIsFormated	= TRUE;

							return;
						}

						CBounds oBounds;
						oBounds.SetAsRectMm(m_oLayoutRect);

						pSimplePageMaster->Init(fWidthL, fHeightL, m_fWidthMm, m_fHeightMm, oBounds, m_oBrush);

						CTextAttributes oAttributes;
						XmlUtils::CXmlNode oAttributeNode;
						if (oXmlNode.GetNode(_T("Attributes"), oAttributeNode))
							oAttributes.FromXmlNode(oAttributeNode);

						CAtlArray<CBlockAttributes*> arPFs;
						CBlockAttributes *pParagraph = new CBlockAttributes();
						pParagraph->FromXmlNode(oAttributeNode, m_DocumentManager);
						pParagraph->m_lCount = m_strText.GetLength();
						//pParagraph->m_nTextAlignment = oAttributes.m_nTextAlignmentHorizontal;
						arPFs.Add(pParagraph);
						arPFs[0]->m_bIsFirst = true;

						CAtlArray<CCharacter*> arCFs;
						CCharacter *pCharacter = new CCharacter();
						pCharacter->FromXmlNode(oXmlNode);
						pCharacter->m_lCount = m_strText.GetLength();
						pCharacter->m_oAttributes = oAttributes;
						arCFs.Add(pCharacter);

						m_arrPageSequence.Add(new CPageSequence());
						SetDefaultPageSequence(*m_arrPageSequence[0]);

						CFlow* pFirstFlow	= m_arrPageSequence[0]->GetFirstFlow();

						pFirstFlow->SetAlignVertical((CAlignVertical)oAttributes.m_nTextAlignmentVertical);

						if (!Normalize(&arPFs, &arCFs, pFirstFlow->GetBlocks()))
						{
							InternalClear();
						}

						m_arrPages.RemoveAll();
					}
					virtual void	InternalClear()
					{
						m_oLayoutMasterSet.Clear();
						for (int i = 0; i < (int) m_arrPageSequence.GetCount(); ++i)
							if (m_arrPageSequence[i])
								delete m_arrPageSequence[i];
						m_arrPageSequence.RemoveAll();

						m_iPageSequenceIndex	= 0;
						m_bIsFo			= false;
						m_fCompleteness	= 1.0f;

						m_pRenderer		= NULL;

						m_DocumentManager.Clear();
						for (size_t nIndex = 0; nIndex < m_arrPages.GetCount(); ++nIndex)
						{
							RELEASEOBJECT(m_arrPages[nIndex]);
						}
						m_arrPages.RemoveAll();
						m_nCurrentPage	= 0;

						m_fWidthMm		= 0;
						m_fHeightMm		= 0;

						m_strText		= _T("");
						m_bIsFormated	= FALSE;

						m_bVertical		= FALSE;
						m_bRightToLeft	= FALSE;

						m_dAngle		= 0.0f;
						m_lFlags		= 0;
						m_oLayoutRect	= RectF();
					}
				public:
					void	IWorker_Resume()
					{

					}
					void	IWorker_Pause()
					{

					}
					void	IWorker_Stop()
					{

					}
					void	IWorker_OnNewPage(double dWidthMm, double dHeightMm)
					{

					}

					void	IWorker_OnCompletePage()
					{
					}
					void	IWorker_OnProgress(double dCompleteness)
					{
						double d	= dCompleteness;
					}
				public:
					void	SetRenderer(IAVSRenderer *pRenderer)
					{
						m_pRenderer	= pRenderer;
					}
					bool	IsFormated()
					{
						return true;
					}					
					void	RotateRect(RectF& oRect)
					{
						REAL fWidth		= oRect.Width;
						REAL fHeight	= oRect.Height;

						REAL fCenterX	= oRect.X + fWidth / 2;
						REAL fCenterY	= oRect.Y + fHeight / 2;

						oRect.Width		= fHeight;
						oRect.Height	= fWidth;
						oRect.X			= fCenterX - fHeight / 2;
						oRect.Y			= fCenterY - fWidth / 2;
					}
				public:					
					void	InitDrawText(IAVSRenderer *pRenderer, REAL fWidhtPix, REAL fHeightPix)
					{
					}
					bool	DrawText(IAVSRenderer* renderer, const float& completeness
								, const bool& transform = true, const bool& draw = true, const int& block = -1)
					{
						#ifdef TME_EMPTY_DRAWING
						return true;
						#endif

						if (m_bIsFormated && (m_arrPages.GetCount() <= 0))
							return true;

						if (!m_bIsFormated) {
							m_DocumentManager.RendererType(renderer);
							CGrapher* grapher	= new CGrapher();
							grapher->DocumentManager(&m_DocumentManager);
							grapher->FontManager(m_pFontManager);
							
							int lastPage = (int) m_arrPages.GetCount() - 1;
							CPage* prevPage = (lastPage != -1) ? m_arrPages[lastPage] : NULL;
							CPage* newPage = (*m_arrPageSequence[m_iPageSequenceIndex]).NewPage(grapher, prevPage);
							if ((m_iPageSequenceIndex == (int)m_arrPageSequence.GetCount() - 1) 
								|| !(*m_arrPageSequence[m_iPageSequenceIndex + 1]).Continuous())
								(*m_arrPageSequence[m_iPageSequenceIndex]).ReWriteColumns(false);

							bool complete = (*m_arrPageSequence[m_iPageSequenceIndex]).FillPage(*newPage, grapher);
							if (complete)
							{
								while (m_iPageSequenceIndex < (int)m_arrPageSequence.GetCount() - 1)
								{
									++m_iPageSequenceIndex;
									if ((*m_arrPageSequence[m_iPageSequenceIndex]).Continuous())
									{
										(*m_arrPageSequence[m_iPageSequenceIndex]).ContinuePage(*newPage);
										if ((m_iPageSequenceIndex == (int)m_arrPageSequence.GetCount() - 1) 
											|| !(*m_arrPageSequence[m_iPageSequenceIndex + 1]).Continuous())
											(*m_arrPageSequence[m_iPageSequenceIndex]).ReWriteColumns(false);
										complete = (*m_arrPageSequence[m_iPageSequenceIndex]).FillPage(*newPage, grapher);
										if (!complete)
											break;
									}
									else
									{
										complete = false;
										break;
									}
								}
							}

							if (complete && (m_iPageSequenceIndex == (int)m_arrPageSequence.GetCount() - 1))
								m_bIsFormated = true;

							RELEASEOBJECT(grapher);

							if (!newPage->IsEmptyBody())
							{
								m_arrPages.Add(newPage);
								m_nCurrentPage = m_arrPages.GetCount() - 1;

								if (draw)
									DrawPage(newPage, renderer, completeness, transform, block);

								if (m_bIsFo)
									Progress(0.0f);
								else
									Progress(1.0f);
							}

							if (m_bIsFo && m_bIsFormated)
							{
								Progress(1.0f);
								SendLinkerXml(renderer);
							}
						}

						return m_bIsFormated;
					}
					void	DrawTextInRect(BSTR bstrText, const RectF& textRect, IAVSRenderer* renderer, const NSStructures::CFont& font, const NSStructures::CBrush& brush, const NSStructures::CFormat& format, ITextPainter* textPainter)
					{
						CItemManager* itemManager = &m_DocumentManager.m_ItemManager;
						m_DocumentManager.m_FontManager = m_pFontManager;
						m_DocumentManager.m_TextPainter = textPainter;
						itemManager->SetWrapFlags(format.WordWrapBySymbol);

						CRegion textRegion;
						textRegion.FromRectMm(textRect);

						CPage page;

						CGrapher* grapher = new CGrapher();
						grapher->FontManager(m_pFontManager);
						grapher->DocumentManager(&m_DocumentManager);

						CBlock block;
						CString text(bstrText);						
						block.FromString(text, grapher, font, brush, format);

						page.StartPrintingFlow();
						block.FillRegion(textRegion, page, false, grapher);
						float offset = textRegion.GetRegionHeightPt();
						switch (format.StringAlignmentVertical)
						{
						case 1 :
							offset /= 2;
							break;
						case 0 :
							offset = 0;
							break;
						}
						page.MoveFlowOn(0, offset);

						page.Draw(renderer, m_DocumentManager, 1.0f);

						RELEASEOBJECT(grapher);
					}

					void	DrawFirstPage(IAVSRenderer* renderer, const float& completeness, const int& block = -1) {
						if (m_arrPages.GetCount())
							DrawPage(m_arrPages[0], renderer, completeness, false, block);
						else
							DrawText(renderer, completeness, false, true, block);
					}
					void	PrepareFirstPage(IAVSRenderer* renderer) {
						DrawText(renderer, 0, false, false);
					}
					void	TruncateByBlocks(CArray<TextMeasurer2>& blockMeasurers, const bool& removeEmpty = false) {
						blockMeasurers.RemoveAll();
						if (m_arrPages.GetCount() == 0)
							return;

						CPage& page = *m_arrPages[0];
						float height, offset;
						for (int i = 0; i < m_arrPages[0]->getBlockCount(); ++i) {
							page.getBlockMetric(i, height, offset);
							if (removeEmpty && height == 0)
								continue;
							blockMeasurers.Add(TextMeasurer2(this, i, height, offset));
						}
					}

				private:
					void	InternalFromFoXml(XmlUtils::CXmlNode &oXmlNode)
					{
						m_bIsFo	= true;

						XmlUtils::CXmlNode oDocInfoNode;
						if (oXmlNode.GetNode(_T("fo:doc-info"), oDocInfoNode))
							m_DocumentManager.loadFromXml(oDocInfoNode);

						//int iPageCount	= oDocInfoNode.ReadAttributeInt(_T("pages"), 0);
						//m_DocumentManager.SetPageCount(iPageCount);
						XmlUtils::CXmlNode fontTable;
						if (oDocInfoNode.GetNode(_T("font-table"), fontTable))							
							m_DocumentManager.FontTableFromXml(fontTable);
						m_DocumentManager.UseHtmlSpacing(XmlUtils::GetBoolean(oDocInfoNode.GetAttribute(_T("useHtmlSpacing"), _T("true"))) == TRUE);

						XmlUtils::CXmlNode oBackgroundNode;
						oDocInfoNode.GetNode(_T("w:background"), oBackgroundNode);
						m_oBGPage.PageBGFromXml(oBackgroundNode);

						XmlUtils::CXmlNode oLayoutMasterSetNode;
						oXmlNode.GetNode(_T("fo:layout-master-set"), oLayoutMasterSetNode);

						m_oLayoutMasterSet.Clear();
						m_oLayoutMasterSet.FromXmlNode(oLayoutMasterSetNode, m_DocumentManager);

						m_arrPageSequence.RemoveAll();
						CPageSequence* prev = NULL;
						XmlUtils::CXmlNodes	oPageSequenceNodes;
						oXmlNode.GetNodes(_T("fo:page-sequence"), oPageSequenceNodes);
						for (INT iIndex = 0; iIndex < oPageSequenceNodes.GetCount(); ++iIndex) {
							m_arrPageSequence.Add(new CPageSequence());
							(*m_arrPageSequence[iIndex]).SetLayoutMasterSet(&m_oLayoutMasterSet);
							(*m_arrPageSequence[iIndex]).setPrev(prev);
							prev = m_arrPageSequence[iIndex];

							XmlUtils::CXmlNode oPageSequenceNode;
							oPageSequenceNodes.GetAt(iIndex, oPageSequenceNode);
							(*m_arrPageSequence[iIndex]).loadFromXml(oPageSequenceNode, m_DocumentManager);
						}

						m_arrPages.RemoveAll();
					}					
					void	InternalFromNonFoXml(XmlUtils::CXmlNode &oXmlNode)
					{
						m_bIsFo	= FALSE;
						m_DocumentManager.UseHtmlSpacing(false);

						SetDefaultLayoutMasterSet(m_oLayoutMasterSet);

						m_strText = oXmlNode.GetAttributeOrValueExt(_T("text"), _T(""));
						FromXmlString(m_strText);

						if (m_strText == _T(""))
						{
							m_bIsFormated	= TRUE;

							return;
						}

						m_dAngle	= XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("angle"), _T("0")));
						m_lFlags	= XmlUtils::GetInteger(oXmlNode.GetAttributeOrValue(_T("flags"), _T("0")));

						m_bVertical		= (0 != XmlUtils::GetInteger(oXmlNode.GetAttributeOrValue(_T("vertical"), _T("0"))));
						m_bRightToLeft	= (0 != XmlUtils::GetInteger(oXmlNode.GetAttributeOrValue(_T("righttoleft"), _T("0"))));

						REAL fWidthL	= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("widthl"), _T("0")));
						REAL fHeightL	= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("heightl"), _T("0")));

						m_fWidthMm	= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("widthmm"), _T("0")));
						m_fHeightMm	= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("heightmm"), _T("0")));

						CItemManager *pItemManager	= &m_DocumentManager.m_ItemManager;
						pItemManager->SetWidthL(fWidthL);
						pItemManager->SetHeightL(fHeightL);
						REAL fMmToPt	= 72.0f / 25.4f;
						pItemManager->SetMultiplierX(m_fWidthMm * fMmToPt);
						pItemManager->SetMultiplierY(m_fHeightMm * fMmToPt);

						CSimplePageMaster *pSimplePageMaster	= m_oLayoutMasterSet.FindSimplePageMaster(_T("SPM"));

						m_oLayoutRect.X			= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("left"), _T("0")));
						m_oLayoutRect.Width		= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("right"), _T("0"))) 
							- m_oLayoutRect.X;
						m_oLayoutRect.Y			= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("top"), _T("0")));
						m_oLayoutRect.Height	= (REAL)XmlUtils::GetDouble(oXmlNode.GetAttributeOrValue(_T("bottom"), _T("0"))) 
							- m_oLayoutRect.Y;

						if ((m_oLayoutRect.Width == 0) || (m_oLayoutRect.Height == 0))
						{
							InternalClear();

							m_bIsFormated	= TRUE;

							return;
						}

						if (m_bVertical == TRUE)
						{
							RotateRect(m_oLayoutRect);

							m_dAngle	= 90.0f;
							m_lFlags	= 0;
						}

						CBounds oBounds;
						oBounds.SetAsRectMm(m_oLayoutRect);

						pSimplePageMaster->Init(fWidthL, fHeightL, m_fWidthMm, m_fHeightMm, oBounds, m_oBrush);

						CTextAttributes oAttributes;
						XmlUtils::CXmlNode oAttributeNode;
						if (oXmlNode.GetNode(_T("Attributes"), oAttributeNode))
						{
							oAttributes.FromXmlNode(oAttributeNode);
						}

						CAtlArray<CBlockAttributes*> arPFs;
						XmlUtils::CXmlNodes oNodesPFs;
						if (oXmlNode.GetNodes(_T("Paragraph"), oNodesPFs))
						{
							INT iCount = oNodesPFs.GetCount();
							for (INT iIndex = 0; iIndex < iCount; ++iIndex)
							{
								XmlUtils::CXmlNode oNode;
								oNodesPFs.GetAt(iIndex, oNode);
								arPFs.Add(new CBlockAttributes());
								arPFs[iIndex]->m_nTextAlignment = oAttributes.m_nTextAlignmentHorizontal;
								arPFs[iIndex]->FromXmlNode(oNode, m_DocumentManager);								
							}
							if (iCount == 0)
							{
								CBlockAttributes *pParagraph = new CBlockAttributes();
								pParagraph->FromXmlNode(oXmlNode, m_DocumentManager);
								pParagraph->m_lCount = m_strText.GetLength();
								pParagraph->m_nTextAlignment = oAttributes.m_nTextAlignmentHorizontal;
								arPFs.Add(pParagraph);
							}
							arPFs[0]->m_bIsFirst	= TRUE;
						}

						CAtlArray<CCharacter*> arCFs;
						XmlUtils::CXmlNodes oNodesCFs;
						if (oXmlNode.GetNodes(_T("Character"), oNodesCFs))
						{
							INT iCount = oNodesCFs.GetCount();
							for (INT iIndex = 0; iIndex < iCount; ++iIndex)
							{
								XmlUtils::CXmlNode oNode;
								oNodesCFs.GetAt(iIndex, oNode);
								arCFs.Add(new CCharacter());
								arCFs[iIndex]->m_oAttributes = oAttributes;								
								arCFs[iIndex]->FromXmlNode(oNode, m_DocumentManager);
							}
							if (iCount == 0)
							{
								CCharacter *pCharacter = new CCharacter();
								pCharacter->FromXmlNode(oXmlNode, m_DocumentManager);
								pCharacter->m_lCount = m_strText.GetLength();
								pCharacter->m_oAttributes = oAttributes;
								arCFs.Add(pCharacter);
							}
						}

						m_arrPageSequence.Add(new CPageSequence());
						SetDefaultPageSequence(*m_arrPageSequence[0]);

						CFlow* pFirstFlow	= (*m_arrPageSequence[0]).GetFirstFlow();

						pFirstFlow->SetAlignVertical((CAlignVertical)oAttributes.m_nTextAlignmentVertical);

						if (!Normalize(&arPFs, &arCFs, pFirstFlow->GetBlocks()))
							InternalClear();

						m_arrPages.RemoveAll();
					}
					void	SetDefaultLayoutMasterSet(CLayoutMasterSet &oLayoutMasterSet)
					{
						oLayoutMasterSet.Clear();

						CString strXml	= _T("<fo:layout-master-set xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">");
						strXml			+= _T("<fo:simple-page-master master-name=\"SPM\" margin-left=\"0pt\" margin-top=\"0pt\" margin-right=\"0pt\" margin-bottom=\"0pt\">");
						strXml			+= _T("<fo:region-body region-name=\"R\"/>");
						strXml			+= _T("</fo:simple-page-master>");
						strXml			+= _T("<fo:flow-map flow-map-name=\"FM\">");
						strXml			+= _T("<fo:flow-assignment>");
						strXml			+= _T("<fo:flow-source-list>");
						strXml			+= _T("<fo:flow-name-specifier flow-name-reference=\"F\"/>");
						strXml			+= _T("</fo:flow-source-list>");
						strXml			+= _T("<fo:flow-target-list>");
						strXml			+= _T("<fo:region-name-specifier region-name-reference=\"R\"/>");
						strXml			+= _T("</fo:flow-target-list>");
						strXml			+= _T("</fo:flow-assignment>");
						strXml			+= _T("</fo:flow-map>");
						strXml			+= _T("<fo:page-sequence-master master-name=\"PSM\">");
						strXml			+= _T("<fo:repeatable-page-master-alternatives>");
						strXml			+= _T("<fo:conditional-page-master-reference odd-or-even=\"odd\" master-reference=\"SPM\"/>");
						strXml			+= _T("<fo:conditional-page-master-reference odd-or-even=\"even\" master-reference=\"SPM\"/>");
						strXml			+= _T("</fo:repeatable-page-master-alternatives>");
						strXml			+= _T("</fo:page-sequence-master>");
						strXml			+= _T("</fo:layout-master-set>");

						XmlUtils::CXmlNode oNode;
						oNode.FromXmlString(strXml, _T("xmlns:fo='http://www.w3.org/1999/XSL/Format'"));
						oLayoutMasterSet.FromXmlNode(oNode, m_DocumentManager);
					}
					void	SetDefaultPageSequence(CPageSequence &oPageSequence)
					{
						oPageSequence.Clear();

						CString strXml = _T("<fo:page-sequence xmlns:fo=\"http://www.w3.org/1999/XSL/Format\" master-reference=\"PSM\" flow-map-reference=\"FM\">");
						strXml += _T("<fo:flow flow-name=\"R\">");
						strXml += _T("</fo:flow>");
						strXml += _T("</fo:page-sequence>");

						XmlUtils::CXmlNode oNode;
						oNode.FromXmlString(strXml, _T("xmlns:fo=\"http://www.w3.org/1999/XSL/Format\""));
						oPageSequence.SetLayoutMasterSet(&m_oLayoutMasterSet);
						oPageSequence.loadFromXml(oNode, m_DocumentManager);
					}
					bool	Normalize(CAtlArray<CBlockAttributes*> *pArrayPFs, CAtlArray<CCharacter*> *pArrayCFs, 
						CAtlArray<CCommonBlock*> &arrParagraphs)
					{
						size_t nParagraphsCount		= pArrayPFs->GetCount();
						size_t nCharactersCount		= pArrayCFs->GetCount();
						size_t nTextLength			= m_strText.GetLength();
						size_t nCurrentSymbolIndex	= 0;

						size_t nIndex			= 0;
						size_t nSymbolsCount	= 0;
						for (; nIndex < nParagraphsCount; ++nIndex)
						{
							nSymbolsCount	+= (*pArrayPFs)[nIndex]->m_lCount;
							if (nSymbolsCount >= nTextLength)
							{
								break;
							}
						}
						if (nIndex < nParagraphsCount - 1)
						{
							for (size_t i = nIndex + 1; i < nParagraphsCount; ++i)
							{
								RELEASEOBJECT((*pArrayPFs)[i]);
							}
							pArrayPFs->RemoveAt(nIndex + 1, nParagraphsCount - nIndex - 1);
							nParagraphsCount	= pArrayPFs->GetCount();
						}
						if (nSymbolsCount != nTextLength)
						{
							CBlockAttributes *pParagraph	= (*pArrayPFs)[nParagraphsCount - 1];
							pParagraph->m_lCount					+= (LONG)(nTextLength - nSymbolsCount);
						}

						size_t nCurrentCharacter	= 0;
						for (size_t nIndex = 0; nIndex < nParagraphsCount; ++ nIndex)
						{
							CBlockAttributes *pParagraph = (*pArrayPFs)[nIndex];
							CBlock *pTextParagraph = new CBlock;
							arrParagraphs.Add(pTextParagraph);	
							pTextParagraph->m_pBlockAttributes = pParagraph;
							size_t nSymbolsCount	= 0;
							size_t nParagraphLen	= pParagraph->m_lCount;
							for (; nCurrentCharacter < nCharactersCount; ++nCurrentCharacter)
							{
								if (nSymbolsCount >= nParagraphLen)
								{
									break;
								}
								CCharacter *pCharacter	= (*pArrayCFs)[nCurrentCharacter];
								size_t nCharacterLen	= pCharacter->m_lCount;
								if (nCharacterLen == 0)
								{
									RELEASEOBJECT(pCharacter);
									continue;
								}
								if (nSymbolsCount + nCharacterLen <= nParagraphLen)
								{
									nSymbolsCount	+= nCharacterLen;
									pTextParagraph->m_Items.AddCharacter(pCharacter);
								}
								else
								{
									CCharacter *pNewCharacter		= new CCharacter();
									pNewCharacter->m_oAttributes	= pCharacter->m_oAttributes;
									pNewCharacter->m_lCount			= (LONG)(nParagraphLen - nSymbolsCount);
									pCharacter->m_lCount			-= pNewCharacter->m_lCount;
									nSymbolsCount					+= pNewCharacter->m_lCount;
									pTextParagraph->m_Items.AddCharacter(pNewCharacter);
									break;
								}
							}
							if (nSymbolsCount < nParagraphLen)
							{
								if (pTextParagraph->m_Items.CountCharacters() != 0)
								{
									int nLastCharacterIndex	= pTextParagraph->m_Items.CountCharacters() - 1;
									CCharacter *pLastCharacter	= pTextParagraph->m_Items.GetCharacter(nLastCharacterIndex);
									pLastCharacter->m_lCount	+= (LONG)(nParagraphLen - nSymbolsCount);
								}
								else
								{
									CCharacter *pNewCharacter		= new CCharacter();
									size_t nLastCharacterIndex		= nCharactersCount - 1;
									CCharacter *pLastCharacter		= (*pArrayCFs)[nLastCharacterIndex];
									pNewCharacter->m_oAttributes	= pLastCharacter->m_oAttributes;
									pNewCharacter->m_lCount			= pTextParagraph->m_pBlockAttributes->m_lCount;									
									pTextParagraph->m_Items.AddCharacter(pNewCharacter);
								}
							}
							pTextParagraph->m_Items.Text(m_strText.Mid((int)nCurrentSymbolIndex, (int)pParagraph->m_lCount));
							nCurrentSymbolIndex			+= pParagraph->m_lCount;
						}
						if (nCurrentCharacter < nCharactersCount)
						{
							for (size_t i = nCurrentCharacter; i < nCharactersCount; ++i)
							{
								RELEASEOBJECT((*pArrayCFs)[i]);
							}
							pArrayCFs->RemoveAt(nCurrentCharacter, nCharactersCount - nCurrentCharacter);
						}
						m_bIsFormated = false;
						return TRUE;
					}

				private:
					void	DrawPage(CPage* page, IAVSRenderer* renderer, const float& completeness, const bool& transform = true, const int& block = -1) {
						if (m_bIsFo) {
							m_fWidthMm = page->GetWidthMm();
							m_fHeightMm = page->GetHeightMm();
							IWorker_OnNewPage(m_fWidthMm, m_fHeightMm);

							CBackgroundRect* pageRect = m_oBGPage.GetBackgroundRect2(0, 0, m_fWidthMm, m_fHeightMm);
							pageRect->Draw(renderer, completeness);
							RELEASEOBJECT(pageRect);

							if (block == -1)
								page->Draw(renderer, m_DocumentManager, completeness);
							else
								page->Draw(renderer, m_DocumentManager, block, completeness);
							IWorker_OnCompletePage();
						}
						else {
							#ifdef TME_DEBUG_VSXML
							m_fWidthMm = page->GetWidthMm();
							m_fHeightMm = page->GetHeightMm();
							IWorker_OnNewPage(m_fWidthMm, m_fHeightMm);
							#endif

							SetRenderer(renderer);
							if (transform)
								renderer->SetCommandParams(m_dAngle, m_oLayoutRect.X, m_oLayoutRect.Y, 
										m_oLayoutRect.Width, m_oLayoutRect.Height, m_lFlags);
							if (block == -1)
								page->Draw(renderer, m_DocumentManager, completeness);
							else
								page->Draw(renderer, m_DocumentManager, block, completeness);
							if (transform)
								renderer->SetCommandParams(0, -1, -1, -1, -1, 0);
							
							#ifdef TME_DEBUG_VSXML
							IWorker_OnCompletePage();
							#endif
						}
					}
					void	Progress(const float &fProgress)
					{
						if (fProgress > 0.0f)
						{
							IWorker_OnProgress(fProgress);
						}
						else
						{
							IWorker_OnProgress(m_DocumentManager.GetCompleteness());
						}
					}
					void	SendLinkerXml(IAVSRenderer *pRenderer)
					{
						BSTR bstrHyperlinkXml	= m_DocumentManager.m_Linker.GenerateXml();

						pRenderer->BeginCommand(c_nHyperlinkType);
						pRenderer->CommandDrawText(bstrHyperlinkXml, 0, 0, 0, 0, 0);
						pRenderer->EndCommand(c_nHyperlinkType);
					}
				protected:
					void	InitFontManager()
					{
						m_pFontManager = CGrapher::GenerateFontManager();
						//ADDREFINTERFACE(m_pFontManager);
					}

				};
			}
		}
	}
}