diff --git a/DocxRenderer/DocxRenderer.h b/DocxRenderer/DocxRenderer.h index 0972389254..4865c88d3f 100644 --- a/DocxRenderer/DocxRenderer.h +++ b/DocxRenderer/DocxRenderer.h @@ -62,7 +62,7 @@ class DOCXRENDERER_DECL_EXPORT CDocxRenderer : public IRenderer { public: CDocxRenderer(NSFonts::IApplicationFonts* pAppFonts); - ~CDocxRenderer(); + virtual ~CDocxRenderer(); HRESULT CreateNewFile(const std::wstring& wsPath, bool bIsOutCompress = true); HRESULT Close(); diff --git a/DocxRenderer/DocxRenderer.pro b/DocxRenderer/DocxRenderer.pro index f2ba455e25..15d2d681c6 100644 --- a/DocxRenderer/DocxRenderer.pro +++ b/DocxRenderer/DocxRenderer.pro @@ -40,6 +40,9 @@ HEADERS += \ DocxRenderer.h SOURCES += \ + src/logic/Document.cpp \ + src/logic/ElementParagraph.cpp \ + src/logic/Page.cpp \ src/resources/resources.cpp \ \ DocxRenderer.cpp diff --git a/DocxRenderer/src/logic/Document.cpp b/DocxRenderer/src/logic/Document.cpp new file mode 100644 index 0000000000..498a5e65e9 --- /dev/null +++ b/DocxRenderer/src/logic/Document.cpp @@ -0,0 +1,952 @@ +#include "Document.h" + +namespace NSDocxRenderer +{ + CDocument::CDocument(IRenderer* pRenderer, NSFonts::IApplicationFonts* pFonts) : + m_oCurrentPage(pFonts), m_oWriter() + { + m_pAppFonts = pFonts; + m_oSimpleGraphicsConverter.SetRenderer(pRenderer); + m_lCurrentCommandType = 0; + + m_dWidth = 0; + m_dHeight = 0; + + m_dDpiX = 72; + m_dDpiY = 72; + + m_strTempDirectory = L""; + m_lPagesCount = 0; + + m_bIsNeedPDFTextAnalyzer = false; + m_pFontManager = NULL; + + m_bIsDisablePageCommand = false; + } + void CDocument::Clear() + { + m_lClipMode = 0; + } + + CDocument::~CDocument() + { + m_lClipMode = 0; + RELEASEINTERFACE(m_pFontManager); + } + + HRESULT CDocument::NewPage() + { + if (0 != m_lPagesCount) + { + m_oCurrentPage.WriteSectionToFile(false, m_oWriter); + m_oDocumentStream.WriteStringUTF8(m_oWriter.GetData()); + m_oWriter.ClearNoAttack(); + } + + m_oPen.SetDefaultParams(); + m_oBrush.SetDefaultParams(); + m_oFont.SetDefaultParams(); + m_oShadow.SetDefaultParams(); + m_oEdge.SetDefaultParams(); + + m_oTransform.Reset(); + + ++m_lPagesCount; + m_oCurrentPage.Clear(); + + return S_OK; + } + HRESULT CDocument::get_Height(double* dHeight) + { + *dHeight = m_dHeight; + return S_OK; + } + HRESULT CDocument::put_Height(double dHeight) + { + m_dHeight = dHeight; + m_oCurrentPage.m_dHeight = dHeight; + return S_OK; + } + HRESULT CDocument::get_Width(double* dWidth) + { + *dWidth = m_dWidth; + return S_OK; + } + HRESULT CDocument::put_Width(double dWidth) + { + m_dWidth = dWidth; + m_oCurrentPage.m_dWidth = dWidth; + return S_OK; + } + HRESULT CDocument::get_DpiX(double* dDpiX) + { + *dDpiX = m_dDpiX; + return S_OK; + } + HRESULT CDocument::get_DpiY(double* dDpiY) + { + *dDpiY = m_dDpiY; + return S_OK; + } + //-------- Функции для задания настроек текста ---------------------------------------------- + // pen -------------------------------------------------------------------------------------- + HRESULT CDocument::get_PenColor(LONG* lColor) + { + *lColor = m_oPen.Color; + return S_OK; + } + HRESULT CDocument::put_PenColor(LONG lColor) + { + m_oPen.Color = lColor; + return S_OK; + } + HRESULT CDocument::get_PenAlpha(LONG* lAlpha) + { + *lAlpha = m_oPen.Alpha; + return S_OK; + } + HRESULT CDocument::put_PenAlpha(LONG lAlpha) + { + m_oPen.Alpha = lAlpha; + return S_OK; + } + HRESULT CDocument::get_PenSize(double* dSize) + { + *dSize = m_oPen.Size; + return S_OK; + } + HRESULT CDocument::put_PenSize(double dSize) + { + m_oPen.Size = dSize; + return S_OK; + } + HRESULT CDocument::get_PenDashStyle(BYTE* val) + { + *val = m_oPen.DashStyle; + return S_OK; + } + HRESULT CDocument::put_PenDashStyle(BYTE val) + { + m_oPen.DashStyle = val; + return S_OK; + } + HRESULT CDocument::get_PenLineStartCap(BYTE* val) + { + *val = m_oPen.LineStartCap; + return S_OK; + } + HRESULT CDocument::put_PenLineStartCap(BYTE val) + { + m_oPen.LineStartCap = val; + return S_OK; + } + HRESULT CDocument::get_PenLineEndCap(BYTE* val) + { + *val = m_oPen.LineEndCap; + return S_OK; + } + HRESULT CDocument::put_PenLineEndCap(BYTE val) + { + m_oPen.LineEndCap = val; + return S_OK; + } + HRESULT CDocument::get_PenLineJoin(BYTE* val) + { + *val = m_oPen.LineJoin; + return S_OK; + } + HRESULT CDocument::put_PenLineJoin(BYTE val) + { + m_oPen.LineJoin = val; + return S_OK; + } + HRESULT CDocument::get_PenDashOffset(double* val) + { + *val = m_oPen.DashOffset; + return S_OK; + } + HRESULT CDocument::put_PenDashOffset(double val) + { + m_oPen.DashOffset = val; + return S_OK; + } + HRESULT CDocument::get_PenAlign(LONG* val) + { + *val = m_oPen.Align; + return S_OK; + } + HRESULT CDocument::put_PenAlign(LONG val) + { + m_oPen.Align = val; + return S_OK; + } + HRESULT CDocument::get_PenMiterLimit(double* val) + { + *val = m_oPen.MiterLimit; + return S_OK; + } + HRESULT CDocument::put_PenMiterLimit(double val) + { + m_oPen.MiterLimit = val; + return S_OK; + } + HRESULT CDocument::PenDashPattern(double* pPattern, LONG lCount) + { + if (NULL != pPattern) + { + m_oPen.SetDashPattern(pPattern, lCount); + } + + return S_OK; + } + // brush ------------------------------------------------------------------------------------ + HRESULT CDocument::get_BrushType(LONG* lType) + { + *lType = m_oBrush.Type; + return S_OK; + } + HRESULT CDocument::put_BrushType(LONG lType) + { + m_oBrush.Type = lType; + return S_OK; + } + HRESULT CDocument::get_BrushColor1(LONG* lColor) + { + *lColor = m_oBrush.Color1; + return S_OK; + } + HRESULT CDocument::put_BrushColor1(LONG lColor) + { + m_oBrush.Color1 = lColor; + return S_OK; + } + HRESULT CDocument::get_BrushAlpha1(LONG* lAlpha) + { + *lAlpha = m_oBrush.Alpha1; + return S_OK; + } + HRESULT CDocument::put_BrushAlpha1(LONG lAlpha) + { + m_oBrush.Alpha1 = lAlpha; + return S_OK; + } + HRESULT CDocument::get_BrushColor2(LONG* lColor) + { + *lColor = m_oBrush.Color2; + return S_OK; + } + HRESULT CDocument::put_BrushColor2(LONG lColor) + { + m_oBrush.Color2 = lColor; + return S_OK; + } + HRESULT CDocument::get_BrushAlpha2(LONG* lAlpha) + { + *lAlpha = m_oBrush.Alpha2; + return S_OK; + } + HRESULT CDocument::put_BrushAlpha2(LONG lAlpha) + { + m_oBrush.Alpha2 = lAlpha; + return S_OK; + } + HRESULT CDocument::get_BrushTexturePath(std::wstring* sPath) + { + *sPath = m_oBrush.TexturePath; + return S_OK; + } + HRESULT CDocument::put_BrushTexturePath(const std::wstring& sPath) + { + m_oBrush.TexturePath = sPath; + return S_OK; + } + HRESULT CDocument::get_BrushTextureMode(LONG* lMode) + { + *lMode = m_oBrush.TextureMode; + return S_OK; + } + HRESULT CDocument::put_BrushTextureMode(LONG lMode) + { + m_oBrush.TextureMode = lMode; + return S_OK; + } + HRESULT CDocument::get_BrushTextureAlpha(LONG* lTxAlpha) + { + *lTxAlpha = m_oBrush.TextureAlpha; + return S_OK; + } + HRESULT CDocument::put_BrushTextureAlpha(LONG lTxAlpha) + { + m_oBrush.TextureAlpha = lTxAlpha; + return S_OK; + } + HRESULT CDocument::get_BrushLinearAngle(double* dAngle) + { + *dAngle = m_oBrush.LinearAngle; + return S_OK; + } + HRESULT CDocument::put_BrushLinearAngle(double dAngle) + { + m_oBrush.LinearAngle = dAngle; + return S_OK; + } + HRESULT CDocument::BrushRect(bool val, double left, double top, double width, double height) + { + m_oBrush.Rectable = val ? 1 : 0; + m_oBrush.Rect.X = (float)left; + m_oBrush.Rect.Y = (float)top; + m_oBrush.Rect.Width = (float)width; + m_oBrush.Rect.Height = (float)height; + + return S_OK; + } + // font ------------------------------------------------------------------------------------- + HRESULT CDocument::get_FontName(std::wstring* sName) + { + *sName = m_oFont.Name; + return S_OK; + } + HRESULT CDocument::put_FontName(std::wstring sName) + { + m_oFont.Name = sName; + return S_OK; + } + HRESULT CDocument::get_FontPath(std::wstring* sPath) + { + *sPath = m_oFont.Path; + return S_OK; + } + HRESULT CDocument::put_FontPath(std::wstring sPath) + { + m_oFont.Path = sPath; + return S_OK; + } + HRESULT CDocument::get_FontSize(double* dSize) + { + *dSize = m_oFont.Size; + return S_OK; + } + HRESULT CDocument::put_FontSize(double dSize) + { + m_oFont.Size = dSize; + return S_OK; + } + HRESULT CDocument::get_FontStyle(LONG* lStyle) + { + *lStyle = m_oFont.GetStyle(); + return S_OK; + } + HRESULT CDocument::put_FontStyle(LONG lStyle) + { + m_oFont.SetStyle(lStyle); + return S_OK; + } + HRESULT CDocument::get_FontStringGID(INT* bGID) + { + *bGID = m_oFont.StringGID; + return S_OK; + } + HRESULT CDocument::put_FontStringGID(INT bGID) + { + m_oFont.StringGID = bGID; + return S_OK; + } + HRESULT CDocument::get_FontCharSpace(double* dSpace) + { + *dSpace = m_oFont.CharSpace; + return S_OK; + } + HRESULT CDocument::put_FontCharSpace(double dSpace) + { + m_oFont.CharSpace = dSpace; + return S_OK; + } + HRESULT CDocument::get_FontFaceIndex(int* lFaceIndex) + { + *lFaceIndex = m_oFont.FaceIndex; + return S_OK; + } + HRESULT CDocument::put_FontFaceIndex(const int& lFaceIndex) + { + m_oFont.FaceIndex = lFaceIndex; + return S_OK; + } + // shadow ----------------------------------------------------------------------------------- + HRESULT CDocument::get_ShadowDistanceX(double* val) + { + *val = m_oShadow.DistanceX; + return S_OK; + } + HRESULT CDocument::put_ShadowDistanceX(double val) + { + m_oShadow.DistanceX = val; + return S_OK; + } + HRESULT CDocument::get_ShadowDistanceY(double* val) + { + *val = m_oShadow.DistanceY; + return S_OK; + } + HRESULT CDocument::put_ShadowDistanceY(double val) + { + m_oShadow.DistanceY = val; + return S_OK; + } + HRESULT CDocument::get_ShadowBlurSize(double* val) + { + *val = m_oShadow.BlurSize; + return S_OK; + } + HRESULT CDocument::put_ShadowBlurSize(double val) + { + m_oShadow.BlurSize = val; + return S_OK; + } + HRESULT CDocument::get_ShadowColor(LONG* val) + { + *val = m_oShadow.Color; + return S_OK; + } + HRESULT CDocument::put_ShadowColor(LONG val) + { + m_oShadow.Color = val; + return S_OK; + } + HRESULT CDocument::get_ShadowAlpha(LONG* val) + { + *val = m_oShadow.Alpha; + return S_OK; + } + HRESULT CDocument::put_ShadowAlpha(LONG val) + { + m_oShadow.Alpha = val; + return S_OK; + } + HRESULT CDocument::get_ShadowVisible(INT* val) + { + *val = m_oShadow.Visible; + return S_OK; + } + HRESULT CDocument::put_ShadowVisible(INT val) + { + m_oShadow.Visible = val; + return S_OK; + } + // edge ------------------------------------------------------------------------------------- + HRESULT CDocument::get_EdgeVisible(LONG* val) + { + *val = m_oEdge.Visible; + return S_OK; + } + HRESULT CDocument::put_EdgeVisible(LONG val) + { + m_oEdge.Visible = val; + return S_OK; + } + HRESULT CDocument::get_EdgeColor(LONG* val) + { + *val = m_oEdge.Color; + return S_OK; + } + HRESULT CDocument::put_EdgeColor(LONG val) + { + m_oEdge.Color = val; + return S_OK; + } + HRESULT CDocument::get_EdgeAlpha(LONG* val) + { + *val = m_oEdge.Alpha; + return S_OK; + } + HRESULT CDocument::put_EdgeAlpha(LONG val) + { + m_oEdge.Alpha = val; + return S_OK; + } + HRESULT CDocument::get_EdgeDist(double* val) + { + *val = m_oEdge.Dist; + return S_OK; + } + HRESULT CDocument::put_EdgeDist(double val) + { + m_oEdge.Dist = val; + return S_OK; + } + + //-------- Функции для вывода текста -------------------------------------------------------- + HRESULT CDocument::CommandDrawTextPrivate(const int* pUnicodes, const int* pGids, int nCount, + const double& dX, const double& dY, const double& dW, + const double& dH, const double& dBaseLineOffset) + { + double dAngleMatrix = m_oTransform.z_Rotation(); + if (abs(dAngleMatrix) > 1 || m_oTransform.sx() < 0 || m_oTransform.sy() < 0) + { + _SetFont(); + PathCommandEnd(); + BeginCommand(c_nPathType); + m_oSimpleGraphicsConverter.PathCommandText2(pUnicodes, pGids, nCount, m_pFontManager, dX, dY, dW, dH); + DrawPath(c_nWindingFillMode); + EndCommand(c_nPathType); + PathCommandEnd(); + return S_OK; + } + + m_oCurrentPage.WriteText((unsigned int*)pUnicodes, (unsigned int*)pGids, nCount, dX, dY, dW, dH, 0, m_bIsNeedPDFTextAnalyzer); + return S_OK; + } + + HRESULT CDocument::CommandDrawTextCHAR(const int& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH) + { + return CommandDrawTextPrivate(&lUnicode, NULL, 1, dX, dY, dW, dH); + } + HRESULT CDocument::CommandDrawTextExCHAR(const int& lUnicode, const int& lGid, const double& dX, const double& dY, const double& dW, const double& dH) + { + return CommandDrawTextPrivate(&lUnicode, &lGid, 1, dX, dY, dW, dH); + } + HRESULT CDocument::CommandDrawText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH) + { + unsigned int nLen = 0; + unsigned int* pUnicodes = NSStringExt::CConverter::GetUtf32FromUnicode(wsUnicodeText, nLen); + if (nLen == 0) + return S_OK; + CommandDrawTextPrivate((int*)pUnicodes, NULL, nLen, dX, dY, dW, dH); + delete [] pUnicodes; + return S_OK; + } + HRESULT CDocument::CommandDrawTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH) + { + unsigned int nLen = 0; + unsigned int* pUnicodes = NSStringExt::CConverter::GetUtf32FromUnicode(wsUnicodeText, nLen); + if (nLen == 0) + return S_OK; + if (nLen != nGidsCount) + { + delete [] pUnicodes; + return S_OK; + } + + CommandDrawTextPrivate((int*)pUnicodes, (int*)pGids, (int)nLen, dX, dY, dW, dH); + delete [] pUnicodes; + return S_OK; + } + //-------- Маркеры для команд --------------------------------------------------------------- + HRESULT CDocument::BeginCommand(DWORD lType) + { + if (c_nPageType == lType && m_bIsDisablePageCommand) + return S_OK; + + m_lCurrentCommandType = (LONG)lType; + m_oCurrentPage.m_lCurrentCommand = m_lCurrentCommandType; + + if (c_nTextType == lType) + m_oCurrentPage.m_dLastTextX_block = -1; + + return S_OK; + } + HRESULT CDocument::EndCommand(DWORD lType) + { + if (c_nPageType == lType && m_bIsDisablePageCommand) + return S_OK; + + m_lCurrentCommandType = -1; + m_oCurrentPage.m_lCurrentCommand = m_lCurrentCommandType; + + if (c_nPageType == lType) + { + // нужно записать страницу в файл + m_oCurrentPage.Build(); + m_oCurrentPage.Write(m_oWriter); + } + else if (c_nPathType == lType) + { + m_oCurrentPage.End(); + } + + if (c_nTextType == lType) + m_oCurrentPage.m_dLastTextX_block = -1; + + return S_OK; + } + //-------- Функции для работы с Graphics Path ----------------------------------------------- + HRESULT CDocument::PathCommandMoveTo(double fX, double fY) + { + if (c_nSimpleGraphicType == m_lCurrentCommandType) + { + m_oCurrentPage.MoveTo(fX, fY); + } + else + { + m_oSimpleGraphicsConverter.PathCommandMoveTo(fX, fY); + } + return S_OK; + } + HRESULT CDocument::PathCommandLineTo(double fX, double fY) + { + if (c_nSimpleGraphicType == m_lCurrentCommandType) + { + m_oCurrentPage.LineTo(fX, fY); + } + else + { + m_oSimpleGraphicsConverter.PathCommandLineTo(fX, fY); + } + return S_OK; + } + HRESULT CDocument::PathCommandLinesTo(double* pPoints, LONG lCount) + { + m_oSimpleGraphicsConverter.PathCommandLinesTo(pPoints, lCount); + return S_OK; + } + HRESULT CDocument::PathCommandCurveTo(double fX1, double fY1, double fX2, double fY2, double fX3, double fY3) + { + if (c_nSimpleGraphicType == m_lCurrentCommandType) + { + m_oCurrentPage.CurveTo(fX1, fY1, fX2, fY2, fX3, fY3); + } + else + { + m_oSimpleGraphicsConverter.PathCommandCurveTo(fX1, fY1, fX2, fY2, fX3, fY3); + } + return S_OK; + } + HRESULT CDocument::PathCommandCurvesTo(double* pPoints, LONG lCount) + { + m_oSimpleGraphicsConverter.PathCommandCurvesTo(pPoints, lCount); + return S_OK; + } + HRESULT CDocument::PathCommandArcTo(double fX, double fY, double fWidth, double fHeight, double fStartAngle, double fSweepAngle) + { + m_oSimpleGraphicsConverter.PathCommandArcTo(fX, fY, fWidth, fHeight, fStartAngle, fSweepAngle); + return S_OK; + } + HRESULT CDocument::PathCommandClose() + { + if (c_nSimpleGraphicType == m_lCurrentCommandType) + { + m_oCurrentPage.Close(); + } + else + { + m_oSimpleGraphicsConverter.PathCommandClose(); + } + return S_OK; + } + HRESULT CDocument::PathCommandEnd() + { + if (c_nSimpleGraphicType == m_lCurrentCommandType) + { + m_oCurrentPage.End(); + } + else + { + m_oSimpleGraphicsConverter.PathCommandEnd(); + } + return S_OK; + } + HRESULT CDocument::DrawPath(long nType) + { + LONG lTxId = -1; + if ((nType > 0xFF) && (c_BrushTypeTexture == m_oBrush.Type)) + { + double x = 0; + double y = 0; + double w = 0; + double h = 0; + CImageInfo oInfo = m_oManager.WriteImage(m_oBrush.TexturePath, x, y, w, h); + lTxId = oInfo.m_nId; + } + + m_oCurrentPage.DrawPath(nType, lTxId); + return S_OK; + } + HRESULT CDocument::PathCommandStart() + { + if (c_nSimpleGraphicType == m_lCurrentCommandType) + { + m_oCurrentPage.Start(); + } + else + { + m_oSimpleGraphicsConverter.PathCommandStart(); + } + return S_OK; + } + HRESULT CDocument::PathCommandGetCurrentPoint(double* fX, double* fY) + { + m_oSimpleGraphicsConverter.PathCommandGetCurrentPoint(fX, fY); + return S_OK; + } + + HRESULT CDocument::PathCommandTextCHAR(const int& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH) + { + _SetFont(); + m_oSimpleGraphicsConverter.PathCommandText2(&lUnicode, NULL, 1, m_pFontManager, dX, dY, dW, dH); + return S_OK; + } + HRESULT CDocument::PathCommandTextExCHAR(const int& lUnicode, const int& lGid, const double& dX, const double& dY, const double& dW, const double& dH) + { + _SetFont(); + m_oSimpleGraphicsConverter.PathCommandText2(&lUnicode, &lGid, 1, m_pFontManager, dX, dY, dW, dH); + return S_OK; + } + HRESULT CDocument::PathCommandText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH) + { + _SetFont(); + m_oSimpleGraphicsConverter.PathCommandText(wsUnicodeText, m_pFontManager, dX, dY, dW, dH, 0); + return S_OK; + } + HRESULT CDocument::PathCommandTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH) + { + _SetFont(); + m_oSimpleGraphicsConverter.PathCommandText2(wsUnicodeText, (const int*)pGids, nGidsCount, m_pFontManager, dX, dY, dW, dH); + return S_OK; + } + + HRESULT CDocument::GetCommandParams(double* dAngle, double* dLeft, double* dTop, double* dWidth, double* dHeight, DWORD* lFlags) + { + return S_OK; + } + HRESULT CDocument::SetCommandParams(double dAngle, double dLeft, double dTop, double dWidth, double dHeight, DWORD lFlags) + { + ApplyTransform2(dAngle, dLeft, dTop, dWidth, dHeight, lFlags); + return S_OK; + } + //-------- Функции для вывода изображений -------------------------------------------------- + HRESULT CDocument::DrawImage(IGrObject* pImage, double fX, double fY, double fWidth, double fHeight) + { + CImageInfo oInfo = m_oManager.WriteImage((Aggplus::CImage*)pImage, fX, fY, fWidth, fHeight); + m_oCurrentPage.WriteImage(oInfo, fX, fY, fWidth, fHeight); + return S_OK; + } + HRESULT CDocument::DrawImageFromFile(const std::wstring& sVal, double fX, double fY, double fWidth, double fHeight) + { + CImageInfo oInfo = m_oManager.WriteImage(sVal, fX, fY, fWidth, fHeight); + m_oCurrentPage.WriteImage(oInfo, fX, fY, fWidth, fHeight); + return S_OK; + } + //------------------------------------------------------------------------------------------ + HRESULT CDocument::SetTransform(double dA, double dB, double dC, double dD, double dE, double dF) + { + ApplyTransform(dA, dB, dC, dD, dE, dF); + return S_OK; + } + HRESULT CDocument::GetTransform(double *pdA, double *pdB, double *pdC, double *pdD, double *pdE, double *pdF) + { + return S_OK; + } + HRESULT CDocument::ResetTransform(void) + { + m_oTransform.Reset(); + return S_OK; + } + HRESULT CDocument::get_ClipMode(LONG* plMode) + { + *plMode = m_lClipMode; + return S_OK; + } + HRESULT CDocument::put_ClipMode(LONG lMode) + { + m_lClipMode = lMode; + return S_OK; + } + + void CDocument::ApplyTransform(double d1, double d2, double d3, double d4, double d5, double d6) + { + m_oTransform.SetElements(d1, d2, d3, d4, d5, d6); + } + + void CDocument::ApplyTransform2(double dAngle, double dLeft, double dTop, double dWidth, double dHeight, DWORD lFlags) + { + if ((dWidth <= 1) || (dHeight <= 1)) + lFlags = 0; + + bool bFlipX = (0 != (c_nParamFlipX & lFlags)); + bool bFlipY = (0 != (c_nParamFlipY & lFlags)); + + double m11 = bFlipX ? -1.0 : 1.0; + double m22 = bFlipY ? -1.0 : 1.0; + + Aggplus::CMatrix oMatrix(1, 0, 0, 1, 0, 0); + + if ((0 != dAngle) || (0 != lFlags)) + { + double dCentreX = (dLeft + dWidth / 2.0); + double dCentreY = (dTop + dHeight / 2.0); + + oMatrix.Translate(-dCentreX, -dCentreY , Aggplus::MatrixOrderAppend); + + oMatrix.Rotate(dAngle , Aggplus::MatrixOrderAppend); + oMatrix.Scale(m11, m22 , Aggplus::MatrixOrderAppend); + + oMatrix.Translate(dCentreX, dCentreY , Aggplus::MatrixOrderAppend); + } + + m_oTransform = oMatrix; + } + + void CDocument::_SetFont() + { + if (NULL == m_pFontManager) + { + m_pFontManager = NSFontManager::CreateFontManager(m_pAppFonts); + } + + double dPix = m_oFont.CharSpace * m_dDpiX / 25.4; + + if (m_oInstalledFont.IsEqual(&m_oFont)) + { + if (1 < m_dWidth) + { + m_pFontManager->SetCharSpacing(dPix); + } + return; + } + + m_pFontManager->SetStringGID(m_oFont.StringGID); + if (1 < m_dWidth) + { + m_pFontManager->SetCharSpacing(dPix); + } + + if (m_oFont.Path.empty()) + { + m_pFontManager->LoadFontByName(m_oFont.Name, (float)m_oFont.Size, m_oFont.GetStyle(), m_dDpiX, m_dDpiY); + } + else + { + m_pFontManager->LoadFontFromFile(m_oFont.Path, m_oFont.FaceIndex, (float)m_oFont.Size, m_dDpiX, m_dDpiY); + } + + m_oInstalledFont = m_oFont; + } + + bool CDocument::CreateDocument() + { + CreateTemplate(m_strTempDirectory); + + // Init + Clear(); + + m_lCurrentCommandType = 0; + m_oCurrentPage.Init(&m_oFont, &m_oPen, &m_oBrush, &m_oShadow, &m_oEdge, &m_oTransform, &m_oSimpleGraphicsConverter); + + m_oManager.NewDocument(); + // media + m_oManager.m_strDstMedia = m_strTempDirectory + L"/word/media"; + NSDirectory::CreateDirectory(m_oManager.m_strDstMedia); + + m_oCurrentPage.m_oManager.m_oFontTable.m_mapTable.clear(); + + m_oDocumentStream.CloseFile(); + m_oDocumentStream.CreateFileW(m_strTempDirectory + L"/word/document.xml"); + m_oDocumentStream.WriteStringUTF8(L"\ +\ +"); + + m_lPagesCount = 0; + m_oWriter.Clear(); + m_oWriter.AddSize(10000); + + return true; + } + + void CDocument::Close() + { + // сохраним rels (images & docs) + NSStringUtils::CStringBuilder oWriter; + + oWriter.WriteString(L"\ +\ +\ +\ +\ +\ +"); + + for (std::map::iterator iterImage = m_oManager.m_mapImageData.begin(); iterImage != m_oManager.m_mapImageData.end(); iterImage++) + { + CImageInfo& oInfo = iterImage->second; + + oWriter.WriteString(L"") : oWriter.WriteString(L".jpg\"/>"); + } + + for (std::map::iterator iterImage = m_oManager.m_mapImagesFile.begin(); iterImage != m_oManager.m_mapImagesFile.end(); iterImage++) + { + CImageInfo& oInfo = iterImage->second; + + oWriter.WriteString(L"") : oWriter.WriteString(L".jpg\"/>"); + } + + oWriter.WriteString(L""); + + NSFile::CFileBinary::SaveToFile(m_strTempDirectory + L"/word/_rels/document.xml.rels", oWriter.GetData()); + oWriter.ClearNoAttack(); + + // сохраним fontTable + oWriter.WriteString(L"\ +"); + + CFontTable* pFontTable = &m_oCurrentPage.m_oManager.m_oFontTable; + for (std::map::iterator iterFont = pFontTable->m_mapTable.begin(); iterFont != pFontTable->m_mapTable.end(); iterFont++) + { + CFontTableEntry& oEntry = iterFont->second; + + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + + if (oEntry.m_bIsFixedWidth) + oWriter.WriteString(L""); + else + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + } + + oWriter.WriteString(L""); + NSFile::CFileBinary::SaveToFile(m_strTempDirectory + L"/word/fontTable.xml", oWriter.GetData()); + + // document + m_oCurrentPage.WriteSectionToFile(true, m_oWriter); + m_oWriter.WriteString(L""); + m_oDocumentStream.WriteStringUTF8(m_oWriter.GetData()); + m_oWriter.ClearNoAttack(); + + m_oDocumentStream.CloseFile(); + } +} diff --git a/DocxRenderer/src/logic/Document.h b/DocxRenderer/src/logic/Document.h index bf9081de24..a8b849efd9 100644 --- a/DocxRenderer/src/logic/Document.h +++ b/DocxRenderer/src/logic/Document.h @@ -47,954 +47,153 @@ namespace NSDocxRenderer bool m_bIsDisablePageCommand; // disable commands inside draw function public: - CDocument(IRenderer* pRenderer, NSFonts::IApplicationFonts* pFonts) : m_oWriter(), m_oCurrentPage(pFonts) - { - m_pAppFonts = pFonts; - m_oSimpleGraphicsConverter.SetRenderer(pRenderer); - m_lCurrentCommandType = 0; + CDocument(IRenderer* pRenderer, NSFonts::IApplicationFonts* pFonts); + void Clear(); - m_dWidth = 0; - m_dHeight = 0; - - m_dDpiX = 72; - m_dDpiY = 72; - - m_strTempDirectory = L""; - m_lPagesCount = 0; - - m_bIsNeedPDFTextAnalyzer = false; - m_pFontManager = NULL; - - m_bIsDisablePageCommand = false; - } - void Clear() - { - m_lClipMode = 0; - } - - ~CDocument() - { - m_lClipMode = 0; - RELEASEINTERFACE(m_pFontManager); - } + ~CDocument(); public: - HRESULT NewPage() - { - if (0 != m_lPagesCount) - { - m_oCurrentPage.WriteSectionToFile(false, m_oWriter); - m_oDocumentStream.WriteStringUTF8(m_oWriter.GetData()); - m_oWriter.ClearNoAttack(); - } - - m_oPen.SetDefaultParams(); - m_oBrush.SetDefaultParams(); - m_oFont.SetDefaultParams(); - m_oShadow.SetDefaultParams(); - m_oEdge.SetDefaultParams(); - - m_oTransform.Reset(); - - ++m_lPagesCount; - m_oCurrentPage.Clear(); - - return S_OK; - } - HRESULT get_Height(double* dHeight) - { - *dHeight = m_dHeight; - return S_OK; - } - HRESULT put_Height(double dHeight) - { - m_dHeight = dHeight; - m_oCurrentPage.m_dHeight = dHeight; - return S_OK; - } - HRESULT get_Width(double* dWidth) - { - *dWidth = m_dWidth; - return S_OK; - } - HRESULT put_Width(double dWidth) - { - m_dWidth = dWidth; - m_oCurrentPage.m_dWidth = dWidth; - return S_OK; - } - HRESULT get_DpiX(double* dDpiX) - { - *dDpiX = m_dDpiX; - return S_OK; - } - HRESULT get_DpiY(double* dDpiY) - { - *dDpiY = m_dDpiY; - return S_OK; - } + HRESULT NewPage(); + HRESULT get_Height(double* dHeight); + HRESULT put_Height(double dHeight); + HRESULT get_Width(double* dWidth); + HRESULT put_Width(double dWidth); + HRESULT get_DpiX(double* dDpiX); + HRESULT get_DpiY(double* dDpiY); //-------- Функции для задания настроек текста ---------------------------------------------- // pen -------------------------------------------------------------------------------------- - HRESULT get_PenColor(LONG* lColor) - { - *lColor = m_oPen.Color; - return S_OK; - } - HRESULT put_PenColor(LONG lColor) - { - m_oPen.Color = lColor; - return S_OK; - } - HRESULT get_PenAlpha(LONG* lAlpha) - { - *lAlpha = m_oPen.Alpha; - return S_OK; - } - HRESULT put_PenAlpha(LONG lAlpha) - { - m_oPen.Alpha = lAlpha; - return S_OK; - } - HRESULT get_PenSize(double* dSize) - { - *dSize = m_oPen.Size; - return S_OK; - } - HRESULT put_PenSize(double dSize) - { - m_oPen.Size = dSize; - return S_OK; - } - HRESULT get_PenDashStyle(BYTE* val) - { - *val = m_oPen.DashStyle; - return S_OK; - } - HRESULT put_PenDashStyle(BYTE val) - { - m_oPen.DashStyle = val; - return S_OK; - } - HRESULT get_PenLineStartCap(BYTE* val) - { - *val = m_oPen.LineStartCap; - return S_OK; - } - HRESULT put_PenLineStartCap(BYTE val) - { - m_oPen.LineStartCap = val; - return S_OK; - } - HRESULT get_PenLineEndCap(BYTE* val) - { - *val = m_oPen.LineEndCap; - return S_OK; - } - HRESULT put_PenLineEndCap(BYTE val) - { - m_oPen.LineEndCap = val; - return S_OK; - } - HRESULT get_PenLineJoin(BYTE* val) - { - *val = m_oPen.LineJoin; - return S_OK; - } - HRESULT put_PenLineJoin(BYTE val) - { - m_oPen.LineJoin = val; - return S_OK; - } - HRESULT get_PenDashOffset(double* val) - { - *val = m_oPen.DashOffset; - return S_OK; - } - HRESULT put_PenDashOffset(double val) - { - m_oPen.DashOffset = val; - return S_OK; - } - HRESULT get_PenAlign(LONG* val) - { - *val = m_oPen.Align; - return S_OK; - } - HRESULT put_PenAlign(LONG val) - { - m_oPen.Align = val; - return S_OK; - } - HRESULT get_PenMiterLimit(double* val) - { - *val = m_oPen.MiterLimit; - return S_OK; - } - HRESULT put_PenMiterLimit(double val) - { - m_oPen.MiterLimit = val; - return S_OK; - } - HRESULT PenDashPattern(double* pPattern, LONG lCount) - { - if (NULL != pPattern) - { - m_oPen.SetDashPattern(pPattern, lCount); - } - - return S_OK; - } + HRESULT get_PenColor(LONG* lColor); + HRESULT put_PenColor(LONG lColor); + HRESULT get_PenAlpha(LONG* lAlpha); + HRESULT put_PenAlpha(LONG lAlpha); + HRESULT get_PenSize(double* dSize); + HRESULT put_PenSize(double dSize); + HRESULT get_PenDashStyle(BYTE* val); + HRESULT put_PenDashStyle(BYTE val); + HRESULT get_PenLineStartCap(BYTE* val); + HRESULT put_PenLineStartCap(BYTE val); + HRESULT get_PenLineEndCap(BYTE* val); + HRESULT put_PenLineEndCap(BYTE val); + HRESULT get_PenLineJoin(BYTE* val); + HRESULT put_PenLineJoin(BYTE val); + HRESULT get_PenDashOffset(double* val); + HRESULT put_PenDashOffset(double val); + HRESULT get_PenAlign(LONG* val); + HRESULT put_PenAlign(LONG val); + HRESULT get_PenMiterLimit(double* val); + HRESULT put_PenMiterLimit(double val); + HRESULT PenDashPattern(double* pPattern, LONG lCount); // brush ------------------------------------------------------------------------------------ - HRESULT get_BrushType(LONG* lType) - { - *lType = m_oBrush.Type; - return S_OK; - } - HRESULT put_BrushType(LONG lType) - { - m_oBrush.Type = lType; - return S_OK; - } - HRESULT get_BrushColor1(LONG* lColor) - { - *lColor = m_oBrush.Color1; - return S_OK; - } - HRESULT put_BrushColor1(LONG lColor) - { - m_oBrush.Color1 = lColor; - return S_OK; - } - HRESULT get_BrushAlpha1(LONG* lAlpha) - { - *lAlpha = m_oBrush.Alpha1; - return S_OK; - } - HRESULT put_BrushAlpha1(LONG lAlpha) - { - m_oBrush.Alpha1 = lAlpha; - return S_OK; - } - HRESULT get_BrushColor2(LONG* lColor) - { - *lColor = m_oBrush.Color2; - return S_OK; - } - HRESULT put_BrushColor2(LONG lColor) - { - m_oBrush.Color2 = lColor; - return S_OK; - } - HRESULT get_BrushAlpha2(LONG* lAlpha) - { - *lAlpha = m_oBrush.Alpha2; - return S_OK; - } - HRESULT put_BrushAlpha2(LONG lAlpha) - { - m_oBrush.Alpha2 = lAlpha; - return S_OK; - } - HRESULT get_BrushTexturePath(std::wstring* sPath) - { - *sPath = m_oBrush.TexturePath; - return S_OK; - } - HRESULT put_BrushTexturePath(const std::wstring& sPath) - { - m_oBrush.TexturePath = sPath; - return S_OK; - } - HRESULT get_BrushTextureMode(LONG* lMode) - { - *lMode = m_oBrush.TextureMode; - return S_OK; - } - HRESULT put_BrushTextureMode(LONG lMode) - { - m_oBrush.TextureMode = lMode; - return S_OK; - } - HRESULT get_BrushTextureAlpha(LONG* lTxAlpha) - { - *lTxAlpha = m_oBrush.TextureAlpha; - return S_OK; - } - HRESULT put_BrushTextureAlpha(LONG lTxAlpha) - { - m_oBrush.TextureAlpha = lTxAlpha; - return S_OK; - } - HRESULT get_BrushLinearAngle(double* dAngle) - { - *dAngle = m_oBrush.LinearAngle; - return S_OK; - } - HRESULT put_BrushLinearAngle(double dAngle) - { - m_oBrush.LinearAngle = dAngle; - return S_OK; - } - HRESULT BrushRect(bool val, double left, double top, double width, double height) - { - m_oBrush.Rectable = val ? 1 : 0; - m_oBrush.Rect.X = (float)left; - m_oBrush.Rect.Y = (float)top; - m_oBrush.Rect.Width = (float)width; - m_oBrush.Rect.Height = (float)height; - - return S_OK; - } + HRESULT get_BrushType(LONG* lType); + HRESULT put_BrushType(LONG lType); + HRESULT get_BrushColor1(LONG* lColor); + HRESULT put_BrushColor1(LONG lColor); + HRESULT get_BrushAlpha1(LONG* lAlpha); + HRESULT put_BrushAlpha1(LONG lAlpha); + HRESULT get_BrushColor2(LONG* lColor); + HRESULT put_BrushColor2(LONG lColor); + HRESULT get_BrushAlpha2(LONG* lAlpha); + HRESULT put_BrushAlpha2(LONG lAlpha); + HRESULT get_BrushTexturePath(std::wstring* sPath); + HRESULT put_BrushTexturePath(const std::wstring& sPath); + HRESULT get_BrushTextureMode(LONG* lMode); + HRESULT put_BrushTextureMode(LONG lMode); + HRESULT get_BrushTextureAlpha(LONG* lTxAlpha); + HRESULT put_BrushTextureAlpha(LONG lTxAlpha); + HRESULT get_BrushLinearAngle(double* dAngle); + HRESULT put_BrushLinearAngle(double dAngle); + HRESULT BrushRect(bool val, double left, double top, double width, double height); // font ------------------------------------------------------------------------------------- - HRESULT get_FontName(std::wstring* sName) - { - *sName = m_oFont.Name; - return S_OK; - } - HRESULT put_FontName(std::wstring sName) - { - m_oFont.Name = sName; - return S_OK; - } - HRESULT get_FontPath(std::wstring* sPath) - { - *sPath = m_oFont.Path; - return S_OK; - } - HRESULT put_FontPath(std::wstring sPath) - { - m_oFont.Path = sPath; - return S_OK; - } - HRESULT get_FontSize(double* dSize) - { - *dSize = m_oFont.Size; - return S_OK; - } - HRESULT put_FontSize(double dSize) - { - m_oFont.Size = dSize; - return S_OK; - } - HRESULT get_FontStyle(LONG* lStyle) - { - *lStyle = m_oFont.GetStyle(); - return S_OK; - } - HRESULT put_FontStyle(LONG lStyle) - { - m_oFont.SetStyle(lStyle); - return S_OK; - } - HRESULT get_FontStringGID(INT* bGID) - { - *bGID = m_oFont.StringGID; - return S_OK; - } - HRESULT put_FontStringGID(INT bGID) - { - m_oFont.StringGID = bGID; - return S_OK; - } - HRESULT get_FontCharSpace(double* dSpace) - { - *dSpace = m_oFont.CharSpace; - return S_OK; - } - HRESULT put_FontCharSpace(double dSpace) - { - m_oFont.CharSpace = dSpace; - return S_OK; - } - HRESULT get_FontFaceIndex(int* lFaceIndex) - { - *lFaceIndex = m_oFont.FaceIndex; - return S_OK; - } - HRESULT put_FontFaceIndex(const int& lFaceIndex) - { - m_oFont.FaceIndex = lFaceIndex; - return S_OK; - } + HRESULT get_FontName(std::wstring* sName); + HRESULT put_FontName(std::wstring sName); + HRESULT get_FontPath(std::wstring* sPath); + HRESULT put_FontPath(std::wstring sPath); + HRESULT get_FontSize(double* dSize); + HRESULT put_FontSize(double dSize); + HRESULT get_FontStyle(LONG* lStyle); + HRESULT put_FontStyle(LONG lStyle); + HRESULT get_FontStringGID(INT* bGID); + HRESULT put_FontStringGID(INT bGID); + HRESULT get_FontCharSpace(double* dSpace); + HRESULT put_FontCharSpace(double dSpace); + HRESULT get_FontFaceIndex(int* lFaceIndex); + HRESULT put_FontFaceIndex(const int& lFaceIndex); // shadow ----------------------------------------------------------------------------------- - HRESULT get_ShadowDistanceX(double* val) - { - *val = m_oShadow.DistanceX; - return S_OK; - } - HRESULT put_ShadowDistanceX(double val) - { - m_oShadow.DistanceX = val; - return S_OK; - } - HRESULT get_ShadowDistanceY(double* val) - { - *val = m_oShadow.DistanceY; - return S_OK; - } - HRESULT put_ShadowDistanceY(double val) - { - m_oShadow.DistanceY = val; - return S_OK; - } - HRESULT get_ShadowBlurSize(double* val) - { - *val = m_oShadow.BlurSize; - return S_OK; - } - HRESULT put_ShadowBlurSize(double val) - { - m_oShadow.BlurSize = val; - return S_OK; - } - HRESULT get_ShadowColor(LONG* val) - { - *val = m_oShadow.Color; - return S_OK; - } - HRESULT put_ShadowColor(LONG val) - { - m_oShadow.Color = val; - return S_OK; - } - HRESULT get_ShadowAlpha(LONG* val) - { - *val = m_oShadow.Alpha; - return S_OK; - } - HRESULT put_ShadowAlpha(LONG val) - { - m_oShadow.Alpha = val; - return S_OK; - } - HRESULT get_ShadowVisible(INT* val) - { - *val = m_oShadow.Visible; - return S_OK; - } - HRESULT put_ShadowVisible(INT val) - { - m_oShadow.Visible = val; - return S_OK; - } + HRESULT get_ShadowDistanceX(double* val); + HRESULT put_ShadowDistanceX(double val); + HRESULT get_ShadowDistanceY(double* val); + HRESULT put_ShadowDistanceY(double val); + HRESULT get_ShadowBlurSize(double* val); + HRESULT put_ShadowBlurSize(double val); + HRESULT get_ShadowColor(LONG* val); + HRESULT put_ShadowColor(LONG val); + HRESULT get_ShadowAlpha(LONG* val); + HRESULT put_ShadowAlpha(LONG val); + HRESULT get_ShadowVisible(INT* val); + HRESULT put_ShadowVisible(INT val); // edge ------------------------------------------------------------------------------------- - HRESULT get_EdgeVisible(LONG* val) - { - *val = m_oEdge.Visible; - return S_OK; - } - HRESULT put_EdgeVisible(LONG val) - { - m_oEdge.Visible = val; - return S_OK; - } - HRESULT get_EdgeColor(LONG* val) - { - *val = m_oEdge.Color; - return S_OK; - } - HRESULT put_EdgeColor(LONG val) - { - m_oEdge.Color = val; - return S_OK; - } - HRESULT get_EdgeAlpha(LONG* val) - { - *val = m_oEdge.Alpha; - return S_OK; - } - HRESULT put_EdgeAlpha(LONG val) - { - m_oEdge.Alpha = val; - return S_OK; - } - HRESULT get_EdgeDist(double* val) - { - *val = m_oEdge.Dist; - return S_OK; - } - HRESULT put_EdgeDist(double val) - { - m_oEdge.Dist = val; - return S_OK; - } - + HRESULT get_EdgeVisible(LONG* val); + HRESULT put_EdgeVisible(LONG val); + HRESULT get_EdgeColor(LONG* val); + HRESULT put_EdgeColor(LONG val); + HRESULT get_EdgeAlpha(LONG* val); + HRESULT put_EdgeAlpha(LONG val); + HRESULT get_EdgeDist(double* val); + HRESULT put_EdgeDist(double val); //-------- Функции для вывода текста -------------------------------------------------------- - HRESULT CommandDrawTextPrivate(const int* pUnicodes, const int* pGids, int nCount, const double& dX, const double& dY, const double& dW, const double& dH, const double& dBaseLineOffset = 0) - { - double dAngleMatrix = m_oTransform.z_Rotation(); - if (abs(dAngleMatrix) > 1 || m_oTransform.sx() < 0 || m_oTransform.sy() < 0) - { - _SetFont(); - PathCommandEnd(); - BeginCommand(c_nPathType); - m_oSimpleGraphicsConverter.PathCommandText2(pUnicodes, pGids, nCount, m_pFontManager, dX, dY, dW, dH); - DrawPath(c_nWindingFillMode); - EndCommand(c_nPathType); - PathCommandEnd(); - return S_OK; - } - - m_oCurrentPage.WriteText((unsigned int*)pUnicodes, (unsigned int*)pGids, nCount, dX, dY, dW, dH, 0, m_bIsNeedPDFTextAnalyzer); - return S_OK; - } - - HRESULT CommandDrawTextCHAR(const int& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH) - { - return CommandDrawTextPrivate(&lUnicode, NULL, 1, dX, dY, dW, dH); - } - HRESULT CommandDrawTextExCHAR(const int& lUnicode, const int& lGid, const double& dX, const double& dY, const double& dW, const double& dH) - { - return CommandDrawTextPrivate(&lUnicode, &lGid, 1, dX, dY, dW, dH); - } - virtual HRESULT CommandDrawText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH) - { - unsigned int nLen = 0; - unsigned int* pUnicodes = NSStringExt::CConverter::GetUtf32FromUnicode(wsUnicodeText, nLen); - if (nLen == 0) - return S_OK; - CommandDrawTextPrivate((int*)pUnicodes, NULL, nLen, dX, dY, dW, dH); - delete [] pUnicodes; - return S_OK; - } - virtual HRESULT CommandDrawTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH) - { - unsigned int nLen = 0; - unsigned int* pUnicodes = NSStringExt::CConverter::GetUtf32FromUnicode(wsUnicodeText, nLen); - if (nLen == 0) - return S_OK; - if (nLen != nGidsCount) - { - delete [] pUnicodes; - return S_OK; - } - - CommandDrawTextPrivate((int*)pUnicodes, (int*)pGids, (int)nLen, dX, dY, dW, dH); - delete [] pUnicodes; - return S_OK; - } + HRESULT CommandDrawTextPrivate(const int* pUnicodes, const int* pGids, int nCount, + const double& dX, const double& dY, const double& dW, + const double& dH, const double& dBaseLineOffset = 0); + HRESULT CommandDrawTextCHAR(const int& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH); + HRESULT CommandDrawTextExCHAR(const int& lUnicode, const int& lGid, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT CommandDrawText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH); + virtual HRESULT CommandDrawTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, + const unsigned int nGidsCount, const double& dX, const double& dY, + const double& dW, const double& dH); //-------- Маркеры для команд --------------------------------------------------------------- - HRESULT BeginCommand(DWORD lType) - { - if (c_nPageType == lType && m_bIsDisablePageCommand) - return S_OK; - - m_lCurrentCommandType = (LONG)lType; - m_oCurrentPage.m_lCurrentCommand = m_lCurrentCommandType; - - if (c_nTextType == lType) - m_oCurrentPage.m_dLastTextX_block = -1; - - return S_OK; - } - HRESULT EndCommand(DWORD lType) - { - if (c_nPageType == lType && m_bIsDisablePageCommand) - return S_OK; - - m_lCurrentCommandType = -1; - m_oCurrentPage.m_lCurrentCommand = m_lCurrentCommandType; - - if (c_nPageType == lType) - { - // нужно записать страницу в файл - m_oCurrentPage.Build(); - m_oCurrentPage.Write(m_oWriter); - } - else if (c_nPathType == lType) - { - m_oCurrentPage.End(); - } - - if (c_nTextType == lType) - m_oCurrentPage.m_dLastTextX_block = -1; - - return S_OK; - } + HRESULT BeginCommand(DWORD lType); + HRESULT EndCommand(DWORD lType); //-------- Функции для работы с Graphics Path ----------------------------------------------- - HRESULT PathCommandMoveTo(double fX, double fY) - { - if (c_nSimpleGraphicType == m_lCurrentCommandType) - { - m_oCurrentPage.MoveTo(fX, fY); - } - else - { - m_oSimpleGraphicsConverter.PathCommandMoveTo(fX, fY); - } - return S_OK; - } - HRESULT PathCommandLineTo(double fX, double fY) - { - if (c_nSimpleGraphicType == m_lCurrentCommandType) - { - m_oCurrentPage.LineTo(fX, fY); - } - else - { - m_oSimpleGraphicsConverter.PathCommandLineTo(fX, fY); - } - return S_OK; - } - HRESULT PathCommandLinesTo(double* pPoints, LONG lCount) - { - m_oSimpleGraphicsConverter.PathCommandLinesTo(pPoints, lCount); - return S_OK; - } - HRESULT PathCommandCurveTo(double fX1, double fY1, double fX2, double fY2, double fX3, double fY3) - { - if (c_nSimpleGraphicType == m_lCurrentCommandType) - { - m_oCurrentPage.CurveTo(fX1, fY1, fX2, fY2, fX3, fY3); - } - else - { - m_oSimpleGraphicsConverter.PathCommandCurveTo(fX1, fY1, fX2, fY2, fX3, fY3); - } - return S_OK; - } - HRESULT PathCommandCurvesTo(double* pPoints, LONG lCount) - { - m_oSimpleGraphicsConverter.PathCommandCurvesTo(pPoints, lCount); - return S_OK; - } - HRESULT PathCommandArcTo(double fX, double fY, double fWidth, double fHeight, double fStartAngle, double fSweepAngle) - { - m_oSimpleGraphicsConverter.PathCommandArcTo(fX, fY, fWidth, fHeight, fStartAngle, fSweepAngle); - return S_OK; - } - HRESULT PathCommandClose() - { - if (c_nSimpleGraphicType == m_lCurrentCommandType) - { - m_oCurrentPage.Close(); - } - else - { - m_oSimpleGraphicsConverter.PathCommandClose(); - } - return S_OK; - } - HRESULT PathCommandEnd() - { - if (c_nSimpleGraphicType == m_lCurrentCommandType) - { - m_oCurrentPage.End(); - } - else - { - m_oSimpleGraphicsConverter.PathCommandEnd(); - } - return S_OK; - } - HRESULT DrawPath(long nType) - { - LONG lTxId = -1; - if ((nType > 0xFF) && (c_BrushTypeTexture == m_oBrush.Type)) - { - double x = 0; - double y = 0; - double w = 0; - double h = 0; - CImageInfo oInfo = m_oManager.WriteImage(m_oBrush.TexturePath, x, y, w, h); - lTxId = oInfo.m_nId; - } + HRESULT PathCommandMoveTo(double fX, double fY); + HRESULT PathCommandLineTo(double fX, double fY); + HRESULT PathCommandLinesTo(double* pPoints, LONG lCount); + HRESULT PathCommandCurveTo(double fX1, double fY1, double fX2, double fY2, double fX3, double fY3); + HRESULT PathCommandCurvesTo(double* pPoints, LONG lCount); + HRESULT PathCommandArcTo(double fX, double fY, double fWidth, double fHeight, double fStartAngle, double fSweepAngle); + HRESULT PathCommandClose(); + HRESULT PathCommandEnd(); + HRESULT DrawPath(long nType); + HRESULT PathCommandStart(); + HRESULT PathCommandGetCurrentPoint(double* fX, double* fY); - m_oCurrentPage.DrawPath(nType, lTxId); - return S_OK; - } - HRESULT PathCommandStart() - { - if (c_nSimpleGraphicType == m_lCurrentCommandType) - { - m_oCurrentPage.Start(); - } - else - { - m_oSimpleGraphicsConverter.PathCommandStart(); - } - return S_OK; - } - HRESULT PathCommandGetCurrentPoint(double* fX, double* fY) - { - m_oSimpleGraphicsConverter.PathCommandGetCurrentPoint(fX, fY); - return S_OK; - } + HRESULT PathCommandTextCHAR(const int& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH); + HRESULT PathCommandTextExCHAR(const int& lUnicode, const int& lGid, const double& dX, const double& dY, const double& dW, const double& dH); + HRESULT PathCommandText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH); + HRESULT PathCommandTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH); - HRESULT PathCommandTextCHAR(const int& lUnicode, const double& dX, const double& dY, const double& dW, const double& dH) - { - _SetFont(); - m_oSimpleGraphicsConverter.PathCommandText2(&lUnicode, NULL, 1, m_pFontManager, dX, dY, dW, dH); - return S_OK; - } - HRESULT PathCommandTextExCHAR(const int& lUnicode, const int& lGid, const double& dX, const double& dY, const double& dW, const double& dH) - { - _SetFont(); - m_oSimpleGraphicsConverter.PathCommandText2(&lUnicode, &lGid, 1, m_pFontManager, dX, dY, dW, dH); - return S_OK; - } - HRESULT PathCommandText(const std::wstring& wsUnicodeText, const double& dX, const double& dY, const double& dW, const double& dH) - { - _SetFont(); - m_oSimpleGraphicsConverter.PathCommandText(wsUnicodeText, m_pFontManager, dX, dY, dW, dH, 0); - return S_OK; - } - HRESULT PathCommandTextEx(const std::wstring& wsUnicodeText, const unsigned int* pGids, const unsigned int nGidsCount, const double& dX, const double& dY, const double& dW, const double& dH) - { - _SetFont(); - m_oSimpleGraphicsConverter.PathCommandText2(wsUnicodeText, (const int*)pGids, nGidsCount, m_pFontManager, dX, dY, dW, dH); - return S_OK; - } - - HRESULT GetCommandParams(double* dAngle, double* dLeft, double* dTop, double* dWidth, double* dHeight, DWORD* lFlags) - { - return S_OK; - } - HRESULT SetCommandParams(double dAngle, double dLeft, double dTop, double dWidth, double dHeight, DWORD lFlags) - { - ApplyTransform2(dAngle, dLeft, dTop, dWidth, dHeight, lFlags); - return S_OK; - } + HRESULT GetCommandParams(double* dAngle, double* dLeft, double* dTop, double* dWidth, double* dHeight, DWORD* lFlags); + HRESULT SetCommandParams(double dAngle, double dLeft, double dTop, double dWidth, double dHeight, DWORD lFlags); //-------- Функции для вывода изображений -------------------------------------------------- - HRESULT DrawImage(IGrObject* pImage, double fX, double fY, double fWidth, double fHeight) - { - CImageInfo oInfo = m_oManager.WriteImage((Aggplus::CImage*)pImage, fX, fY, fWidth, fHeight); - m_oCurrentPage.WriteImage(oInfo, fX, fY, fWidth, fHeight); - return S_OK; - } - HRESULT DrawImageFromFile(const std::wstring& sVal, double fX, double fY, double fWidth, double fHeight) - { - CImageInfo oInfo = m_oManager.WriteImage(sVal, fX, fY, fWidth, fHeight); - m_oCurrentPage.WriteImage(oInfo, fX, fY, fWidth, fHeight); - return S_OK; - } + HRESULT DrawImage(IGrObject* pImage, double fX, double fY, double fWidth, double fHeight); + HRESULT DrawImageFromFile(const std::wstring& sVal, double fX, double fY, double fWidth, double fHeight); //------------------------------------------------------------------------------------------ - HRESULT SetTransform(double dA, double dB, double dC, double dD, double dE, double dF) - { - ApplyTransform(dA, dB, dC, dD, dE, dF); - return S_OK; - } - HRESULT GetTransform(double *pdA, double *pdB, double *pdC, double *pdD, double *pdE, double *pdF) - { - return S_OK; - } - HRESULT ResetTransform(void) - { - m_oTransform.Reset(); - return S_OK; - } - HRESULT get_ClipMode(LONG* plMode) - { - *plMode = m_lClipMode; - return S_OK; - } - HRESULT put_ClipMode(LONG lMode) - { - m_lClipMode = lMode; - return S_OK; - } + HRESULT SetTransform(double dA, double dB, double dC, double dD, double dE, double dF); + HRESULT GetTransform(double *pdA, double *pdB, double *pdC, double *pdD, double *pdE, double *pdF); + HRESULT ResetTransform(void); + HRESULT get_ClipMode(LONG* plMode); + HRESULT put_ClipMode(LONG lMode); protected: - void ApplyTransform(double d1, double d2, double d3, double d4, double d5, double d6) - { - m_oTransform.SetElements(d1, d2, d3, d4, d5, d6); - } + void ApplyTransform(double d1, double d2, double d3, double d4, double d5, double d6); - void ApplyTransform2(double dAngle, double dLeft, double dTop, double dWidth, double dHeight, DWORD lFlags) - { - if ((dWidth <= 1) || (dHeight <= 1)) - lFlags = 0; - - bool bFlipX = (0 != (c_nParamFlipX & lFlags)); - bool bFlipY = (0 != (c_nParamFlipY & lFlags)); - - double m11 = bFlipX ? -1.0 : 1.0; - double m22 = bFlipY ? -1.0 : 1.0; - - Aggplus::CMatrix oMatrix(1, 0, 0, 1, 0, 0); - - if ((0 != dAngle) || (0 != lFlags)) - { - double dCentreX = (dLeft + dWidth / 2.0); - double dCentreY = (dTop + dHeight / 2.0); - - oMatrix.Translate(-dCentreX, -dCentreY , Aggplus::MatrixOrderAppend); - - oMatrix.Rotate(dAngle , Aggplus::MatrixOrderAppend); - oMatrix.Scale(m11, m22 , Aggplus::MatrixOrderAppend); - - oMatrix.Translate(dCentreX, dCentreY , Aggplus::MatrixOrderAppend); - } - - m_oTransform = oMatrix; - } - - void _SetFont() - { - if (NULL == m_pFontManager) - { - m_pFontManager = NSFontManager::CreateFontManager(m_pAppFonts); - } - - double dPix = m_oFont.CharSpace * m_dDpiX / 25.4; - - if (m_oInstalledFont.IsEqual(&m_oFont)) - { - if (1 < m_dWidth) - { - m_pFontManager->SetCharSpacing(dPix); - } - return; - } - - m_pFontManager->SetStringGID(m_oFont.StringGID); - if (1 < m_dWidth) - { - m_pFontManager->SetCharSpacing(dPix); - } - - if (m_oFont.Path.empty()) - { - m_pFontManager->LoadFontByName(m_oFont.Name, (float)m_oFont.Size, m_oFont.GetStyle(), m_dDpiX, m_dDpiY); - } - else - { - m_pFontManager->LoadFontFromFile(m_oFont.Path, m_oFont.FaceIndex, (float)m_oFont.Size, m_dDpiX, m_dDpiY); - } - - m_oInstalledFont = m_oFont; - } + void ApplyTransform2(double dAngle, double dLeft, double dTop, double dWidth, double dHeight, DWORD lFlags); + void _SetFont(); public: - bool CreateDocument() - { - CreateTemplate(m_strTempDirectory); + bool CreateDocument(); - // Init - Clear(); - - m_lCurrentCommandType = 0; - m_oCurrentPage.Init(&m_oFont, &m_oPen, &m_oBrush, &m_oShadow, &m_oEdge, &m_oTransform, &m_oSimpleGraphicsConverter); - - m_oManager.NewDocument(); - // media - m_oManager.m_strDstMedia = m_strTempDirectory + L"/word/media"; - NSDirectory::CreateDirectory(m_oManager.m_strDstMedia); - - m_oCurrentPage.m_oManager.m_oFontTable.m_mapTable.clear(); - - m_oDocumentStream.CloseFile(); - m_oDocumentStream.CreateFileW(m_strTempDirectory + L"/word/document.xml"); - m_oDocumentStream.WriteStringUTF8(L"\ -\ -"); - - m_lPagesCount = 0; - m_oWriter.Clear(); - m_oWriter.AddSize(10000); - - return true; - } - - void Close() - { - // сохраним rels (images & docs) - NSStringUtils::CStringBuilder oWriter; - - oWriter.WriteString(L"\ -\ -\ -\ -\ -\ -"); - - for (std::map::iterator iterImage = m_oManager.m_mapImageData.begin(); iterImage != m_oManager.m_mapImageData.end(); iterImage++) - { - CImageInfo& oInfo = iterImage->second; - - oWriter.WriteString(L"") : oWriter.WriteString(L".jpg\"/>"); - } - - for (std::map::iterator iterImage = m_oManager.m_mapImagesFile.begin(); iterImage != m_oManager.m_mapImagesFile.end(); iterImage++) - { - CImageInfo& oInfo = iterImage->second; - - oWriter.WriteString(L"") : oWriter.WriteString(L".jpg\"/>"); - } - - oWriter.WriteString(L""); - - NSFile::CFileBinary::SaveToFile(m_strTempDirectory + L"/word/_rels/document.xml.rels", oWriter.GetData()); - oWriter.ClearNoAttack(); - - // сохраним fontTable - oWriter.WriteString(L"\ -"); - - CFontTable* pFontTable = &m_oCurrentPage.m_oManager.m_oFontTable; - for (std::map::iterator iterFont = pFontTable->m_mapTable.begin(); iterFont != pFontTable->m_mapTable.end(); iterFont++) - { - CFontTableEntry& oEntry = iterFont->second; - - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - - if (oEntry.m_bIsFixedWidth) - oWriter.WriteString(L""); - else - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - } - - oWriter.WriteString(L""); - NSFile::CFileBinary::SaveToFile(m_strTempDirectory + L"/word/fontTable.xml", oWriter.GetData()); - - // document - m_oCurrentPage.WriteSectionToFile(true, m_oWriter); - m_oWriter.WriteString(L""); - m_oDocumentStream.WriteStringUTF8(m_oWriter.GetData()); - m_oWriter.ClearNoAttack(); - - m_oDocumentStream.CloseFile(); - } + void Close(); }; } diff --git a/DocxRenderer/src/logic/ElementParagraph.cpp b/DocxRenderer/src/logic/ElementParagraph.cpp new file mode 100644 index 0000000000..c4f8f8747b --- /dev/null +++ b/DocxRenderer/src/logic/ElementParagraph.cpp @@ -0,0 +1,683 @@ +#include "ElementParagraph.h" + +namespace NSDocxRenderer +{ + void DeleteSpaces(NSStringUtils::CStringUTF32& oText) + { + size_t nLen = oText.length(); + size_t nStart = 0; + + while ((nStart < nLen) && (' ' == oText[nStart])) + ++nStart; + + if (nStart == nLen) + { + oText = L""; + return; + } + + size_t nEnd = nLen - 1; + while ((nEnd > nStart) && (' ' == oText[nEnd])) + --nEnd; + + oText = oText.substr(nStart, nEnd - nStart + 1); + } + + CContText::CContText() + { + m_strPickFontName = L""; + m_lPickFontStyle = 0; + + m_dX = 0; + m_dY = 0; + m_dWidth = 0; + m_dHeight = 0; + m_dLastX = 0; + + m_dWidthWithoutSpaces = 0; + m_dLeftWithoutSpaces = 0; + + m_dPosition = 0; + m_dSpaceWidthMM = 0; + + m_dCalculateWidth = 0; + + m_dSpaceByText = 0; + } + + void CContText::Clear() + { + } + + CContText::CContText(const CContText& oSrc) + { + *this = oSrc; + } + CContText& CContText::operator=(const CContText& oSrc) + { + if (this == &oSrc) + { + return *this; + } + + m_oFont = oSrc.m_oFont; + m_oBrush = oSrc.m_oBrush; + + m_oText = oSrc.m_oText; + m_oGidText = oSrc.m_oGidText; + + m_strPickFontName = oSrc.m_strPickFontName; + m_lPickFontStyle = oSrc.m_lPickFontStyle; + + m_dX = oSrc.m_dX; + m_dY = oSrc.m_dY; + m_dWidth = oSrc.m_dWidth; + m_dHeight = oSrc.m_dHeight; + + m_dLastX = oSrc.m_dLastX; + + m_dWidthWithoutSpaces = oSrc.m_dWidthWithoutSpaces; + m_dLeftWithoutSpaces = oSrc.m_dLeftWithoutSpaces; + + m_dPosition = oSrc.m_dPosition; + m_dSpaceWidthMM = oSrc.m_dSpaceWidthMM; + + m_dCalculateWidth = oSrc.m_dCalculateWidth; + m_dSpaceByText = oSrc.m_dSpaceByText; + + return *this; + } + + bool CContText::IsBigger(const CContText* oSrc) + { + return (m_dX > oSrc->m_dX) ? true : false; + } + bool CContText::IsBiggerOrEqual(const CContText* oSrc) + { + return (m_dX >= oSrc->m_dX) ? true : false; + } + + double CContText::GetIntersect(const CContText* oSrc) const + { + double d1 = std::max(m_dX, oSrc->m_dX); + double d2 = std::min(m_dX + m_dWidth, oSrc->m_dX + oSrc->m_dWidth); + + if (d2 > d1) + return d2 - d1; + return 0; + } + + void CContText::Write(NSStringUtils::CStringBuilder& oWriter, + CFontManagerLight* pManagerLight, + bool bIsAddSpace) + { + oWriter.WriteString(L""); + + if (m_dWidth != m_dWidthWithoutSpaces) + { + DeleteSpaces(m_oText); + m_dWidth = m_dWidthWithoutSpaces; + } + + if (m_strPickFontName.empty()) + { + if (m_oFont.Bold) + oWriter.WriteString(L""); + if (m_oFont.Italic) + oWriter.WriteString(L""); + + if (bIsAddSpace) + { + m_dWidth += m_dSpaceWidthMM; + m_oText += L" "; + } + } + else + { + if (0x01 == (0x01 & m_lPickFontStyle)) + oWriter.WriteString(L""); + if (0x02 == (0x02 & m_lPickFontStyle)) + oWriter.WriteString(L""); + + if (bIsAddSpace) + { + m_dWidth += pManagerLight->GetSpaceWidth(); + m_oText += L" "; + } + + // нужно перемерять... + double ___dSize = (double)((LONG)(m_oFont.Size * 2)) / 2; + pManagerLight->LoadFont(m_strPickFontName, m_lPickFontStyle, ___dSize, false); + double dWidth = pManagerLight->MeasureStringWidth(m_oText.ToStdWString()); + + if (fabs(dWidth - m_dWidth) > 2) + { + double dSpacing = (m_dWidth - dWidth) / (m_oText.length() + 1); + dSpacing *= c_dMMToDx; + + oWriter.WriteString(L""); + } + } + + int lSize = (int)(2 * m_oFont.Size); + oWriter.WriteString(L""); + + std::wstring& strFontName = m_strPickFontName.empty() ? m_oFont.Name : m_strPickFontName; + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + oWriter.WriteEncodeXmlString(m_oText.ToStdWString()); + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + } + + void CContText::WriteTo(double dSpacingMM, + NSStringUtils::CStringBuilder& oWriter, + CFontManagerLight* pManagerLight) + { + oWriter.WriteString(L""); + + double dSpaceMMSize = m_dSpaceWidthMM; + if (m_strPickFontName.empty()) + { + if (m_oFont.Bold) + oWriter.WriteString(L""); + if (m_oFont.Italic) + oWriter.WriteString(L""); + } + else + { + if (0x01 == (0x01 & m_lPickFontStyle)) + oWriter.WriteString(L""); + if (0x02 == (0x02 & m_lPickFontStyle)) + oWriter.WriteString(L""); + + dSpaceMMSize = pManagerLight->GetSpaceWidth(); + } + + int lSize = (int)(2 * m_oFont.Size); + oWriter.WriteString(L""); + + std::wstring& strFontName = m_strPickFontName.empty() ? m_oFont.Name : m_strPickFontName; + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + + LONG lSpacing = (LONG)((dSpacingMM - dSpaceMMSize) * c_dMMToDx); + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + oWriter.WriteString(L" "); + oWriter.WriteString(L""); + + oWriter.WriteString(L""); + } + + CTextLine::CTextLine() : m_arConts() + { + m_dBaselinePos = 0; + m_dBaselineOffset = 0; + + m_dX = 0; + m_dY = 0; + m_dWidth = 0; + m_dHeight = 0; + } + void CTextLine::Clear() + { + for (std::vector::iterator iter = m_arConts.begin(); + iter != m_arConts.end(); iter++) + { + CContText* pText = *iter; + RELEASEOBJECT(pText); + } + m_arConts.clear(); + } + + CTextLine::~CTextLine() + { + Clear(); + } + + CTextLine::CTextLine(const CTextLine& oSrc) + { + *this = oSrc; + } + CTextLine& CTextLine::operator=(const CTextLine& oSrc) + { + if (this == &oSrc) + { + return *this; + } + + Clear(); + for (std::vector::const_iterator iter = oSrc.m_arConts.begin(); iter != oSrc.m_arConts.end(); iter++) + { + m_arConts.push_back(new CContText(*(*iter))); + } + + m_dBaselinePos = oSrc.m_dBaselinePos; + m_dBaselineOffset = oSrc.m_dBaselineOffset; + + m_dX = oSrc.m_dX; + m_dY = oSrc.m_dY; + m_dWidth = oSrc.m_dWidth; + m_dHeight = oSrc.m_dHeight; + + return *this; + } + + void CTextLine::AddCont(CContText* pCont, double dBaselineOffset) + { + if (0 == m_arConts.size()) + m_dBaselineOffset = dBaselineOffset; + + if ( ( pCont->m_dX > 0 ) && ( ( m_dX == 0 ) || ( pCont->m_dX < m_dX ) ) ) + m_dX = pCont->m_dX; + + if (m_dHeight < pCont->m_dHeight) + m_dHeight = pCont->m_dHeight; + + m_arConts.push_back(pCont); + } + + bool CTextLine::IsBigger(const CTextLine* oSrc) + { + return (m_dBaselinePos > oSrc->m_dBaselinePos) ? true : false; + } + + bool CTextLine::IsBiggerOrEqual(const CTextLine* oSrc) + { + return (m_dBaselinePos >= oSrc->m_dBaselinePos) ? true : false; + } + + void CTextLine::SortConts() + { + // сортировка непрерывных слов по m_dX + SortElements(m_arConts); + } + + void CTextLine::Merge(CTextLine* pTextLine) + { + size_t nCount = pTextLine->m_arConts.size(); + if (0 != nCount) + { + if (pTextLine->m_dX < m_dX) + { + m_dX = pTextLine->m_dX; + } + if (pTextLine->m_dBaselinePos < m_dBaselinePos) + { + m_dHeight = (m_dBaselinePos - pTextLine->m_dBaselinePos + pTextLine->m_dHeight); + } + else + { + m_dHeight = (pTextLine->m_dBaselinePos - m_dBaselinePos + m_dHeight); + } + + double dSubPosition = m_dBaselinePos - pTextLine->m_dBaselinePos; + + for (size_t i = 0; i < nCount; ++i) + { + pTextLine->m_arConts[i]->m_dPosition = dSubPosition; + m_arConts.push_back(pTextLine->m_arConts[i]); + } + } + } + + void CTextLine::Analyze() + { + size_t nCountConts = m_arConts.size(); + + if (0 == nCountConts) + return; + + CContText* pFirst = m_arConts[0]; + + for (size_t i = 1; i < nCountConts; ++i) + { + CContText* pCurrent = m_arConts[i]; + + if (pFirst->m_strPickFontName != pCurrent->m_strPickFontName || + pFirst->m_oFont.Bold != pCurrent->m_oFont.Bold || + pFirst->m_oFont.Italic != pCurrent->m_oFont.Italic) + { + // вообще надо бы все объединить. но пока этот метод на соединение "первых" + break; + } + + double dRight = pFirst->m_dX + pFirst->m_dWidth; + double dLeft = pCurrent->m_dX; + + if (fabs(dRight - dLeft) > 0.1) + { + // вообще надо бы все объединить. но пока этот метод на соединение "первых" + break; + } + + // продолжаем слово + pFirst->m_oText += pCurrent->m_oText; + pFirst->m_dWidth = (dLeft + pCurrent->m_dWidth - pFirst->m_dX); + + pFirst->m_dWidthWithoutSpaces < 0.0001 ? + pFirst->m_dLeftWithoutSpaces = pCurrent->m_dLeftWithoutSpaces : + pFirst->m_dWidthWithoutSpaces = pCurrent->m_dLeftWithoutSpaces + + pCurrent->m_dWidthWithoutSpaces - pFirst->m_dLeftWithoutSpaces; + + m_arConts.erase(m_arConts.begin() + i); + --i; + --nCountConts; + } + } + + void CTextLine::CalculateWidth() + { + m_dWidth = 2; //это хак - по идее должно == 0. + for (size_t i = 0; i < m_arConts.size(); ++i) + { + m_dWidth += m_arConts[i]->m_dWidthWithoutSpaces; + m_dWidth += m_arConts[i]->m_dSpaceWidthMM; + } + } + + void CTextLine::AddSpaceToEnd() + { + /*double dX = 0; + size_t isNeedIndex = 0; + + for (size_t i = 0; i < m_arConts.size(); i++) + { + if (dX < m_arConts[i]->m_dX) + { + dX = m_arConts[i]->m_dX; + isNeedIndex = i; + } + } + + CContText* pCurrent = m_arConts[isNeedIndex]; + + if (pCurrent->m_oText[pCurrent->m_oText.length()-1] != uint32_t(' ')) + { + NSStringUtils::CStringUTF32 oText(pCurrent->m_oText); + oText += uint32_t(' '); + pCurrent->m_oText = oText; + pCurrent->m_dWidth += pCurrent->m_dSpaceWidthMM; + m_dWidth += pCurrent->m_dSpaceWidthMM; + }*/ + + /*CContText* pCurrent = m_arConts.back(); + + if (pCurrent->m_oText[pCurrent->m_oText.length()-1] != uint32_t(' ')) + { + pCurrent->m_oText += uint32_t(' '); + //pCurrent->m_dWidth += pCurrent->m_dSpaceWidthMM; + //m_dWidth += pCurrent->m_dSpaceWidthMM; + }*/ + + m_arConts.back()->m_oText += uint32_t(' '); + } + + bool CTextLine::IsForceBlock() + { + // линия отсортирована, так что сравниваем только соседние conts + size_t nCount = m_arConts.size(); + if (nCount <= 1) + return false; + + for (size_t i = 0; i < nCount; i++) + { + for (size_t j = i + 1; j < nCount; j++) + { + if (m_arConts[i]->GetIntersect(m_arConts[j]) > 10) + return true; + } + } + return false; + } + + void CTextLine::ToXml(NSStringUtils::CStringBuilder& oWriter, CFontManagerLight* pManagerLight) + { + size_t nCountConts = m_arConts.size(); + + if (0 == nCountConts) + return; + + CContText* pPrev = m_arConts[0]; + double dDelta = 0; + + for (size_t i = 1; i < nCountConts; ++i) + { + CContText* pCurrent = m_arConts[i]; + + if (0 == pCurrent->m_dWidthWithoutSpaces) + continue; + + dDelta = pCurrent->m_dLeftWithoutSpaces - (pPrev->m_dLeftWithoutSpaces + pPrev->m_dWidthWithoutSpaces); + + if (dDelta < 0.5) + { + // просто текст на тексте или сменились настройки (font/brush) + pPrev->Write(oWriter, pManagerLight); + pPrev = pCurrent; + } + //else if (dDelta < 2 * pPrev->m_dSpaceWidthMM) + //{ + // // сменились настройки, но пробел все-таки вставить нужно + // pPrev->Write(oWriter, pManagerLight, true); + // pPrev = pCurrent; + //} + else + { + // расстояние слишком большое. нужно сделать большой пробел + pPrev->Write(oWriter, pManagerLight); + pPrev->WriteTo(dDelta, oWriter, pManagerLight); + pPrev = pCurrent; + } + } + + pPrev->Write(oWriter, pManagerLight); + } + + CParagraph::CParagraph(const TextAssociationType& eType) : m_arLines() + { + m_eType = etParagraph; + + m_bIsTextFrameProperties = false; + m_bIsNeedFirstLineIndent = false; + m_eTextAlignmentType = TextAlignmentType_ByWidth; + + m_dLeft = 0.0; + m_dRight = 0.0; + m_dTop = 0.0; + m_dWidth = 0.0; + m_dHeight = 0.0; + m_dFirstLine= 0.0; + + m_dSpaceBefore = 0.0; + m_dBaselinePos = 0.0; + + m_pManagerLight = NULL; + m_eTextAssociationType = eType; + + m_numLines = 0; + } + CParagraph::CParagraph(const CParagraph& oSrc) + { + *this = oSrc; + } + CParagraph::~CParagraph() + { + Clear(); + } + + void CParagraph::Clear() + { + size_t nCount = m_arLines.size(); + for (size_t i = 0; i < nCount; ++i) + { + CTextLine* pText = m_arLines[i]; + RELEASEOBJECT(pText); + } + m_arLines.clear(); + + m_pManagerLight = NULL; + } + + CParagraph& CParagraph::operator=(const CParagraph& oSrc) + { + if (this == &oSrc) + { + return *this; + } + + m_eType = etParagraph; + + m_bIsTextFrameProperties = oSrc.m_bIsTextFrameProperties; + m_bIsNeedFirstLineIndent = oSrc.m_bIsNeedFirstLineIndent; + m_eTextAlignmentType = oSrc.m_eTextAlignmentType; + + m_dLeft = oSrc.m_dLeft; + m_dRight = oSrc.m_dRight; + m_dTop = oSrc.m_dTop; + m_dWidth = oSrc.m_dWidth; + m_dHeight = oSrc.m_dHeight; + m_dFirstLine= oSrc.m_dFirstLine; + + m_dSpaceBefore = oSrc.m_dSpaceBefore; + m_dBaselinePos = oSrc.m_dBaselinePos; + + m_eTextAssociationType = oSrc.m_eTextAssociationType; + + Clear(); + size_t nCount = oSrc.m_arLines.size(); + for (size_t i = 0; i < nCount; ++i) + { + m_arLines.push_back(new CTextLine(*oSrc.m_arLines[i])); + } + + m_pManagerLight = oSrc.m_pManagerLight; + + m_numLines = oSrc.m_numLines; + return *this; + } + + void CParagraph::ToXml(NSStringUtils::CStringBuilder& oWriter) + { + oWriter.WriteString(L""); + + switch (m_eTextAssociationType) + { + case TextAssociationTypeBlockChar: + case TextAssociationTypeBlockLine: + { + oWriter.WriteString(L""); + break; + } + case TextAssociationTypePlainLine: + case TextAssociationTypePlainParagraph: + { + if (m_bIsTextFrameProperties) + { + oWriter.WriteString(L""); + break; + } + oWriter.WriteString(L" 0.0) + { + oWriter.WriteString(L"\" w:right=\""); + oWriter.AddInt((int)(m_dRight * c_dMMToDx)); + } + if (m_bIsNeedFirstLineIndent) + { + oWriter.WriteString(L"\" w:firstLine=\""); + oWriter.AddInt((int)(m_dFirstLine * c_dMMToDx)); + } + + if (m_eTextAssociationType == TextAssociationTypePlainParagraph) + { + switch (m_eTextAlignmentType) + { + case TextAlignmentType_ByCenter: + oWriter.WriteString(L"\"/>"); + break; + } + default: + break; + } + + size_t nCount = m_arLines.size(); + for (size_t i = 0; i < nCount; ++i) + { + CTextLine* pTextLine = m_arLines[i]; + if (m_eTextAssociationType != TextAssociationTypePlainParagraph) + { + pTextLine->SortConts(); + } + pTextLine->ToXml(oWriter, m_pManagerLight); + } + + oWriter.WriteString(L""); + } +} diff --git a/DocxRenderer/src/logic/ElementParagraph.h b/DocxRenderer/src/logic/ElementParagraph.h index 6c554f22b8..bcab48fb54 100644 --- a/DocxRenderer/src/logic/ElementParagraph.h +++ b/DocxRenderer/src/logic/ElementParagraph.h @@ -85,26 +85,7 @@ namespace NSDocxRenderer } } - inline void DeleteSpaces(NSStringUtils::CStringUTF32& oText) - { - size_t nLen = oText.length(); - size_t nStart = 0; - - while ((nStart < nLen) && (' ' == oText[nStart])) - ++nStart; - - if (nStart == nLen) - { - oText = L""; - return; - } - - size_t nEnd = nLen - 1; - while ((nEnd > nStart) && (' ' == oText[nEnd])) - --nEnd; - - oText = oText.substr(nStart, nEnd - nStart + 1); - } + void DeleteSpaces(NSStringUtils::CStringUTF32& oText); class CContText { @@ -134,224 +115,28 @@ namespace NSDocxRenderer double m_dSpaceByText; public: - CContText() - { - m_strPickFontName = L""; - m_lPickFontStyle = 0; + CContText(); + ~CContText(){} - m_dX = 0; - m_dY = 0; - m_dWidth = 0; - m_dHeight = 0; - m_dLastX = 0; + inline void Clear(); - m_dWidthWithoutSpaces = 0; - m_dLeftWithoutSpaces = 0; + CContText(const CContText& oSrc); - m_dPosition = 0; - m_dSpaceWidthMM = 0; + CContText& operator=(const CContText& oSrc); + void CopyFormat(const CContText& oSrc); - m_dCalculateWidth = 0; + bool IsBigger(const CContText* oSrc); + bool IsBiggerOrEqual(const CContText* oSrc); - m_dSpaceByText = 0; - } - ~CContText() - { - } + double GetIntersect(const CContText* oSrc) const; - inline void Clear() - { - } + void Write(NSStringUtils::CStringBuilder& oWriter, + CFontManagerLight* pManagerLight, + bool bIsAddSpace = false); - CContText(const CContText& oSrc) - { - *this = oSrc; - } - CContText& operator=(const CContText& oSrc) - { - m_oFont = oSrc.m_oFont; - m_oBrush = oSrc.m_oBrush; - - m_oText = oSrc.m_oText; - m_oGidText = oSrc.m_oGidText; - - m_strPickFontName = oSrc.m_strPickFontName; - m_lPickFontStyle = oSrc.m_lPickFontStyle; - - m_dX = oSrc.m_dX; - m_dY = oSrc.m_dY; - m_dWidth = oSrc.m_dWidth; - m_dHeight = oSrc.m_dHeight; - - m_dLastX = oSrc.m_dLastX; - - m_dWidthWithoutSpaces = oSrc.m_dWidthWithoutSpaces; - m_dLeftWithoutSpaces = oSrc.m_dLeftWithoutSpaces; - - m_dPosition = oSrc.m_dPosition; - m_dSpaceWidthMM = oSrc.m_dSpaceWidthMM; - - m_dCalculateWidth = oSrc.m_dCalculateWidth; - m_dSpaceByText = oSrc.m_dSpaceByText; - - return *this; - } - - inline bool IsBigger(const CContText* oSrc) - { - return (m_dX > oSrc->m_dX) ? true : false; - } - inline bool IsBiggerOrEqual(const CContText* oSrc) - { - return (m_dX >= oSrc->m_dX) ? true : false; - } - - inline double GetIntersect(const CContText* oSrc) const - { - double d1 = std::max(m_dX, oSrc->m_dX); - double d2 = std::min(m_dX + m_dWidth, oSrc->m_dX + oSrc->m_dWidth); - - if (d2 > d1) - return d2 - d1; - return 0; - } - - inline void Write(NSStringUtils::CStringBuilder& oWriter, CFontManagerLight* pManagerLight, bool bIsAddSpace = false) - { - oWriter.WriteString(L""); - - if (m_dWidth != m_dWidthWithoutSpaces) - { - DeleteSpaces(m_oText); - m_dWidth = m_dWidthWithoutSpaces; - } - - if (m_strPickFontName.empty()) - { - if (m_oFont.Bold) - oWriter.WriteString(L""); - if (m_oFont.Italic) - oWriter.WriteString(L""); - - if (bIsAddSpace) - { - m_dWidth += m_dSpaceWidthMM; - m_oText += L" "; - } - } - else - { - if (0x01 == (0x01 & m_lPickFontStyle)) - oWriter.WriteString(L""); - if (0x02 == (0x02 & m_lPickFontStyle)) - oWriter.WriteString(L""); - - if (bIsAddSpace) - { - m_dWidth += pManagerLight->GetSpaceWidth(); - m_oText += L" "; - } - - // нужно перемерять... - double ___dSize = (double)((LONG)(m_oFont.Size * 2)) / 2; - pManagerLight->LoadFont(m_strPickFontName, m_lPickFontStyle, ___dSize, false); - double dWidth = pManagerLight->MeasureStringWidth(m_oText.ToStdWString()); - - if (fabs(dWidth - m_dWidth) > 2) - { - double dSpacing = (m_dWidth - dWidth) / (m_oText.length() + 1); - dSpacing *= c_dMMToDx; - - oWriter.WriteString(L""); - } - } - - int lSize = (int)(2 * m_oFont.Size); - oWriter.WriteString(L""); - - std::wstring& strFontName = m_strPickFontName.empty() ? m_oFont.Name : m_strPickFontName; - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - oWriter.WriteEncodeXmlString(m_oText.ToStdWString()); - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - } - - void WriteTo(double dSpacingMM, NSStringUtils::CStringBuilder& oWriter, CFontManagerLight* pManagerLight) - { - oWriter.WriteString(L""); - - double dSpaceMMSize = m_dSpaceWidthMM; - if (m_strPickFontName.empty()) - { - if (m_oFont.Bold) - oWriter.WriteString(L""); - if (m_oFont.Italic) - oWriter.WriteString(L""); - } - else - { - if (0x01 == (0x01 & m_lPickFontStyle)) - oWriter.WriteString(L""); - if (0x02 == (0x02 & m_lPickFontStyle)) - oWriter.WriteString(L""); - - dSpaceMMSize = pManagerLight->GetSpaceWidth(); - } - - int lSize = (int)(2 * m_oFont.Size); - oWriter.WriteString(L""); - - std::wstring& strFontName = m_strPickFontName.empty() ? m_oFont.Name : m_strPickFontName; - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - - LONG lSpacing = (LONG)((dSpacingMM - dSpaceMMSize) * c_dMMToDx); - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - oWriter.WriteString(L" "); - oWriter.WriteString(L""); - - oWriter.WriteString(L""); - } + void WriteTo(double dSpacingMM, + NSStringUtils::CStringBuilder& oWriter, + CFontManagerLight* pManagerLight); }; class CTextLine @@ -368,359 +153,74 @@ namespace NSDocxRenderer double m_dHeight; public: - CTextLine() : m_arConts() - { - m_dBaselinePos = 0; + CTextLine(); + void Clear(); - m_dX = 0; - m_dY = 0; - m_dWidth = 0; - m_dHeight = 0; - } - void Clear() - { - for (std::vector::iterator iter = m_arConts.begin(); iter != m_arConts.end(); iter++) - { - CContText* pText = *iter; - RELEASEOBJECT(pText); - } - m_arConts.clear(); - } + ~CTextLine(); - ~CTextLine() - { - Clear(); - } + CTextLine(const CTextLine& oSrc); + CTextLine& operator=(const CTextLine& oSrc); - CTextLine(const CTextLine& oSrc) - { - *this = oSrc; - } - CTextLine& operator=(const CTextLine& oSrc) - { - Clear(); - for (std::vector::const_iterator iter = oSrc.m_arConts.begin(); iter != oSrc.m_arConts.end(); iter++) - { - m_arConts.push_back(new CContText(*(*iter))); - } + void AddCont(CContText* pCont, double dBaselineOffset); + bool IsBigger(const CTextLine* oSrc); + bool IsBiggerOrEqual(const CTextLine* oSrc); + void SortConts(); - m_dBaselinePos = oSrc.m_dBaselinePos; - m_dX = oSrc.m_dX; - m_dY = oSrc.m_dY; - m_dWidth = oSrc.m_dWidth; - m_dHeight = oSrc.m_dHeight; - } - - inline void AddCont(CContText* pCont, double dBaselineOffset) - { - if (0 == m_arConts.size()) - m_dBaselineOffset = dBaselineOffset; - - if ( ( pCont->m_dX > 0 ) && ( ( m_dX == 0 ) || ( pCont->m_dX < m_dX ) ) ) - m_dX = pCont->m_dX; - - if (m_dHeight < pCont->m_dHeight) - m_dHeight = pCont->m_dHeight; - - m_arConts.push_back(pCont); - } - - inline bool IsBigger(const CTextLine* oSrc) - { - return (m_dBaselinePos > oSrc->m_dBaselinePos) ? true : false; - } - inline bool IsBiggerOrEqual(const CTextLine* oSrc) - { - return (m_dBaselinePos >= oSrc->m_dBaselinePos) ? true : false; - } - - inline void SortConts() - { - // сортировка непрерывных слов по m_dX - SortElements(m_arConts); - } - - void Merge(CTextLine* pTextLine) - { - size_t nCount = pTextLine->m_arConts.size(); - if (0 != nCount) - { - if (pTextLine->m_dX < m_dX) - { - m_dX = pTextLine->m_dX; - } - if (pTextLine->m_dBaselinePos < m_dBaselinePos) - { - m_dHeight = (m_dBaselinePos - pTextLine->m_dBaselinePos + pTextLine->m_dHeight); - } - else - { - m_dHeight = (pTextLine->m_dBaselinePos - m_dBaselinePos + m_dHeight); - } - - double dSubPosition = m_dBaselinePos - pTextLine->m_dBaselinePos; - - for (size_t i = 0; i < nCount; ++i) - { - pTextLine->m_arConts[i]->m_dPosition = dSubPosition; - m_arConts.push_back(pTextLine->m_arConts[i]); - } - } - } - - void Analyze() - { - size_t nCountConts = m_arConts.size(); - - if (0 == nCountConts) - return; - - CContText* pFirst = m_arConts[0]; - - for (size_t i = 1; i < nCountConts; ++i) - { - CContText* pCurrent = m_arConts[i]; - - if (pFirst->m_strPickFontName != pCurrent->m_strPickFontName || - pFirst->m_oFont.Bold != pCurrent->m_oFont.Bold || - pFirst->m_oFont.Italic != pCurrent->m_oFont.Italic) - { - // вообще надо бы все объединить. но пока этот метод на соединение "первых" - break; - } - - double dRight = pFirst->m_dX + pFirst->m_dWidth; - double dLeft = pCurrent->m_dX; - - if (fabs(dRight - dLeft) > 0.5) - { - // вообще надо бы все объединить. но пока этот метод на соединение "первых" - break; - } - - // продолжаем слово - pFirst->m_oText += pCurrent->m_oText; - pFirst->m_dWidth = (dLeft + pCurrent->m_dWidth - pFirst->m_dX); - - if (pFirst->m_dWidthWithoutSpaces < 0.0001) - { - pFirst->m_dLeftWithoutSpaces = pCurrent->m_dLeftWithoutSpaces; - } - - if (pCurrent->m_dWidthWithoutSpaces > 0.0001) - { - pFirst->m_dWidthWithoutSpaces = pCurrent->m_dLeftWithoutSpaces + pCurrent->m_dWidthWithoutSpaces - pFirst->m_dLeftWithoutSpaces; - } - - m_arConts.erase(m_arConts.begin() + i); - --i; - --nCountConts; - } - } - - bool IsForceBlock() - { - // линия отсортирована, так что сравниваем только соседние conts - size_t nCount = m_arConts.size(); - if (nCount <= 1) - return false; - - for (size_t i = 0; i < nCount; i++) - { - for (size_t j = i + 1; j < nCount; j++) - { - if (m_arConts[i]->GetIntersect(m_arConts[j]) > 10) - return true; - } - } - return false; - } - - void ToXml(NSStringUtils::CStringBuilder& oWriter, CFontManagerLight* pManagerLight) - { - size_t nCountConts = m_arConts.size(); - - if (0 == nCountConts) - return; - - CContText* pPrev = m_arConts[0]; - double dDelta = 0; - - for (size_t i = 1; i < nCountConts; ++i) - { - CContText* pCurrent = m_arConts[i]; - - if (0 == pCurrent->m_dWidthWithoutSpaces) - continue; - - dDelta = pCurrent->m_dLeftWithoutSpaces - (pPrev->m_dLeftWithoutSpaces + pPrev->m_dWidthWithoutSpaces); - - if (dDelta < 0.5) - { - // просто текст на тексте или сменились настройки (font/brush) - pPrev->Write(oWriter, pManagerLight); - pPrev = pCurrent; - } - //else if (dDelta < 2 * pPrev->m_dSpaceWidthMM) - //{ - // // сменились настройки, но пробел все-таки вставить нужно - // pPrev->Write(oWriter, pManagerLight, true); - // pPrev = pCurrent; - //} - else - { - // расстояние слишком большое. нужно сделать большой пробел - pPrev->Write(oWriter, pManagerLight); - pPrev->WriteTo(dDelta, oWriter, pManagerLight); - pPrev = pCurrent; - } - } - - pPrev->Write(oWriter, pManagerLight); - } + //Объединяем слова из двух строк + void Merge(CTextLine* pTextLine); + //Объединяем подходящие слова в одну строку, если возможно + void Analyze(); + bool IsForceBlock(); + void ToXml(NSStringUtils::CStringBuilder& oWriter, CFontManagerLight* pManagerLight); + void CalculateWidth(); + void AddSpaceToEnd(); }; class CParagraph : public CBaseItem { public: + enum TextAlignmentType + { + TextAlignmentType_ByLeftEdge = 0, + TextAlignmentType_ByCenter = 1, + TextAlignmentType_ByRightEdge = 2, + TextAlignmentType_ByWidth = 3 + }; + // text frame properties bool m_bIsTextFrameProperties; + bool m_bIsNeedFirstLineIndent; + TextAlignmentType m_eTextAlignmentType; // geometry paragraph - double m_dLeft; + double m_dLeft; //сдвиг относительно левого края страницы + double m_dRight; //сдвиг относительно правого края страницы double m_dTop; double m_dWidth; - double m_dHeight; + double m_dHeight; //высота каждой строки + double m_dFirstLine; //сдвиг относительно m_dLeft CFontManagerLight* m_pManagerLight; double m_dSpaceBefore; + double m_dBaselinePos; TextAssociationType m_eTextAssociationType; std::vector m_arLines; + // statistic + size_t m_numLines; //число изначально входящих линий + public: - CParagraph(const TextAssociationType& eType) : m_arLines() - { - m_eType = etParagraph; + CParagraph(const TextAssociationType& eType); + CParagraph(const CParagraph& oSrc); + ~CParagraph(); - m_bIsTextFrameProperties = false; + void Clear(); + CParagraph& operator=(const CParagraph& oSrc); - m_dLeft = 0.0; - m_dTop = 0.0; - m_dWidth = 0.0; - m_dHeight = 0.0; + virtual void ToXml(NSStringUtils::CStringBuilder& oWriter); - m_dSpaceBefore = 0.0; - - m_pManagerLight = NULL; - m_eTextAssociationType = eType; - } - CParagraph(const CParagraph& oSrc) - { - *this = oSrc; - } - ~CParagraph() - { - Clear(); - } - - void Clear() - { - size_t nCount = m_arLines.size(); - for (size_t i = 0; i < nCount; ++i) - { - CTextLine* pText = m_arLines[i]; - RELEASEOBJECT(pText); - } - m_arLines.clear(); - - m_pManagerLight = NULL; - } - - CParagraph& operator=(const CParagraph& oSrc) - { - m_eType = etParagraph; - - m_bIsTextFrameProperties = oSrc.m_bIsTextFrameProperties; - - m_dLeft = oSrc.m_dLeft; - m_dTop = oSrc.m_dTop; - m_dWidth = oSrc.m_dWidth; - m_dHeight = oSrc.m_dHeight; - - m_dSpaceBefore = oSrc.m_dSpaceBefore; - - m_eTextAssociationType = oSrc.m_eTextAssociationType; - - Clear(); - size_t nCount = oSrc.m_arLines.size(); - for (size_t i = 0; i < nCount; ++i) - { - m_arLines.push_back(new CTextLine(*oSrc.m_arLines[i])); - } - - m_pManagerLight = oSrc.m_pManagerLight; - return *this; - } - - virtual void ToXml(NSStringUtils::CStringBuilder& oWriter) - { - oWriter.WriteString(L""); - - switch (m_eTextAssociationType) - { - case TextAssociationTypeBlockChar: - { - oWriter.WriteString(L""); - break; - } - case TextAssociationTypeBlockLine: - { - oWriter.WriteString(L""); - break; - } - case TextAssociationTypePlainLine: - { - if (m_bIsTextFrameProperties) - { - oWriter.WriteString(L""); - break; - } - oWriter.WriteString(L""); - break; - } - default: - break; - } - - size_t nCount = m_arLines.size(); - for (size_t i = 0; i < nCount; ++i) - { - CTextLine* pTextLine = m_arLines[i]; - pTextLine->SortConts(); - pTextLine->ToXml(oWriter, m_pManagerLight); - } - - oWriter.WriteString(L""); - } + void CalculateTextAlignmentType(); }; } diff --git a/DocxRenderer/src/logic/Page.cpp b/DocxRenderer/src/logic/Page.cpp new file mode 100644 index 0000000000..551e7db116 --- /dev/null +++ b/DocxRenderer/src/logic/Page.cpp @@ -0,0 +1,1028 @@ +#include "Page.h" + +namespace NSDocxRenderer +{ + CPage::CPage(NSFonts::IApplicationFonts* pFonts) : m_oManager(pFonts), m_oManagerLight(pFonts) + { + m_pFont = NULL; + m_pBrush = NULL; + m_pPen = NULL; + m_pShadow = NULL; + m_pEdgeText = NULL; + + m_pTransform = NULL; + m_pSimpleGraphicsConverter = NULL; + + m_dWidth = 0; + m_dHeight = 0; + + m_pCurrentLine = NULL; + m_eTextAssociationType = TextAssociationTypePlainLine; + + m_bIsDeleteTextClipPage = true; + + m_dLastTextX = -1; + m_dLastTextY = -1; + m_dLastTextX_block = m_dLastTextX; + } + +void CPage::Init(NSStructures::CFont* pFont, NSStructures::CPen* pPen, NSStructures::CBrush* pBrush, + NSStructures::CShadow* pShadow, NSStructures::CEdgeText* pEdge, Aggplus::CMatrix* pMatrix, Aggplus::CGraphicsPathSimpleConverter* pSimple) + { + m_pFont = pFont; + m_pPen = pPen; + m_pBrush = pBrush; + m_pShadow = pShadow; + m_pEdgeText = pEdge; + + m_pTransform = pMatrix; + m_pSimpleGraphicsConverter = pSimple; + + m_oManager.m_pFont = m_pFont; + m_oManager.m_pTransform = m_pTransform; + + m_pCurrentLine = NULL; + + m_oWriterVML.AddSize(1000); + + m_dLastTextX = -1; + m_dLastTextY = -1; + m_dLastTextX_block = m_dLastTextX; + } + +void CPage::Clear() + { + ClearTextLines(); + ClearGraphicItems(); + ClearParagraphs(); + ClearParagraphsBlocks(); + + m_pCurrentLine = NULL; + + m_oWriterVML.ClearNoAttack(); + + m_dLastTextX = -1; + m_dLastTextY = -1; + m_dLastTextX_block = m_dLastTextX; + } + + void CPage::ClearTextLines() + { + size_t nCount = m_arTextLine.size(); + for (size_t i = 0; i < nCount; ++i) + { + CTextLine* pTemp = m_arTextLine[i]; + RELEASEOBJECT(pTemp); + } + m_arTextLine.clear(); + } + + void CPage::ClearGraphicItems() + { + size_t nCount = m_arGraphicItems.size(); + for (size_t i = 0; i < nCount; ++i) + { + CBaseItem* pTemp = m_arGraphicItems[i]; + RELEASEOBJECT(pTemp); + } + m_arGraphicItems.clear(); + } + + void CPage::ClearParagraphs() + { + size_t nCount = m_arParagraphs.size(); + for (size_t i = 0; i < nCount; ++i) + { + CParagraph* pTemp = m_arParagraphs[i]; + RELEASEOBJECT(pTemp); + } + m_arParagraphs.clear(); + } + + void CPage::ClearParagraphsBlocks() + { + size_t nCount = m_arParagraphsBlocks.size(); + for (size_t i = 0; i < nCount; ++i) + { + CParagraph* pTemp = m_arParagraphsBlocks[i]; + RELEASEOBJECT(pTemp); + } + m_arParagraphsBlocks.clear(); + } + + CPage::~CPage() + { + Clear(); + } + + void CPage::SetCurrentLineByBaseline(const double& dBaseLinePos) + { + if ((NULL == m_pCurrentLine) || (TextAssociationTypeBlockChar == m_eTextAssociationType)) + { + // пустая (в плане текста) страница + m_pCurrentLine = new CTextLine(); + + m_pCurrentLine->m_dBaselinePos = dBaseLinePos; + m_arTextLine.push_back(m_pCurrentLine); + return; + } + if (fabs(m_pCurrentLine->m_dBaselinePos - dBaseLinePos) <= THE_SAME_STRING_Y_PRECISION_MM) + { + return; + } + size_t nCount = m_arTextLine.size(); + for (size_t i = 0; i < nCount; ++i) + { + if (fabs(m_arTextLine[i]->m_dBaselinePos - dBaseLinePos) <= THE_SAME_STRING_Y_PRECISION_MM) + { + m_pCurrentLine = m_arTextLine[i]; + return; + } + } + + // линия не нашлась - не беда - создадим новую + m_pCurrentLine = new CTextLine(); + m_pCurrentLine->m_dBaselinePos = dBaseLinePos; + m_arTextLine.push_back(m_pCurrentLine); + return; + } + + void CPage::DeleteTextClipPage() + { + if (m_bIsDeleteTextClipPage) + { + // удалим все линии, которые выходят за границы страницы + size_t nCount = m_arTextLine.size(); + for (size_t i = 0; i < nCount; ++i) + { + CTextLine* pTextLine = m_arTextLine[i]; + + double _top = pTextLine->m_dBaselinePos - pTextLine->m_dHeight; + double _bottom = pTextLine->m_dBaselinePos; + + if (_top >= m_dHeight || _bottom <= 0) + { + m_arTextLine.erase(m_arTextLine.begin() + i); + --i; + --nCount; + } + } + } + } + + // image commands + void CPage::WriteImage(CImageInfo& oInfo, double& fX, double& fY, double& fWidth, double& fHeight) + { + CImage* pImage = new CImage(oInfo, L""); + + double dRotation = m_pTransform->z_Rotation(); + + if (fabs(dRotation) < 5.0) + { + double x1 = fX; + double y1 = fY; + double x2 = fX + fWidth; + double y2 = fY + fHeight; + + m_pTransform->TransformPoint(x1, y1); + m_pTransform->TransformPoint(x2, y2); + + if (x1 <= x2) + { + pImage->m_dLeft = x1; + pImage->m_dWidth = x2 - x1; + } + else + { + pImage->m_dLeft = x2; + pImage->m_dWidth = x1 - x2; + } + + if (y1 <= y2) + { + pImage->m_dTop = y1; + pImage->m_dHeight = y2 - y1; + } + else + { + pImage->m_dTop = y2; + pImage->m_dHeight = y1 - y2; + } + + pImage->m_dRotate = 0.0; + } + else + { + double x1 = fX; + double y1 = fY; + double x2 = fX + fWidth; + double y2 = fY + fHeight; + + Aggplus::CMatrix oTemp = *m_pTransform; + + double dCx = (x1 + x2) / 2; + double dCy = (y1 + y2) / 2; + m_pTransform->TransformPoint(dCx, dCy); + oTemp.RotateAt(-dRotation, dCx, dCy, Aggplus::MatrixOrderAppend); + + oTemp.TransformPoint(x1, y1); + oTemp.TransformPoint(x2, y2); + + if (x1 <= x2) + { + pImage->m_dLeft = x1; + pImage->m_dWidth = x2 - x1; + } + else + { + pImage->m_dLeft = x2; + pImage->m_dWidth = x1 - x2; + } + + if (y1 <= y2) + { + pImage->m_dTop = y1; + pImage->m_dHeight = y2 - y1; + } + else + { + pImage->m_dTop = y2; + pImage->m_dHeight = y1 - y2; + } + + pImage->m_dRotate = dRotation; + } + + m_arGraphicItems.push_back(pImage); + } + + // path commands + void CPage::MoveTo(double& dX, double& dY) + { + m_pTransform->TransformPoint(dX, dY); + m_oVector.MoveTo(dX, dY); + + } + void CPage::LineTo(double& dX, double& dY) + { + m_pTransform->TransformPoint(dX, dY); + m_oVector.LineTo(dX, dY); + } + void CPage::CurveTo(double& x1, double& y1, double& x2, double& y2, double& x3, double& y3) + { + m_pTransform->TransformPoint(x1, y1); + m_pTransform->TransformPoint(x2, y2); + m_pTransform->TransformPoint(x3, y3); + + m_oVector.CurveTo(x1, y1, x2, y2, x3, y3); + } + void CPage::Start() + { + } + void CPage::End() + { + m_oVector.End(); + m_oWriterVML.ClearNoAttack(); + } + void CPage::Close() + { + m_oVector.Close(); + } + void CPage::DrawPath(LONG lType, LONG lTxId) + { + if ((m_oVector.m_dLeft <= m_oVector.m_dRight) && (m_oVector.m_dTop <= m_oVector.m_dBottom)) + { + CShape* pShape = new CShape(); + + pShape->m_lTxId = lTxId; + + pShape->m_oPen = *m_pPen; + pShape->m_oBrush = *m_pBrush; + + // нормализуем толщину линии + double dScaleTransform = (m_pTransform->sx() + m_pTransform->sy()) / 2.0; + pShape->m_oPen.Size *= dScaleTransform; + + if ((lType & 0x01) == 0x00) + { + if ((fabs(m_oVector.m_dLeft - m_oVector.m_dRight) < 0.3) || (fabs(m_oVector.m_dTop - m_oVector.m_dBottom) < 0.3)) + { + lType = 0x01; + pShape->m_oPen.Color = m_pBrush->Color1; + pShape->m_oPen.Alpha = m_pBrush->Alpha1; + //pShape->m_oPen.Size = max(pShape->m_oPen.Size, 1); + } + } + + pShape->CreateFromVectorData(&m_oVector, m_oWriterVML, 100000, lType); + m_arGraphicItems.push_back(pShape); + } + } + + void CPage::WriteText(unsigned int* pUnicodes, unsigned int* pGids, unsigned int nCount, double fX, double fY, double fWidth, double fHeight, double fBaseLineOffset, bool bIsPDFAnalyzer) + { + double dTextX = fX; + double dTextY = fY; + double dTextR = fX + fWidth; + double dTextB = fY + fHeight; + + m_pTransform->TransformPoint(dTextX, dTextY); + m_pTransform->TransformPoint(dTextR, dTextB); + + double dTextW = dTextR - dTextX; + double dTextH = dTextB - dTextY; + + NSStringUtils::CStringUTF32 oText((uint32_t*)pUnicodes, nCount); + + if ((pUnicodes != NULL) && (pGids != NULL)) + { + for (unsigned int i = 0; i < nCount; ++i) + { + if ( !IsUnicodeSymbol( pUnicodes[i] ) ) + { + oText[i] = ' '; + } + } + } + + bool bIsPath = ((NULL == pGids) && !bIsPDFAnalyzer) ? false : true; + + m_oManager.LoadFont(0, !bIsPath); + + if (bIsPath) + m_oManager.GenerateFontName2(oText); + + if (fabs(dTextW) < 0.01 || (dTextW > 10)) + { + double _x = 0; + double _y = 0; + double _w = 0; + double _h = 0; + + if (NULL != pGids) + { + m_oManager.SetStringGid(1); + m_oManager.MeasureStringGids(pGids, nCount, dTextX, dTextY, _x, _y, _w, _h, CFontManager::MeasureTypePosition); + } + else + { + // такого быть не должно (только из xps) + m_oManager.SetStringGid(0); + m_oManager.MeasureStringGids(pUnicodes, nCount, dTextX, dTextY, _x, _y, _w, _h, CFontManager::MeasureTypePosition); + } + + dTextW = _w; + //dTextW *= c_dPixToMM; + } + + double dBaseLinePos = dTextY + fBaseLineOffset; + dTextH = m_oManager.GetFontHeight(); + + SetCurrentLineByBaseline(dBaseLinePos); + + CContText* pLastCont = NULL; + size_t nCountConts = m_pCurrentLine->m_arConts.size(); + if (nCountConts != 0) + pLastCont = m_pCurrentLine->m_arConts[nCountConts - 1]; + + if (NULL == pLastCont) + { + // первое слово в линии + CContText* pCont = new CContText(); + + pCont->m_dX = dTextX; + pCont->m_dLastX = dTextX; + pCont->m_dY = dBaseLinePos; + + pCont->m_dWidth = dTextW; + pCont->m_dHeight = dTextH; + + if (IsSpaceUtf32(oText)) + { + pCont->m_dWidthWithoutSpaces = 0; + pCont->m_dLeftWithoutSpaces = dTextX + dTextW; + } + else + { + pCont->m_dWidthWithoutSpaces = dTextW; + pCont->m_dLeftWithoutSpaces = dTextX; + } + + pCont->m_oText = oText; + + pCont->m_oFont = m_oManager.m_oFont.m_oFont; + pCont->m_oBrush = *m_pBrush; + + if (bIsPath) + { + pCont->m_strPickFontName = m_oManager.m_strCurrentPickFont; + pCont->m_lPickFontStyle = m_oManager.m_lCurrentPictFontStyle; + } + + pCont->m_dSpaceWidthMM = m_oManager.m_dSpaceWidthMM; + + m_pCurrentLine->AddCont(pCont, m_oManager.m_oFont.m_dBaselineOffset); + + m_dLastTextX = dTextX; + m_dLastTextY = dBaseLinePos; + m_dLastTextX_block = m_dLastTextX; + return; + } + + // продолжение линии + //if (m_lCurrentCommand == c_nTextType && pLastCont->m_oFont.IsEqual(&m_oManager.m_oFontOld) && pLastCont->m_oBrush.IsEqual(m_pBrush)) + //{ + // // быстрое отметание вс¤ких проверок + // pLastCont->m_strText += strText; + // pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); + // return; + //} + + double dRight = pLastCont->m_dX + pLastCont->m_dWidth; + + if (pLastCont->m_oFont.IsEqual(&m_oManager.m_oFont.m_oFont) && pLastCont->m_oBrush.IsEqual(m_pBrush)) + { + // настройки одинаковые. теперь смотрим, на расположение + if (fabs(dRight - dTextX) < 0.5) + { + // продолжаем слово + pLastCont->m_oText += oText; + pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); + + if (!IsSpaceUtf32(oText)) + { + if (0 == pLastCont->m_dWidthWithoutSpaces) + pLastCont->m_dLeftWithoutSpaces = dTextX; + + pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; + } + else if (0 == pLastCont->m_dWidthWithoutSpaces) + { + pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; + } + + m_dLastTextX = dTextX; + m_dLastTextY = dBaseLinePos; + m_dLastTextX_block = m_dLastTextX; + pLastCont->m_dLastX = dTextX; + return; + } + else if ((dRight < dTextX) && ((dTextX - dRight) < m_oManager.m_dSpaceWidthMM)) + { + // продолжаем слово с пробелом + if (m_eTextAssociationType != TextAssociationTypePlainLine && + m_eTextAssociationType != TextAssociationTypePlainParagraph) + { + pLastCont->m_oText += uint32_t(' '); + } + pLastCont->m_oText += oText; + pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); + + if (!IsSpaceUtf32(oText)) + { + if (0 == pLastCont->m_dWidthWithoutSpaces) + pLastCont->m_dLeftWithoutSpaces = dTextX; + + pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; + } + else if (0 == pLastCont->m_dWidthWithoutSpaces) + { + pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; + } + + m_dLastTextX = dTextX; + m_dLastTextY = dBaseLinePos; + m_dLastTextX_block = m_dLastTextX; + pLastCont->m_dLastX = dTextX; + return; + } + else if (fabs(dBaseLinePos - pLastCont->m_dY) < 0.01 && + fabs(m_dLastTextY - pLastCont->m_dY) < 0.01 && + fabs(m_dLastTextX - pLastCont->m_dLastX) < 0.01) + { + // идет текст подряд, но с расстояниями что-то не так. смотрим - если новый текст идет после предыдущего, но + // просто левее чем предыдущий x + w - то считаем это нормальным. и дописываем слово. корректируя длину + if (dTextX < dRight && dTextX > pLastCont->m_dLastX) + { + // продолжаем слово + pLastCont->m_oText += oText; + double dNewW = (dTextX + dTextW - pLastCont->m_dX); + if (pLastCont->m_dWidth < dNewW) + pLastCont->m_dWidth = dNewW; + + if (!IsSpaceUtf32(oText)) + { + if (0 == pLastCont->m_dWidthWithoutSpaces) + pLastCont->m_dLeftWithoutSpaces = dTextX; + + pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; + } + else if (0 == pLastCont->m_dWidthWithoutSpaces) + { + pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; + } + + m_dLastTextX = dTextX; + m_dLastTextY = dBaseLinePos; + m_dLastTextX_block = m_dLastTextX; + pLastCont->m_dLastX = dTextX; + return; + + } + + // еще одна заглушка на большой пробел - добавляем пробел, потом в линии все разрулится через spacing + if (dTextX > dRight && (dTextX - dRight) < 5 && fabs(m_dLastTextX_block - m_dLastTextX) < 0.01) + { + // продолжаем слово с пробелом + if (m_eTextAssociationType != TextAssociationTypePlainLine && + m_eTextAssociationType != TextAssociationTypePlainParagraph) + { + pLastCont->m_oText += uint32_t(' '); + } + pLastCont->m_oText += oText; + pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); + + if (!IsSpaceUtf32(oText)) + { + if (0 == pLastCont->m_dWidthWithoutSpaces) + pLastCont->m_dLeftWithoutSpaces = dTextX; + + pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; + } + else if (0 == pLastCont->m_dWidthWithoutSpaces) + { + pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; + } + + m_dLastTextX = dTextX; + m_dLastTextY = dBaseLinePos; + m_dLastTextX_block = m_dLastTextX; + pLastCont->m_dLastX = dTextX; + return; + } + } + } + + // либо пробел большой между словами, либо новый текст левее, либо настройки не те (шрифт, кисть) + // либо все вместе... просто добавл¤ем новое слово + CContText* pCont = new CContText(); + + pCont->m_dX = dTextX; + pCont->m_dY = dBaseLinePos; + pCont->m_dLastX = dTextX; + + pCont->m_dWidth = dTextW; + pCont->m_dHeight = dTextH; + + if (IsSpaceUtf32(oText)) + { + pCont->m_dWidthWithoutSpaces = 0; + pCont->m_dLeftWithoutSpaces = dTextX + dTextW; + } + else + { + pCont->m_dWidthWithoutSpaces = dTextW; + pCont->m_dLeftWithoutSpaces = dTextX; + } + + pCont->m_oText = oText; + + pCont->m_oFont = m_oManager.m_oFont.m_oFont; + pCont->m_oBrush = *m_pBrush; + + if (bIsPath) + { + pCont->m_strPickFontName = m_oManager.m_strCurrentPickFont; + pCont->m_lPickFontStyle = m_oManager.m_lCurrentPictFontStyle; + } + + pCont->m_dSpaceWidthMM = m_oManager.m_dSpaceWidthMM; + + m_pCurrentLine->AddCont(pCont, m_oManager.m_oFont.m_dBaselineOffset); + + m_dLastTextX = dTextX; + m_dLastTextY = dBaseLinePos; + m_dLastTextX_block = m_dLastTextX; + } + + void CPage::Build() + { + DeleteTextClipPage(); + + if (0 == m_arTextLine.size()) + return; + + switch (m_eTextAssociationType) + { + case TextAssociationTypeBlockChar: + BuildByTypeBlockChar(); + break; + case TextAssociationTypeBlockLine: + BuildByTypeBlockLine(); + break; + case TextAssociationTypePlainLine: + BuildByTypePlainLine(); + break; + case TextAssociationTypePlainParagraph: + BuildByTypePlainParagraph(); + break; + default: + break; + } + + m_arTextLine.clear(); //todo удалить нельзя и ClearTextLines(); тоже нельзя - наверное переделать + //использовать не указатели, а новые объекты + } + + void CPage::BuildByTypeBlockChar() + { + size_t nCount = m_arTextLine.size(); + for (size_t i = 0; i < nCount; ++i) + { + CTextLine* pTextLine = m_arTextLine[i]; + + CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); + pParagraph->m_pManagerLight = &m_oManagerLight; + pParagraph->m_bIsTextFrameProperties = true; + + pParagraph->m_dLeft = pTextLine->m_dX; + pParagraph->m_dTop = pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset; + + pParagraph->m_arLines.push_back(pTextLine); + + m_arParagraphs.push_back(pParagraph); + } + } + + void CPage::BuildByTypeBlockLine() + { + CTextLine* pFirstLine = m_arTextLine[0]; + + CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); + pParagraph->m_pManagerLight = &m_oManagerLight; + pParagraph->m_bIsTextFrameProperties = true; + + pParagraph->m_dLeft = pFirstLine->m_dX; + pParagraph->m_dTop = pFirstLine->m_dBaselinePos - pFirstLine->m_dHeight - pFirstLine->m_dBaselineOffset; + double dCurrentTop = pParagraph->m_dTop; + + pParagraph->m_arLines.push_back(pFirstLine); + + m_arParagraphs.push_back(pParagraph); + size_t nCount = m_arTextLine.size(); + for (size_t i = 1; i < nCount; ++i) + { + CTextLine* pTextLine = m_arTextLine[i]; + + CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); + pParagraph->m_pManagerLight = &m_oManagerLight; + pParagraph->m_bIsTextFrameProperties = true; + + if (((fabs(pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pFirstLine->m_dBaselinePos) > STANDART_STRING_HEIGHT_MM) && (pTextLine->m_dX == pFirstLine->m_dX)) || + ((pTextLine->m_dX != pFirstLine->m_dX) && (pTextLine->m_dBaselinePos != pFirstLine->m_dBaselinePos))) + { + pParagraph->m_dLeft = pTextLine->m_dX; + pParagraph->m_dTop = pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset; + dCurrentTop = pParagraph->m_dTop; + } + else + { + pParagraph->m_dLeft = pFirstLine->m_dX; + pParagraph->m_dTop = dCurrentTop; + } + + pFirstLine = pTextLine; + + pParagraph->m_arLines.push_back(pTextLine); + m_arParagraphs.push_back(pParagraph); + } + } + + void CPage::BuildByTypePlainLine() + { + SortElements(m_arTextLine); + + if (m_eTextAssociationType == TextAssociationTypePlainLine) + { + if (true) // merge line + { + for (std::vector::iterator iter = m_arTextLine.begin(); iter != m_arTextLine.end(); ++iter) + { + (*iter)->Analyze(); + } + } + Merge(STANDART_STRING_HEIGHT_MM / 3); + } + + double previousStringOffset = 0; + size_t nCount = m_arTextLine.size(); + for (size_t i = 0; i < nCount; ++i) + { + CTextLine* pTextLine = m_arTextLine[i]; + + CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); + pParagraph->m_pManagerLight = &m_oManagerLight; + pParagraph->m_bIsTextFrameProperties = false; +#if 0 + // у рамок нельзя выключить обтекание. поэтому в этом случае нужно конверировать в шейп + if (pTextLine->IsForceBlock()) + { + pParagraph->m_bIsTextFrameProperties = true; + pParagraph->m_dLeft = pTextLine->m_dX; + pParagraph->m_dTop = pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset; + + pParagraph->m_arLines.push_back(pTextLine); + m_arParagraphs.push_back(pParagraph); + continue; + } +#endif + + pTextLine->CalculateWidth(); + + pParagraph->m_dLeft = pTextLine->m_dX; + pParagraph->m_dTop = pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset; + pParagraph->m_dRight = m_dWidth - (pTextLine->m_dX + pTextLine->m_dWidth); + pParagraph->m_dWidth = pTextLine->m_dWidth; + + double dBeforeSpacing = (pTextLine->m_dBaselinePos - previousStringOffset - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset); + + pParagraph->m_dSpaceBefore = std::max(dBeforeSpacing, 0.0); + pParagraph->m_dBaselinePos = pTextLine->m_dBaselinePos; + + double dHeight = 1; + if (pTextLine->m_dHeight != 0) + { + dHeight = pTextLine->m_dHeight; + + if (dBeforeSpacing < 0) + dHeight += dBeforeSpacing; + } + + pParagraph->m_dHeight = dHeight; + + previousStringOffset = pTextLine->m_dBaselinePos - pTextLine->m_dBaselineOffset; + + pParagraph->m_arLines.push_back(pTextLine); + pParagraph->m_numLines++; + + CalculateTextAlignmentType(*pParagraph); + + m_arParagraphs.push_back(pParagraph); + } + } + + void CPage::CalculateTextAlignmentType(CParagraph& a_rParagraph) + { + if (a_rParagraph.m_dFirstLine == 0) //еще не был определен или для параграфа с одной строкой внутри + { + static double maxSringWidth = m_dWidth / 4 * 3; //нужна какая-нибудь константа... + static const double ERROR_X_MM = 3; + double delta = 2 * ERROR_X_MM; //координата m_dWidth/2 +- THE_STRING_X_PRECISION_MM + + if (fabs(m_dWidth/2 - a_rParagraph.m_dLeft - a_rParagraph.m_dWidth/2) <= delta && //если середины линий по x одинаковы + a_rParagraph.m_dWidth < maxSringWidth) + { + a_rParagraph.m_eTextAlignmentType = CParagraph::TextAlignmentType_ByCenter; + } + else if ((a_rParagraph.m_dLeft + a_rParagraph.m_dWidth/2) > (m_dWidth/2 + ERROR_X_MM) && //середина строки правее центра страницы + a_rParagraph.m_dWidth < maxSringWidth) + { + a_rParagraph.m_eTextAlignmentType = CParagraph::TextAlignmentType_ByRightEdge; + } + else if ((a_rParagraph.m_dLeft + a_rParagraph.m_dWidth/2) < (m_dWidth/2 - ERROR_X_MM) && //середина строки левее центра страницы + a_rParagraph.m_dWidth < maxSringWidth) + { + a_rParagraph.m_eTextAlignmentType = CParagraph::TextAlignmentType_ByLeftEdge; + } + else + { + a_rParagraph.m_eTextAlignmentType = CParagraph::TextAlignmentType_ByWidth; + } + } + else + { + //todo + a_rParagraph.m_eTextAlignmentType = CParagraph::TextAlignmentType_ByWidth; + } + + } + + + void CPage::BuildByTypePlainParagraph() + { + //todo возможно лучше разделить все сразу на фреймы и параграфы, до разбиения по линиям, + //т.к. если разномастный текст находится на примерно одной линии его корректно будет сложно отобразить + BuildByTypePlainLine(); + + CParagraph *currP, *nextP; + + //todo выравнивание m_arParagraphsBlocks с TextAlignmentType_ByWidth по всей странице для нескольких стилей + //пока работает только если присутствует один стиль сплошного текста + double corrRight = 0, corrHeight = 0; // + + //todo добавить междустрочные интервалы если их нет + + //коррекция BeforeSpacing + double corrBeforeSpacing = 0; + + for (size_t index = 0; index < m_arParagraphs.size(); index++) + { + size_t nextIndex = index+1; + CParagraph* pParagraph = nullptr; + + currP = m_arParagraphs[index]; + nextIndex == m_arParagraphs.size() ? + nextP = nullptr : + nextP = m_arParagraphs[nextIndex]; + + corrBeforeSpacing = 0; + + //todo пока только для левостроннего письма! - tmp! + if (nextP && //это должна быть не последняя строка + fabs(currP->m_dHeight - nextP->m_dHeight) <= THE_SAME_STRING_Y_PRECISION_MM && //высота строк должна быть примерно одинаковой + (currP->m_eTextAlignmentType == CParagraph::TextAlignmentType_ByLeftEdge || //todo - есть проблема если весь текст выровнен по центру + currP->m_eTextAlignmentType == CParagraph::TextAlignmentType_ByWidth) && + ((currP->m_dLeft > nextP->m_dLeft && fabs(currP->m_dRight - nextP->m_dRight) > THE_STRING_X_PRECISION_MM) || + (fabs(currP->m_dRight - nextP->m_dRight) <= THE_STRING_X_PRECISION_MM))) + { + index++; + + //наверное это сплошной текст + pParagraph = new CParagraph(*currP); + + //делаем абзац в сплошном тексте + pParagraph->m_bIsNeedFirstLineIndent = true; + + //Объединим 2 параграфа-строчки + pParagraph->m_arLines.back()->AddSpaceToEnd(); //todo - невсегда добавляется пробел, если текущая строка сложная (разные m_arConts) + for (size_t i = 0; i < nextP->m_arLines.size(); ++i) + { + pParagraph->m_arLines.push_back(new CTextLine(*nextP->m_arLines[i])); + pParagraph->m_numLines++; + } + pParagraph->m_dFirstLine = currP->m_dLeft - nextP->m_dLeft; + pParagraph->m_dRight = std::min(currP->m_dRight, nextP->m_dRight); + pParagraph->m_dLeft = std::min(currP->m_dLeft, nextP->m_dLeft); + pParagraph->m_dWidth = std::max(currP->m_dWidth, nextP->m_dWidth); + pParagraph->m_dHeight = (pParagraph->m_dHeight + nextP->m_dHeight) / 2; //берем среднее + + //для последующей коррекции + corrRight > 0 ? + corrRight = (corrRight + currP->m_dRight)/2: + corrRight = currP->m_dRight; + corrHeight > 0 ? + corrHeight = (corrHeight + currP->m_dHeight)/2: + corrHeight = currP->m_dHeight; + corrBeforeSpacing = nextP->m_dSpaceBefore; + + //проверим, подходят ли следующие параграфы-строчки для текущего pParagraph + if (nextIndex < m_arParagraphs.size()-1) + { + currP = nextP; + nextP = m_arParagraphs[++nextIndex]; + + while(nextIndex < m_arParagraphs.size() && + fabs(currP->m_dHeight - nextP->m_dHeight) < THE_SAME_STRING_Y_PRECISION_MM && + fabs(currP->m_dSpaceBefore - nextP->m_dSpaceBefore) <= THE_SAME_STRING_Y_PRECISION_MM && //расстрояние между строк тоже одинаково + (currP->m_eTextAlignmentType == nextP->m_eTextAlignmentType || + nextP->m_eTextAlignmentType == CParagraph::TextAlignmentType_ByLeftEdge) && + fabs(currP->m_dLeft - nextP->m_dLeft) < THE_STRING_X_PRECISION_MM //у последующих строк одинаковый отступ + ) + { + index++; + + //Объединим 2 параграфа-строчки + pParagraph->m_arLines.back()->AddSpaceToEnd(); //todo - невсегда добавляется пробел, если текущая строка сложная (разные m_arConts) + for (size_t i = 0; i < nextP->m_arLines.size(); ++i) + { + pParagraph->m_arLines.push_back(new CTextLine(*nextP->m_arLines[i])); + pParagraph->m_numLines++; + } + pParagraph->m_dRight = std::min(pParagraph->m_dRight, nextP->m_dRight); + pParagraph->m_dLeft = std::min(pParagraph->m_dLeft, nextP->m_dLeft); + pParagraph->m_dWidth = std::max(currP->m_dWidth, nextP->m_dWidth); + pParagraph->m_dHeight = (pParagraph->m_dHeight + nextP->m_dHeight) / 2; + + corrRight = (corrRight + currP->m_dRight)/2; + corrHeight = (corrHeight + currP->m_dHeight)/2; + corrBeforeSpacing += nextP->m_dSpaceBefore; + + if (nextIndex < m_arParagraphs.size()) { + currP = nextP; + nextP = m_arParagraphs[++nextIndex]; + } else { + break; + } + } + } + } else { + //todo может нужно некоторые параграфы сделать фреймами? условия? + /*if (currP->m_eTextAlignmentType == CParagraph::TextAlignmentType_ByRightEdge) + { + currP->m_bIsTextFrameProperties = true; + }*/ + pParagraph = new CParagraph(*currP); + } + + if (pParagraph) + { + if (corrBeforeSpacing > 0) + { + pParagraph->m_dSpaceBefore += corrBeforeSpacing; + } + m_arParagraphsBlocks.push_back(pParagraph); + } + } + + //коррекция всей страницы + for (std::vector::iterator iter = m_arParagraphsBlocks.begin(); + iter != m_arParagraphsBlocks.end(); ++iter) + { + if ((*iter)->m_eTextAlignmentType == CParagraph::TextAlignmentType_ByWidth) + { + (*iter)->m_dRight = corrRight; + (*iter)->m_dHeight = corrHeight; + } + } + + ClearParagraphs(); + } + + void CPage::Merge(double dAffinity) + { + size_t nCount = m_arTextLine.size(); + if (1 < nCount) + { + CTextLine* pPrev = m_arTextLine[0]; + for (size_t i = 1; i < nCount; ++i) + { + CTextLine* pNext = m_arTextLine[i]; + + if (fabs(pNext->m_dBaselinePos - pPrev->m_dBaselinePos) < dAffinity) + { + pPrev->Merge(pNext); + + pNext->m_arConts.clear(); + RELEASEOBJECT(pNext); + + m_arTextLine.erase(m_arTextLine.begin() + i); + --i; + --nCount; + continue; + } + pPrev = pNext; + } + } + } + + void CPage::Write(NSStringUtils::CStringBuilder& oWriter) + { + // drawings + size_t nCountDrawings = m_arGraphicItems.size(); + if (0 != nCountDrawings) + { + oWriter.WriteString(L""); + + for (size_t i = 0; i < nCountDrawings; ++i) + { + m_arGraphicItems[i]->ToXml(oWriter); + } + + oWriter.WriteString(L""); + } + + size_t nCountParagraphs = m_eTextAssociationType != TextAssociationTypePlainParagraph ? + m_arParagraphs.size(): m_arParagraphsBlocks.size(); + for (size_t i = 0; i < nCountParagraphs; ++i) + { + m_eTextAssociationType != TextAssociationTypePlainParagraph ? + m_arParagraphs[i]->ToXml(oWriter): + m_arParagraphsBlocks[i]->ToXml(oWriter); + } + } + + void CPage::WriteSectionToFile(bool bLastPage, NSStringUtils::CStringBuilder& oWriter) + { + // section + int lWidthDx = (int)(m_dWidth * c_dMMToDx); + int lHeightDx = (int)(m_dHeight * c_dMMToDx); + + if (!bLastPage) + oWriter.WriteString(L""); + else + oWriter.WriteString(L""); + + oWriter.WriteString(L"= lHeightDx) ? oWriter.WriteString(L"landscape") : oWriter.WriteString(L"portrait"); + oWriter.WriteString(L"\"/>"); + + if (!bLastPage) + oWriter.WriteString(L""); + else + oWriter.WriteString(L""); + } +} diff --git a/DocxRenderer/src/logic/Page.h b/DocxRenderer/src/logic/Page.h index 232bc40d5e..d8abb54a36 100644 --- a/DocxRenderer/src/logic/Page.h +++ b/DocxRenderer/src/logic/Page.h @@ -5,8 +5,13 @@ namespace NSDocxRenderer { - const double STANDART_STRING_HEIGHT_MM = 4.2333333333333334; - const double THE_SAME_STRING_Y_PRECISION_MM = 0.01; + const double STANDART_STRING_HEIGHT_MM = 4.2333333333333334; + const double THE_SAME_STRING_Y_PRECISION_MM = 0.01; + const double THE_STRING_X_PRECISION_MM = 0.1; + + const double STANDART_LEFT_INDENT_MM = 30; + const double STANDART_RIGHT_INDENT_MM = 15; + const double STANDART_FIRSTLINE_INDENT_MM = 12.5; inline bool IsSpaceUtf32(const uint32_t& c) { @@ -20,37 +25,37 @@ namespace NSDocxRenderer } inline bool IsUnicodeSymbol( int symbol ) - { - bool result = false; + { + bool result = false; - if ( ( 0x0009 == symbol ) || ( 0x000A == symbol ) || ( 0x000D == symbol ) || - ( ( 0x0020 <= symbol ) && ( 0xD7FF >= symbol ) ) || ( ( 0xE000 <= symbol ) && ( symbol <= 0xFFFD ) ) || - ( ( 0x10000 <= symbol ) && symbol ) ) - { - result = true; - } + if ( ( 0x0009 == symbol ) || ( 0x000A == symbol ) || ( 0x000D == symbol ) || + ( ( 0x0020 <= symbol ) && ( 0xD7FF >= symbol ) ) || ( ( 0xE000 <= symbol ) && ( symbol <= 0xFFFD ) ) || + ( ( 0x10000 <= symbol ) && symbol ) ) + { + result = true; + } - return result; - } + return result; + } - class CPage - { - public: - NSStructures::CFont* m_pFont; - NSStructures::CPen* m_pPen; - NSStructures::CBrush* m_pBrush; - NSStructures::CShadow* m_pShadow; - NSStructures::CEdgeText* m_pEdgeText; + class CPage + { + public: + NSStructures::CFont* m_pFont; + NSStructures::CPen* m_pPen; + NSStructures::CBrush* m_pBrush; + NSStructures::CShadow* m_pShadow; + NSStructures::CEdgeText* m_pEdgeText; Aggplus::CMatrix* m_pTransform; Aggplus::CGraphicsPathSimpleConverter* m_pSimpleGraphicsConverter; - CVectorGraphics m_oVector; + CVectorGraphics m_oVector; - double m_dWidth; - double m_dHeight; + double m_dWidth; + double m_dHeight; - LONG m_lCurrentCommand; + LONG m_lCurrentCommand; std::vector m_arGraphicItems; std::vector m_arParagraphs; @@ -58,811 +63,65 @@ namespace NSDocxRenderer std::vector m_arParagraphsBlocks; std::vector m_arTextLine; - CTextLine* m_pCurrentLine; + CTextLine* m_pCurrentLine; - CFontManager m_oManager; - CFontManagerLight m_oManagerLight; + CFontManager m_oManager; + CFontManagerLight m_oManagerLight; - TextAssociationType m_eTextAssociationType; + TextAssociationType m_eTextAssociationType; NSStringUtils::CStringBuilder m_oWriterVML; - bool m_bIsDeleteTextClipPage; + bool m_bIsDeleteTextClipPage; double m_dLastTextX; double m_dLastTextY; double m_dLastTextX_block; - public: - CPage(NSFonts::IApplicationFonts* pFonts) : m_oManager(pFonts), m_oManagerLight(pFonts) - { - m_pFont = NULL; - m_pBrush = NULL; - m_pPen = NULL; - m_pShadow = NULL; - m_pEdgeText = NULL; - - m_pTransform = NULL; - m_pSimpleGraphicsConverter = NULL; - - m_dWidth = 0; - m_dHeight = 0; - - m_pCurrentLine = NULL; - m_eTextAssociationType = TextAssociationTypePlainLine; - - m_bIsDeleteTextClipPage = true; - - m_dLastTextX = -1; - m_dLastTextY = -1; - m_dLastTextX_block = m_dLastTextX; - } - - public: + public: + CPage(NSFonts::IApplicationFonts* pFonts); + ~CPage(); void Init(NSStructures::CFont* pFont, NSStructures::CPen* pPen, NSStructures::CBrush* pBrush, - NSStructures::CShadow* pShadow, NSStructures::CEdgeText* pEdge, Aggplus::CMatrix* pMatrix, Aggplus::CGraphicsPathSimpleConverter* pSimple) - { - m_pFont = pFont; - m_pPen = pPen; - m_pBrush = pBrush; - m_pShadow = pShadow; - m_pEdgeText = pEdge; + NSStructures::CShadow* pShadow, NSStructures::CEdgeText* pEdge, Aggplus::CMatrix* pMatrix, Aggplus::CGraphicsPathSimpleConverter* pSimple); - m_pTransform = pMatrix; - m_pSimpleGraphicsConverter = pSimple; + void Clear(); + void ClearTextLines(); + void ClearGraphicItems(); + void ClearParagraphs(); + void ClearParagraphsBlocks(); - m_oManager.m_pFont = m_pFont; - m_oManager.m_pTransform = m_pTransform; + void SetCurrentLineByBaseline(const double& dBaseLinePos); + void DeleteTextClipPage(); - m_pCurrentLine = NULL; + // image commands + void WriteImage(CImageInfo& oInfo, double& fX, double& fY, double& fWidth, double& fHeight); - m_oWriterVML.AddSize(1000); + // path commands + void MoveTo(double& dX, double& dY); + void LineTo(double& dX, double& dY); + void CurveTo(double& x1, double& y1, double& x2, double& y2, double& x3, double& y3); + void Start(); + void End(); + void Close(); + void DrawPath(LONG lType, LONG lTxId); - m_dLastTextX = -1; - m_dLastTextY = -1; - m_dLastTextX_block = m_dLastTextX; - } + void WriteText(unsigned int* pUnicodes, unsigned int* pGids, unsigned int nCount, + double fX, double fY, double fWidth, double fHeight, + double fBaseLineOffset, bool bIsPDFAnalyzer); - void Clear() - { - size_t nCount = 0; + void Build(); + void BuildByTypeBlockChar(); + void BuildByTypeBlockLine(); + void BuildByTypePlainLine(); + void BuildByTypePlainParagraph(); - nCount = m_arTextLine.size(); - for (size_t i = 0; i < nCount; ++i) - { - CTextLine* pTemp = m_arTextLine[i]; - RELEASEOBJECT(pTemp); - } - m_arTextLine.clear(); + void CalculateTextAlignmentType(CParagraph& a_rParagraph); - nCount = m_arGraphicItems.size(); - for (size_t i = 0; i < nCount; ++i) - { - CBaseItem* pTemp = m_arGraphicItems[i]; - RELEASEOBJECT(pTemp); - } - m_arGraphicItems.clear(); + //Объединяем строки, которые находятся на расстроянии не большем dAffinity + void Merge(double dAffinity); - nCount = m_arParagraphs.size(); - for (size_t i = 0; i < nCount; ++i) - { - CParagraph* pTemp = m_arParagraphs[i]; - RELEASEOBJECT(pTemp); - } - m_arParagraphs.clear(); + void Write(NSStringUtils::CStringBuilder& oWriter); - m_pCurrentLine = NULL; - - m_oWriterVML.ClearNoAttack(); - - m_dLastTextX = -1; - m_dLastTextY = -1; - m_dLastTextX_block = m_dLastTextX; - } - - ~CPage() - { - Clear(); - } - - void SetCurrentLineByBaseline(const double& dBaseLinePos) - { - if ((NULL == m_pCurrentLine) || (TextAssociationTypeBlockChar == m_eTextAssociationType)) - { - // пустая (в плане текста) страница - m_pCurrentLine = new CTextLine(); - - m_pCurrentLine->m_dBaselinePos = dBaseLinePos; - m_arTextLine.push_back(m_pCurrentLine); - return; - } - if (fabs(m_pCurrentLine->m_dBaselinePos - dBaseLinePos) <= THE_SAME_STRING_Y_PRECISION_MM) - { - return; - } - size_t nCount = m_arTextLine.size(); - for (size_t i = 0; i < nCount; ++i) - { - if (fabs(m_arTextLine[i]->m_dBaselinePos - dBaseLinePos) <= THE_SAME_STRING_Y_PRECISION_MM) - { - m_pCurrentLine = m_arTextLine[i]; - return; - } - } - - // линия не нашлась - не беда - создадим новую - m_pCurrentLine = new CTextLine(); - m_pCurrentLine->m_dBaselinePos = dBaseLinePos; - m_arTextLine.push_back(m_pCurrentLine); - return; - } - - // image commands - void WriteImage(CImageInfo& oInfo, double& fX, double& fY, double& fWidth, double& fHeight) - { - CImage* pImage = new CImage(oInfo, L""); - - double dRotation = m_pTransform->z_Rotation(); - - if (fabs(dRotation) < 5.0) - { - double x1 = fX; - double y1 = fY; - double x2 = fX + fWidth; - double y2 = fY + fHeight; - - m_pTransform->TransformPoint(x1, y1); - m_pTransform->TransformPoint(x2, y2); - - if (x1 <= x2) - { - pImage->m_dLeft = x1; - pImage->m_dWidth = x2 - x1; - } - else - { - pImage->m_dLeft = x2; - pImage->m_dWidth = x1 - x2; - } - - if (y1 <= y2) - { - pImage->m_dTop = y1; - pImage->m_dHeight = y2 - y1; - } - else - { - pImage->m_dTop = y2; - pImage->m_dHeight = y1 - y2; - } - - pImage->m_dRotate = 0.0; - } - else - { - double x1 = fX; - double y1 = fY; - double x2 = fX + fWidth; - double y2 = fY + fHeight; - - Aggplus::CMatrix oTemp = *m_pTransform; - - double dCx = (x1 + x2) / 2; - double dCy = (y1 + y2) / 2; - m_pTransform->TransformPoint(dCx, dCy); - oTemp.RotateAt(-dRotation, dCx, dCy, Aggplus::MatrixOrderAppend); - - oTemp.TransformPoint(x1, y1); - oTemp.TransformPoint(x2, y2); - - if (x1 <= x2) - { - pImage->m_dLeft = x1; - pImage->m_dWidth = x2 - x1; - } - else - { - pImage->m_dLeft = x2; - pImage->m_dWidth = x1 - x2; - } - - if (y1 <= y2) - { - pImage->m_dTop = y1; - pImage->m_dHeight = y2 - y1; - } - else - { - pImage->m_dTop = y2; - pImage->m_dHeight = y1 - y2; - } - - pImage->m_dRotate = dRotation; - } - - m_arGraphicItems.push_back(pImage); - } - - // path commands - void MoveTo(double& dX, double& dY) - { - m_pTransform->TransformPoint(dX, dY); - m_oVector.MoveTo(dX, dY); - - } - void LineTo(double& dX, double& dY) - { - m_pTransform->TransformPoint(dX, dY); - m_oVector.LineTo(dX, dY); - } - void CurveTo(double& x1, double& y1, double& x2, double& y2, double& x3, double& y3) - { - m_pTransform->TransformPoint(x1, y1); - m_pTransform->TransformPoint(x2, y2); - m_pTransform->TransformPoint(x3, y3); - - m_oVector.CurveTo(x1, y1, x2, y2, x3, y3); - } - void Start() - { - } - void End() - { - m_oVector.End(); - m_oWriterVML.ClearNoAttack(); - } - void Close() - { - m_oVector.Close(); - } - void DrawPath(LONG lType, LONG lTxId) - { - if ((m_oVector.m_dLeft <= m_oVector.m_dRight) && (m_oVector.m_dTop <= m_oVector.m_dBottom)) - { - CShape* pShape = new CShape(); - - pShape->m_lTxId = lTxId; - - pShape->m_oPen = *m_pPen; - pShape->m_oBrush = *m_pBrush; - - // нормализуем толщину линии - double dScaleTransform = (m_pTransform->sx() + m_pTransform->sy()) / 2.0; - pShape->m_oPen.Size *= dScaleTransform; - - if ((lType & 0x01) == 0x00) - { - if ((fabs(m_oVector.m_dLeft - m_oVector.m_dRight) < 0.3) || (fabs(m_oVector.m_dTop - m_oVector.m_dBottom) < 0.3)) - { - lType = 0x01; - pShape->m_oPen.Color = m_pBrush->Color1; - pShape->m_oPen.Alpha = m_pBrush->Alpha1; - //pShape->m_oPen.Size = max(pShape->m_oPen.Size, 1); - } - } - - pShape->CreateFromVectorData(&m_oVector, m_oWriterVML, 100000, lType); - m_arGraphicItems.push_back(pShape); - } - } - - void WriteText(unsigned int* pUnicodes, unsigned int* pGids, unsigned int nCount, double fX, double fY, double fWidth, double fHeight, double fBaseLineOffset, bool bIsPDFAnalyzer) - { - double dTextX = fX; - double dTextY = fY; - double dTextR = fX + fWidth; - double dTextB = fY + fHeight; - - m_pTransform->TransformPoint(dTextX, dTextY); - m_pTransform->TransformPoint(dTextR, dTextB); - - double dTextW = dTextR - dTextX; - double dTextH = dTextB - dTextY; - - NSStringUtils::CStringUTF32 oText((uint32_t*)pUnicodes, nCount); - - if ((pUnicodes != NULL) && (pGids != NULL)) - { - for (unsigned int i = 0; i < nCount; ++i) - { - if ( !IsUnicodeSymbol( pUnicodes[i] ) ) - { - oText[i] = ' '; - } - } - } - - bool bIsPath = ((NULL == pGids) && !bIsPDFAnalyzer) ? false : true; - - m_oManager.LoadFont(0, !bIsPath); - - if (bIsPath) - m_oManager.GenerateFontName2(oText); - - if (fabs(dTextW) < 0.01 || (dTextW > 10)) - { - double _x = 0; - double _y = 0; - double _w = 0; - double _h = 0; - - if (NULL != pGids) - { - m_oManager.SetStringGid(1); - m_oManager.MeasureStringGids(pGids, nCount, dTextX, dTextY, _x, _y, _w, _h, CFontManager::MeasureTypePosition); - } - else - { - // такого быть не должно (только из xps) - m_oManager.SetStringGid(0); - m_oManager.MeasureStringGids(pUnicodes, nCount, dTextX, dTextY, _x, _y, _w, _h, CFontManager::MeasureTypePosition); - } - - dTextW = _w; - //dTextW *= c_dPixToMM; - } - - double dBaseLinePos = dTextY + fBaseLineOffset; - dTextH = m_oManager.GetFontHeight(); - - SetCurrentLineByBaseline(dBaseLinePos); - - CContText* pLastCont = NULL; - size_t nCountConts = m_pCurrentLine->m_arConts.size(); - if (nCountConts != 0) - pLastCont = m_pCurrentLine->m_arConts[nCountConts - 1]; - - if (NULL == pLastCont) - { - // первое слово в линии - CContText* pCont = new CContText(); - - pCont->m_dX = dTextX; - pCont->m_dLastX = dTextX; - pCont->m_dY = dBaseLinePos; - - pCont->m_dWidth = dTextW; - pCont->m_dHeight = dTextH; - - if (IsSpaceUtf32(oText)) - { - pCont->m_dWidthWithoutSpaces = 0; - pCont->m_dLeftWithoutSpaces = dTextX + dTextW; - } - else - { - pCont->m_dWidthWithoutSpaces = dTextW; - pCont->m_dLeftWithoutSpaces = dTextX; - } - - pCont->m_oText = oText; - - pCont->m_oFont = m_oManager.m_oFont.m_oFont; - pCont->m_oBrush = *m_pBrush; - - if (bIsPath) - { - pCont->m_strPickFontName = m_oManager.m_strCurrentPickFont; - pCont->m_lPickFontStyle = m_oManager.m_lCurrentPictFontStyle; - } - - pCont->m_dSpaceWidthMM = m_oManager.m_dSpaceWidthMM; - - m_pCurrentLine->AddCont(pCont, m_oManager.m_oFont.m_dBaselineOffset); - - m_dLastTextX = dTextX; - m_dLastTextY = dBaseLinePos; - m_dLastTextX_block = m_dLastTextX; - return; - } - - // продолжение линии - //if (m_lCurrentCommand == c_nTextType && pLastCont->m_oFont.IsEqual(&m_oManager.m_oFontOld) && pLastCont->m_oBrush.IsEqual(m_pBrush)) - //{ - // // быстрое отметание вс¤ких проверок - // pLastCont->m_strText += strText; - // pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); - // return; - //} - - double dRight = pLastCont->m_dX + pLastCont->m_dWidth; - - if (pLastCont->m_oFont.IsEqual(&m_oManager.m_oFont.m_oFont) && pLastCont->m_oBrush.IsEqual(m_pBrush)) - { - // настройки одинаковые. теперь смотрим, на расположение - if (fabs(dRight - dTextX) < 0.5) - { - // продолжаем слово - pLastCont->m_oText += oText; - pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); - - if (!IsSpaceUtf32(oText)) - { - if (0 == pLastCont->m_dWidthWithoutSpaces) - pLastCont->m_dLeftWithoutSpaces = dTextX; - - pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; - } - else if (0 == pLastCont->m_dWidthWithoutSpaces) - { - pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; - } - - m_dLastTextX = dTextX; - m_dLastTextY = dBaseLinePos; - m_dLastTextX_block = m_dLastTextX; - pLastCont->m_dLastX = dTextX; - return; - } - else if ((dRight < dTextX) && ((dTextX - dRight) < m_oManager.m_dSpaceWidthMM)) - { - // продолжаем слово с пробелом - pLastCont->m_oText += uint32_t(' '); - pLastCont->m_oText += oText; - pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); - - if (!IsSpaceUtf32(oText)) - { - if (0 == pLastCont->m_dWidthWithoutSpaces) - pLastCont->m_dLeftWithoutSpaces = dTextX; - - pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; - } - else if (0 == pLastCont->m_dWidthWithoutSpaces) - { - pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; - } - - m_dLastTextX = dTextX; - m_dLastTextY = dBaseLinePos; - m_dLastTextX_block = m_dLastTextX; - pLastCont->m_dLastX = dTextX; - return; - } - else if (fabs(dBaseLinePos - pLastCont->m_dY) < 0.01 && - fabs(m_dLastTextY - pLastCont->m_dY) < 0.01 && - fabs(m_dLastTextX - pLastCont->m_dLastX) < 0.01) - { - // идет текст подряд, но с расстояниями что-то не так. смотрим - если новый текст идет после предыдущего, но - // просто левее чем предыдущий x + w - то считаем это нормальным. и дописываем слово. корректируя длину - if (dTextX < dRight && dTextX > pLastCont->m_dLastX) - { - // продолжаем слово - pLastCont->m_oText += oText; - double dNewW = (dTextX + dTextW - pLastCont->m_dX); - if (pLastCont->m_dWidth < dNewW) - pLastCont->m_dWidth = dNewW; - - if (!IsSpaceUtf32(oText)) - { - if (0 == pLastCont->m_dWidthWithoutSpaces) - pLastCont->m_dLeftWithoutSpaces = dTextX; - - pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; - } - else if (0 == pLastCont->m_dWidthWithoutSpaces) - { - pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; - } - - m_dLastTextX = dTextX; - m_dLastTextY = dBaseLinePos; - m_dLastTextX_block = m_dLastTextX; - pLastCont->m_dLastX = dTextX; - return; - - } - - // еще одна заглушка на большой пробел - добавляем пробел, потом в линии все разрулится через spacing - if (dTextX > dRight && (dTextX - dRight) < 5 && fabs(m_dLastTextX_block - m_dLastTextX) < 0.01) - { - // продолжаем слово с пробелом - pLastCont->m_oText += uint32_t(' '); - pLastCont->m_oText += oText; - pLastCont->m_dWidth = (dTextX + dTextW - pLastCont->m_dX); - - if (!IsSpaceUtf32(oText)) - { - if (0 == pLastCont->m_dWidthWithoutSpaces) - pLastCont->m_dLeftWithoutSpaces = dTextX; - - pLastCont->m_dWidthWithoutSpaces = dTextX + dTextW - pLastCont->m_dLeftWithoutSpaces; - } - else if (0 == pLastCont->m_dWidthWithoutSpaces) - { - pLastCont->m_dLeftWithoutSpaces = dTextX + dTextW; - } - - m_dLastTextX = dTextX; - m_dLastTextY = dBaseLinePos; - m_dLastTextX_block = m_dLastTextX; - pLastCont->m_dLastX = dTextX; - return; - } - } - } - - // либо пробел большой между словами, либо новый текст левее, либо настройки не те (шрифт, кисть) - // либо все вместе... просто добавл¤ем новое слово - CContText* pCont = new CContText(); - - pCont->m_dX = dTextX; - pCont->m_dY = dBaseLinePos; - pCont->m_dLastX = dTextX; - - pCont->m_dWidth = dTextW; - pCont->m_dHeight = dTextH; - - if (IsSpaceUtf32(oText)) - { - pCont->m_dWidthWithoutSpaces = 0; - pCont->m_dLeftWithoutSpaces = dTextX + dTextW; - } - else - { - pCont->m_dWidthWithoutSpaces = dTextW; - pCont->m_dLeftWithoutSpaces = dTextX; - } - - pCont->m_oText = oText; - - pCont->m_oFont = m_oManager.m_oFont.m_oFont; - pCont->m_oBrush = *m_pBrush; - - if (bIsPath) - { - pCont->m_strPickFontName = m_oManager.m_strCurrentPickFont; - pCont->m_lPickFontStyle = m_oManager.m_lCurrentPictFontStyle; - } - - pCont->m_dSpaceWidthMM = m_oManager.m_dSpaceWidthMM; - - m_pCurrentLine->AddCont(pCont, m_oManager.m_oFont.m_dBaselineOffset); - - m_dLastTextX = dTextX; - m_dLastTextY = dBaseLinePos; - m_dLastTextX_block = m_dLastTextX; - } - - void Build() - { - if (m_bIsDeleteTextClipPage) - { - // удалим все линии, которые выходят за границы страницы - size_t nCount = m_arTextLine.size(); - for (size_t i = 0; i < nCount; ++i) - { - CTextLine* pTextLine = m_arTextLine[i]; - - double _top = pTextLine->m_dBaselinePos - pTextLine->m_dHeight; - double _bottom = pTextLine->m_dBaselinePos; - - if (_top >= m_dHeight || _bottom <= 0) - { - m_arTextLine.erase(m_arTextLine.begin() + i); - --i; - --nCount; - } - } - } - - switch (m_eTextAssociationType) - { - case TextAssociationTypeBlockChar: - { - size_t nCount = m_arTextLine.size(); - for (size_t i = 0; i < nCount; ++i) - { - CTextLine* pTextLine = m_arTextLine[i]; - - CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); - pParagraph->m_pManagerLight = &m_oManagerLight; - pParagraph->m_bIsTextFrameProperties = true; - - pParagraph->m_dLeft = pTextLine->m_dX; - pParagraph->m_dTop = pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset; - - pParagraph->m_arLines.push_back(pTextLine); - - m_arParagraphs.push_back(pParagraph); - } - - // удалим все линии - m_arTextLine.clear(); - break; - } - case TextAssociationTypeBlockLine: - { - size_t nCount = m_arTextLine.size(); - - if (0 == nCount) - break; - - CTextLine* pFirstLine = m_arTextLine[0]; - - CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); - pParagraph->m_pManagerLight = &m_oManagerLight; - pParagraph->m_bIsTextFrameProperties = true; - - pParagraph->m_dLeft = pFirstLine->m_dX; - pParagraph->m_dTop = pFirstLine->m_dBaselinePos - pFirstLine->m_dHeight - pFirstLine->m_dBaselineOffset; - double dCurrentTop = pParagraph->m_dTop; - - pParagraph->m_arLines.push_back(pFirstLine); - - m_arParagraphs.push_back(pParagraph); - - for (size_t i = 1; i < nCount; ++i) - { - CTextLine* pTextLine = m_arTextLine[i]; - - CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); - pParagraph->m_pManagerLight = &m_oManagerLight; - pParagraph->m_bIsTextFrameProperties = true; - - if (((fabs(pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pFirstLine->m_dBaselinePos) > STANDART_STRING_HEIGHT_MM) && (pTextLine->m_dX == pFirstLine->m_dX)) || - ((pTextLine->m_dX != pFirstLine->m_dX) && (pTextLine->m_dBaselinePos != pFirstLine->m_dBaselinePos))) - { - pParagraph->m_dLeft = pTextLine->m_dX; - pParagraph->m_dTop = pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset; - dCurrentTop = pParagraph->m_dTop; - } - else - { - pParagraph->m_dLeft = pFirstLine->m_dX; - pParagraph->m_dTop = dCurrentTop; - } - - pFirstLine = pTextLine; - - pParagraph->m_arLines.push_back(pTextLine); - m_arParagraphs.push_back(pParagraph); - } - - // удалим все линии - m_arTextLine.clear(); - break; - } - case TextAssociationTypePlainLine: - { - SortElements(m_arTextLine); - - if (true) // merge line - { - for (std::vector::iterator iter = m_arTextLine.begin(); iter != m_arTextLine.end(); ++iter) - { - (*iter)->Analyze(); - } - } - - Merge(STANDART_STRING_HEIGHT_MM / 3); - - double previousStringOffset = 0; - size_t nCount = m_arTextLine.size(); - for (size_t i = 0; i < nCount; ++i) - { - CTextLine* pTextLine = m_arTextLine[i]; - - CParagraph* pParagraph = new CParagraph(m_eTextAssociationType); - pParagraph->m_pManagerLight = &m_oManagerLight; - pParagraph->m_bIsTextFrameProperties = false; - -#if 0 - // у рамок нельзя выключить обтекание. поэтому в этом случае нужно конверировать в шейп - if (pTextLine->IsForceBlock()) - { - pParagraph->m_bIsTextFrameProperties = true; - pParagraph->m_dLeft = pTextLine->m_dX; - pParagraph->m_dTop = pTextLine->m_dBaselinePos - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset; - - pParagraph->m_arLines.push_back(pTextLine); - m_arParagraphs.push_back(pParagraph); - continue; - } -#endif - - pParagraph->m_dLeft = pTextLine->m_dX; - - double dBeforeSpacing = (pTextLine->m_dBaselinePos - previousStringOffset - pTextLine->m_dHeight - pTextLine->m_dBaselineOffset); - - pParagraph->m_dSpaceBefore = std::max(dBeforeSpacing, 0.0); - - double dHeight = 1; - if (pTextLine->m_dHeight != 0) - { - dHeight = pTextLine->m_dHeight; - - if (dBeforeSpacing < 0) - dHeight += dBeforeSpacing; - } - - pParagraph->m_dHeight = dHeight; - - previousStringOffset = pTextLine->m_dBaselinePos - pTextLine->m_dBaselineOffset; - - pParagraph->m_arLines.push_back(pTextLine); - m_arParagraphs.push_back(pParagraph); - } - - m_arTextLine.clear(); - break; - } - } - } - - void Merge(double dAffinity) - { - size_t nCount = m_arTextLine.size(); - if (1 < nCount) - { - CTextLine* pPrev = m_arTextLine[0]; - for (size_t i = 1; i < nCount; ++i) - { - CTextLine* pNext = m_arTextLine[i]; - - if (fabs(pNext->m_dBaselinePos - pPrev->m_dBaselinePos) < dAffinity) - { - pPrev->Merge(pNext); - - pNext->m_arConts.clear(); - RELEASEOBJECT(pNext); - - m_arTextLine.erase(m_arTextLine.begin() + i); - --i; - --nCount; - continue; - } - pPrev = pNext; - } - } - } - - void Write(NSStringUtils::CStringBuilder& oWriter) - { - // drawings - size_t nCountDrawings = m_arGraphicItems.size(); - if (0 != nCountDrawings) - { - oWriter.WriteString(L""); - - for (size_t i = 0; i < nCountDrawings; ++i) - { - m_arGraphicItems[i]->ToXml(oWriter); - } - - oWriter.WriteString(L""); - } - - size_t nCountParagraphs = m_arParagraphs.size(); - for (size_t i = 0; i < nCountParagraphs; ++i) - { - m_arParagraphs[i]->ToXml(oWriter); - } - } - - void WriteSectionToFile(bool bLastPage, NSStringUtils::CStringBuilder& oWriter) - { - // section - int lWidthDx = (int)(m_dWidth * c_dMMToDx); - int lHeightDx = (int)(m_dHeight * c_dMMToDx); - - if (!bLastPage) - oWriter.WriteString(L""); - else - oWriter.WriteString(L""); - - oWriter.WriteString(L"= lHeightDx) ? oWriter.WriteString(L"landscape") : oWriter.WriteString(L"portrait"); - oWriter.WriteString(L"\"/>"); - - if (!bLastPage) - oWriter.WriteString(L""); - else - oWriter.WriteString(L""); - } - }; + void WriteSectionToFile(bool bLastPage, NSStringUtils::CStringBuilder& oWriter); + }; }