Files
core/DesktopEditor/raster/Metafile/Common/MetaFileRenderer.h
2025-02-11 11:24:07 +03:00

1369 lines
41 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#ifndef _METAFILE_COMMON_METAFILERENDERER_H
#define _METAFILE_COMMON_METAFILERENDERER_H
#include "../../../graphics/IRenderer.h"
#include "../../../graphics/structures.h"
#include "../../../graphics/Image.h"
#include "../../../raster/ImageFileFormatChecker.h"
#include "../../../raster/BgraFrame.h"
#include "../../../graphics/AggPlusEnums.h"
#include "IOutputDevice.h"
#include "MetaFile.h"
#include "MetaFileTypes.h"
#include "MetaFileObjects.h"
#include <cmath>
#ifndef M_PI
#define M_PI 3.1415926
#endif
#ifdef _DEBUG
#include <iostream>
#define LOGGING(_value) std::wcout << _value << std::endl;
#else
#define LOGGING(_value)
#endif
#define M_MINFONTSIZE 5
namespace MetaFile
{
struct TRenderConditional
{
IMetaFileBase* m_pFile;
int m_lDrawPathType;
double m_dX; // Координаты левого верхнего угла
double m_dY; //
double m_dW; //
double m_dH; //
double m_dScaleX; // Коэффициенты сжатия/растяжения, чтобы
double m_dScaleY; // результирующая картинка была нужных размеров.
bool m_bStartedPath;
};
class CMetaFileRenderer : public IOutputDevice
{
public:
CMetaFileRenderer(IMetaFileBase *pFile, IRenderer *pRenderer, double dX, double dY, double dWidth, double dHeight)
{
m_pFile = pFile;
m_dX = dX;
m_dY = dY;
m_dW = dWidth;
m_dH = dHeight;
m_pRenderer = NULL;
m_pSecondConditional = NULL;
if (!pRenderer)
return;
m_pRenderer = pRenderer;
UpdateScale();
m_bStartedPath = false;
m_bUpdatedClip = true;
m_pRenderer->CommandLong(c_nPenWidth0As1px, 1);
//int alpha = 0xff;
//m_pRenderer->put_BrushAlpha1(alpha);
//m_pRenderer->put_BrushType(c_BrushTypeSolid);
//m_pRenderer->put_BrushColor1(0xffffff);
//m_pRenderer->BeginCommand(c_nPathType);
//m_pRenderer->PathCommandStart();
//m_pRenderer->PathCommandMoveTo(pBounds->nLeft , pBounds->nTop);
//m_pRenderer->PathCommandLineTo(pBounds->nRight , pBounds->nTop);
//m_pRenderer->PathCommandLineTo(pBounds->nRight , pBounds->nBottom);
//m_pRenderer->PathCommandLineTo(pBounds->nLeft , pBounds->nBottom);
//m_pRenderer->PathCommandLineTo(pBounds->nLeft , pBounds->nTop);
//m_pRenderer->PathCommandClose();
//m_pRenderer->DrawPath(c_nWindingFillMode);
//m_pRenderer->EndCommand(c_nPathType);
//m_pRenderer->PathCommandEnd();
}
CMetaFileRenderer(IMetaFileBase *pFile, CMetaFileRenderer* pMetaFileRenderer)
{
m_pFile = pFile;
if (!pMetaFileRenderer)
return;
m_dX = pMetaFileRenderer->m_dX;
m_dY = pMetaFileRenderer->m_dY;
m_dW = pMetaFileRenderer->m_dW;
m_dH = pMetaFileRenderer->m_dH;
m_pRenderer = NULL;
m_pSecondConditional = NULL;
m_pRenderer = pMetaFileRenderer->m_pRenderer;
UpdateScale();
m_bStartedPath = false;
m_bUpdatedClip = false;
//int alpha = 0xff;
//m_pRenderer->put_BrushAlpha1(alpha);
//m_pRenderer->put_BrushType(c_BrushTypeSolid);
//m_pRenderer->put_BrushColor1(0xffffff);
//m_pRenderer->BeginCommand(c_nPathType);
//m_pRenderer->PathCommandStart();
//m_pRenderer->PathCommandMoveTo(pBounds->nLeft , pBounds->nTop);
//m_pRenderer->PathCommandLineTo(pBounds->nRight , pBounds->nTop);
//m_pRenderer->PathCommandLineTo(pBounds->nRight , pBounds->nBottom);
//m_pRenderer->PathCommandLineTo(pBounds->nLeft , pBounds->nBottom);
//m_pRenderer->PathCommandLineTo(pBounds->nLeft , pBounds->nTop);
//m_pRenderer->PathCommandClose();
//m_pRenderer->DrawPath(c_nWindingFillMode);
//m_pRenderer->EndCommand(c_nPathType);
//m_pRenderer->PathCommandEnd();
}
virtual ~CMetaFileRenderer()
{
RELEASEOBJECT(m_pSecondConditional)
}
void CreateConditional(IMetaFileBase* pFile)
{
RELEASEOBJECT(m_pSecondConditional);
m_pSecondConditional = new TRenderConditional();
SaveConditional(*m_pSecondConditional);
m_pSecondConditional->m_pFile = pFile;
}
void ChangeConditional()
{
if (NULL != m_pSecondConditional)
{
TRenderConditional oRenderConditional;
SaveConditional(oRenderConditional);
SetConditional(*m_pSecondConditional);
*m_pSecondConditional = oRenderConditional;
}
}
IMetaFileBase* GetFile() const
{
return m_pFile;
}
void UpdateScale()
{
if (NULL == m_pFile)
return;
const TRectL& oBounds{m_pFile->GetDCBounds()};
m_dScaleX = m_dW / std::fabs((double)(oBounds.Right - oBounds.Left));
m_dScaleY = m_dH / std::fabs((double)(oBounds.Bottom - oBounds.Top));
}
double GetHeight() const
{
return m_dH;
}
double GetWidth() const
{
return m_dW;
}
double GetScaleX() const
{
return m_dScaleX;
}
double GetScaleY() const
{
return m_dScaleY;
}
void Begin()
{
UpdateScale();
}
void End()
{
CheckEndPath();
}
void NeedUpdateClip()
{
m_bUpdatedClip = false;
}
void DrawBitmap(double dX, double dY, double dW, double dH, BYTE* pBuffer, unsigned int unWidth, unsigned int unHeight)
{
if (!pBuffer || 0 == unWidth || 0 == unHeight)
return;
CheckEndPath();
UpdateTransform();
UpdateClip();
Aggplus::CImage oImage;
oImage.Create(pBuffer, unWidth, unHeight, 4 * unWidth, true);
TPointD oTL = TranslatePoint(dX, dY);
TPointD oBR = TranslatePoint(dX + dW, dY + dH);
double dImageX = oTL.X;
double dImageY = oTL.Y;
double dImageW = oBR.X - oTL.X;
double dImageH = oBR.Y - oTL.Y;
if (dImageH < 0 || dImageW < 0)
{
double dM11, dM12, dM21, dM22, dMx, dMy;
m_pRenderer->GetTransform(&dM11, &dM12, &dM21, &dM22, &dMx, &dMy);
double dKx = 1, dKy = 1, dShiftKoefX = 0, dShiftKoefY = 0;
if (dImageW < 0)
{
dKx = -1;
dShiftKoefX = 2 * dImageX + dImageW;
dImageW = -dImageW;
dImageX -= dImageW;
}
if (dImageH < 0)
{
dKy = -1;
dShiftKoefY = 2 * dImageY + dImageH;
dImageH = -dImageH;
dImageY -= dImageH;
}
m_pRenderer->SetTransform(dKx * dM11, dKx * dM12, dKy * dM21, dKy * dM22, dShiftKoefX * dM11 + dShiftKoefY * dM21 + dMx, dShiftKoefX * dM12 + dShiftKoefY * dM22 + dMy);
}
m_pRenderer->DrawImage(&oImage, dImageX, dImageY, dImageW, dImageH);
}
void DrawDriverString(const std::wstring& wsString, const std::vector<TPointD>& arPoints)
{
const IFont *pFont = m_pFile->GetFont();
if (NULL == pFont)
return;
UpdateTransform();
UpdateClip();
double dFontScale = 1.;
double dLogicalFontHeight = std::fabs(pFont->GetHeight());
double dM11, dM12, dM21, dM22, dRx, dRy;
m_pRenderer->GetTransform(&dM11, &dM12, &dM21, &dM22, &dRx, &dRy);
if (dLogicalFontHeight < M_MINFONTSIZE)
{
dFontScale = dM22;
dLogicalFontHeight *= dFontScale;
dM11 /= std::fabs(dM11);
dM22 /= std::fabs(dM22);
m_pRenderer->SetTransform(dM11, dM12, dM21, dM22, dRx, dRy);
}
m_pRenderer->put_FontName(pFont->GetFaceName());
m_pRenderer->put_FontSize(fabs(dLogicalFontHeight * m_dScaleX / 25.4 * 72.) * dM22);
int lStyle = 0;
if (pFont->GetWeight() > 550)
lStyle |= 0x01;
if (pFont->IsItalic())
lStyle |= 0x02;
if (pFont->IsUnderline())
lStyle |= (1 << 2);
if (pFont->IsStrikeOut())
lStyle |= (1 << 7);
m_pRenderer->put_FontStyle(lStyle);
m_pRenderer->put_BrushType(c_BrushTypeSolid);
m_pRenderer->put_BrushColor1(m_pFile->GetTextColor());
m_pRenderer->put_BrushAlpha1(255);
m_pRenderer->GetTransform(&dM11, &dM12, &dM21, &dM22, &dRx, &dRy);
m_pRenderer->ResetTransform();
std::vector<TPointD> arGlyphPoint(arPoints.size());
for (unsigned int unIndex = 0; unIndex < arPoints.size(); ++unIndex)
{
arGlyphPoint[unIndex].X = (arPoints[unIndex].X * dM11) * m_dScaleX * dFontScale + dRx;
arGlyphPoint[unIndex].Y = (arPoints[unIndex].Y * dM22) * m_dScaleY * dFontScale + dRy;
}
for (unsigned int unIndex = 0; unIndex < std::min(arPoints.size(), wsString.length()); ++unIndex)
m_pRenderer->CommandDrawTextCHAR(wsString[unIndex], arGlyphPoint[unIndex].X, arGlyphPoint[unIndex].Y, 0, 0);
}
void DrawString(std::wstring& wsText, unsigned int unCharsCount, double _dX, double _dY, double* pDx, int iGraphicsMode, double dXScale, double dYScale)
{
CheckEndPath();
const IFont* pFont = m_pFile->GetFont();
if (!pFont)
return;
UpdateTransform(iGraphicsMode);
UpdateClip();
double dLogicalFontHeight = std::fabs(pFont->GetHeight());
double dM11, dM12, dM21, dM22, dRx, dRy;
double dFontScale = 1.;
if (dLogicalFontHeight < M_MINFONTSIZE)
{
m_pRenderer->GetTransform(&dM11, &dM12, &dM21, &dM22, &dRx, &dRy);
dFontScale = dM22;
dLogicalFontHeight *= dFontScale;
m_pRenderer->SetTransform(dM11 / std::fabs(dM11), dM12, dM21, dM22 / std::fabs(dM22), dRx, dRy);
}
double dFontHeight = fabs(dLogicalFontHeight * m_dScaleY / 25.4 * 72);
std::wstring wsFaceName = pFont->GetFaceName();
m_pRenderer->put_FontName(wsFaceName);
m_pRenderer->put_FontSize(dFontHeight);
int lStyle = 0;
if (pFont->GetWeight() > 550)
lStyle |= 0x01;
if (pFont->IsItalic())
lStyle |= 0x02;
if (pFont->IsUnderline())
lStyle |= (1 << 2);
if (pFont->IsStrikeOut())
lStyle |= (1 << 7);
m_pRenderer->put_FontStyle(lStyle);
double dTheta = ((((double)pFont->GetEscapement()) / 10) * M_PI / 180);
double dCosTheta = cosf(dTheta);
double dSinTheta = sinf(dTheta);
if (dYScale > 0)
dSinTheta = -dSinTheta;
double dFontCharSpace = m_pFile->GetCharSpace() * m_dScaleX * m_pFile->GetPixelWidth() * dFontScale;
m_pRenderer->put_FontCharSpace(dFontCharSpace);
float fL = 0, fT = 0, fW = 0, fH = 0;
float fUndX1 = 0, fUndY1 = 0, fUndX2 = 0, fUndY2 = 0, fUndSize = 1;
NSFonts::IFontManager* pFontManager = m_pFile->GetFontManager();
std::vector<std::wstring> arSplitString;
if (wsText.find(L"\n") != std::wstring::npos)
{
size_t unStart;
size_t unEnd = 0;
while ((unStart = wsText.find_first_not_of(L"\n", unEnd)) != std::wstring::npos)
{
unEnd = wsText.find(L"\n", unStart);
arSplitString.push_back(wsText.substr(unStart, unEnd - unStart));
}
}
else
arSplitString = {wsText};
double dSkipY = 0;
for (const std::wstring& wsString : arSplitString)
{
if (NULL == pFontManager)
{
if (NULL != pDx && wsString.length())
{
// Тогда мы складываем все pDx кроме последнего символа, последний считаем отдельно
double dTempTextW = 0;
for (unsigned int unCharIndex = 0; unCharIndex < wsString.length() - 1; unCharIndex++)
{
dTempTextW += pDx[unCharIndex];
}
dTempTextW += dFontHeight * wsString.length();
fW = (float)dTempTextW;
}
else
{
fW = (float)(dFontHeight * wsString.length());
}
fH = dFontHeight * 1.2;
}
else
{
double dRendererDpiX, dRendererDpiY;
m_pRenderer->get_DpiX(&dRendererDpiX);
m_pRenderer->get_DpiY(&dRendererDpiY);
pFontManager->LoadFontByName(wsFaceName, dFontHeight, lStyle, dRendererDpiX, dRendererDpiY);
pFontManager->SetCharSpacing(dFontCharSpace * 72 / 25.4);
double dMmToPt = 25.4 / 72;
double dFHeight = dFontHeight;
double dFDescent = dFontHeight;
NSFonts::IFontFile* pFontFile = pFontManager->GetFile();
if (pFontFile)
{
dFHeight *= pFontFile->GetHeight() / pFontFile->Units_Per_Em() * dMmToPt;
dFDescent *= pFontFile->GetDescender() / pFontFile->Units_Per_Em() * dMmToPt;
}
double dFAscent = dFHeight - std::abs(dFDescent);
if (NULL != pDx && unCharsCount > 1)
{
// Тогда мы складываем все pDx кроме последнего символа, последний считаем отдельно
double dTempTextW = 0;
for (unsigned int unCharIndex = 0; unCharIndex < unCharsCount - 1; unCharIndex++)
{
dTempTextW += pDx[unCharIndex];
}
dTempTextW *= m_dScaleX;
std::wstring wsTempText;
wsTempText += wsString.at(wsString.length() - 1);
//wsTempText += wsText.at(unCharsCount - 1);
pFontManager->LoadString1(wsTempText, 0, 0);
TBBox oBox = pFontManager->MeasureString2();
dTempTextW += dMmToPt * (oBox.fMaxX - oBox.fMinX);
fL = 0;
fW = (float)dTempTextW;
}
else
{
pFontManager->LoadString1(wsString, 0, 0);
TBBox oBox = pFontManager->MeasureString2();
fL = (float)dMmToPt * (oBox.fMinX);
fW = (float)dMmToPt * (oBox.fMaxX - oBox.fMinX);
}
// Просчитаем положение подчеркивания
pFontManager->GetUnderline(&fUndX1, &fUndY1, &fUndX2, &fUndY2, &fUndSize);
fUndY1 *= (float)dMmToPt;
fUndY2 *= (float)dMmToPt;
fUndSize *= (float)dMmToPt / 2;
fUndX1 = fL;
fUndX2 = fL + fW;
fT = (float)-dFAscent;
fH = (float)dFHeight;
}
TPointD oTextPoint = TranslatePoint(_dX * dFontScale, _dY * dFontScale);
double dX = oTextPoint.X;
double dY = oTextPoint.Y + dSkipY;
dSkipY += dLogicalFontHeight * m_dScaleY * 1.5;
// Найдем начальную точку текста
unsigned int ulTextAlign = m_pFile->GetTextAlign() & TA_MASK;
unsigned int ulVTextAlign = m_pFile->GetTextAlign() >> 8;
if (ulTextAlign & TA_UPDATECP)
{
ulTextAlign -= TA_UPDATECP;
}
if (ulTextAlign & TA_BASELINE)
{
ulTextAlign -= TA_BASELINE;
// Ничего не делаем
}
else if (ulTextAlign & TA_BOTTOM || ulVTextAlign == VTA_BOTTOM)
{
float fTemp = -(fH + fT / 2);
dX += -fTemp * dSinTheta;
dY += fTemp * dCosTheta;
if (ulVTextAlign != VTA_BOTTOM)
ulTextAlign -= TA_BOTTOM;
}
else if (ulVTextAlign == VTA_CENTER)
{
float fTemp = (fH + fT / 2) / 2;
dX += -fTemp * dSinTheta;
dY += fTemp * dCosTheta;
}
else // if (ulTextAlign & TA_TOP)
{
float fTemp = -fT;
dX += -fTemp * dSinTheta;
dY += fTemp * dCosTheta;
}
if (ulTextAlign == TA_RIGHT)
{
dX += -fW * dCosTheta;
dY += -fW * dSinTheta;
}
else if (ulTextAlign == TA_CENTER)
{
dX += -fW / 2 * dCosTheta;
dY += -fW / 2 * dSinTheta;
}
else //if (ulTextAlign & TA_LEFT)
{
// Ничего не делаем
}
if (pFont->IsUnderline())
{
fUndX1 += (float)dX;
fUndX2 += (float)dX;
fUndY1 += (float)dY;
fUndY2 += (float)dY;
}
bool bChangeCTM = false;
if (iGraphicsMode == GM_COMPATIBLE)
{
double dShiftX = 0;
double dShiftY = 0;
m_pRenderer->GetTransform(&dM11, &dM12, &dM21, &dM22, &dRx, &dRy);
if (dXScale < -0.00001)
{
dX += fabs(fW);
if (m_pFile->IsWindowFlippedX())
{
dShiftX = (2 * dX - fabs(fW)) * dM11;
}
else
{
dShiftX = (2 * dX + fabs(fW)) * dM11;
}
dM11 = fabs(dM11);
}
if (dYScale < -0.00001)
{
dY += fabs(fH);
dShiftY = (2 * dY - fabs(fH)) * dM22;
dM22 = fabs(dM22);
}
m_pRenderer->ResetTransform();
m_pRenderer->SetTransform(dM11, dM12, dM21, dM22, dShiftX + dRx, dShiftY + dRy);
bChangeCTM = true;
}
if (0 != pFont->GetEscapement())
{
// TODO: тут реализован только параметр shEscapement, еще нужно реализовать параметр Orientation
m_pRenderer->GetTransform(&dM11, &dM12, &dM21, &dM22, &dRx, &dRy);
double dOldX = dX;
dX = dX * dCosTheta + dY * dSinTheta;
dY = dY * dCosTheta - dOldX * dSinTheta;
m_pRenderer->ResetTransform();
m_pRenderer->SetTransform(dCosTheta * dM11, dSinTheta * dM22,
-dSinTheta * dM11, dCosTheta * dM22,
dRx, dRy);
bChangeCTM = true;
}
// Для начала нарисуем фон текста
if (OPAQUE == m_pFile->GetTextBgMode())
{
m_pRenderer->put_BrushType(c_BrushTypeSolid);
m_pRenderer->put_BrushAlpha1(255);
m_pRenderer->put_BrushColor1(m_pFile->GetTextBgColor());
m_pRenderer->BeginCommand(c_nPathType);
m_pRenderer->PathCommandStart();
m_pRenderer->PathCommandMoveTo(dX + fL, dY + fT);
m_pRenderer->PathCommandLineTo(dX + fL + fW, dY + fT);
m_pRenderer->PathCommandLineTo(dX + fL + fW, dY + fT + fH);
m_pRenderer->PathCommandLineTo(dX + fL, dY + fT + fH);
m_pRenderer->DrawPath(c_nWindingFillMode);
m_pRenderer->EndCommand(c_nPathType);
m_pRenderer->PathCommandEnd();
}
// Нарисуем подчеркивание
if (pFont->IsUnderline())
{
m_pRenderer->put_PenSize((double)fUndSize);
m_pRenderer->put_PenLineEndCap(0);
m_pRenderer->put_PenLineStartCap(0);
m_pRenderer->BeginCommand(c_nPathType);
m_pRenderer->PathCommandStart();
m_pRenderer->PathCommandMoveTo(fUndX1, fUndY1);
m_pRenderer->PathCommandLineTo(fUndX2, fUndY2);
m_pRenderer->DrawPath(c_nStroke);
m_pRenderer->EndCommand(c_nPathType);
m_pRenderer->PathCommandEnd();
}
// Установим цвет текста
m_pRenderer->put_BrushType(c_BrushTypeSolid);
m_pRenderer->put_BrushColor1(m_pFile->GetTextColor());
m_pRenderer->put_BrushAlpha1(255);
// Рисуем сам текст
if (NULL == pDx)
{
m_pRenderer->CommandDrawText(wsString, dX, dY, 0, 0);
}
else
{
unsigned int unUnicodeLen = 0;
unsigned int* pUnicode = NSStringExt::CConverter::GetUtf32FromUnicode(wsString, unUnicodeLen);
if (pUnicode && unUnicodeLen)
{
double dOffset = 0;
double dKoefX = m_dScaleX * dFontScale;
for (unsigned int unCharIndex = 0; unCharIndex < unUnicodeLen; unCharIndex++)
{
m_pRenderer->CommandDrawTextCHAR(pUnicode[unCharIndex], dX + dOffset, dY, 0, 0);
dOffset += (pDx[unCharIndex] * dKoefX);
}
delete[] pUnicode;
}
}
if (bChangeCTM)
m_pRenderer->ResetTransform();
}
}
void StartPath()
{
CheckEndPath();
UpdateTransform();
UpdateClip();
m_lDrawPathType = -1;
if (true == UpdateBrush())
{
unsigned int unFillMode = m_pFile->GetFillMode();
if (ALTERNATE == unFillMode)
m_lDrawPathType = c_nEvenOddFillMode;
else// if (WINDING == unFillMode)
m_lDrawPathType = c_nWindingFillMode;
}
if (true == UpdatePen())
{
if (-1 == m_lDrawPathType)
m_lDrawPathType = c_nStroke;
else
m_lDrawPathType |= c_nStroke;
}
m_pRenderer->BeginCommand(c_nPathType);
m_pRenderer->PathCommandStart();
m_bStartedPath = true;
}
void MoveTo(double dX, double dY)
{
CheckStartPath(true);
TPointD oPoint = TranslatePoint(dX, dY);
m_pRenderer->PathCommandMoveTo(oPoint.X, oPoint.Y);
}
void LineTo(double dX, double dY)
{
CheckStartPath(false);
TPointD oPoint = TranslatePoint(dX, dY);
m_pRenderer->PathCommandLineTo(oPoint.X, oPoint.Y);
}
void CurveTo(double dX1, double dY1, double dX2, double dY2, double dXe, double dYe)
{
CheckStartPath(false);
TPointD oPoint1 = TranslatePoint(dX1, dY1);
TPointD oPoint2 = TranslatePoint(dX2, dY2);
TPointD oPointE = TranslatePoint(dXe, dYe);
m_pRenderer->PathCommandCurveTo(oPoint1.X, oPoint1.Y, oPoint2.X, oPoint2.Y, oPointE.X, oPointE.Y);
}
void ArcTo(double dLeft, double dTop, double dRight, double dBottom, double dStart, double dSweep)
{
CheckStartPath(false);
TPointD oTL = TranslatePoint(dLeft, dTop);
TPointD oBR = TranslatePoint(dRight, dBottom);
m_pRenderer->PathCommandArcTo(oTL.X, oTL.Y, oBR.X - oTL.X, oBR.Y - oTL.Y, dStart, dSweep);
}
void ClosePath()
{
CheckStartPath(false);
m_pRenderer->PathCommandClose();
}
void DrawPath(int lType = 0)
{
if (lType <= 0)
{
m_pRenderer->DrawPath(1);
}
else if (-1 != m_lDrawPathType)
{
bool bStroke = lType & 1 ? true : false;
bool bFill = lType & 2 ? true : false;
int nEndType = -1;
if (bStroke && (m_lDrawPathType & c_nStroke))
nEndType = c_nStroke;
if (bFill)
{
if (m_lDrawPathType & c_nWindingFillMode)
nEndType = (-1 == nEndType ? c_nWindingFillMode : nEndType | c_nWindingFillMode);
else if (m_lDrawPathType & c_nEvenOddFillMode)
nEndType = (-1 == nEndType ? c_nEvenOddFillMode : nEndType | c_nEvenOddFillMode);
}
if (-1 != nEndType)
m_pRenderer->DrawPath(nEndType);
}
}
void EndPath()
{
m_pRenderer->EndCommand(c_nPathType);
m_pRenderer->PathCommandEnd();
m_bStartedPath = false;
}
void UpdateDC()
{
CheckEndPath();
}
void ResetClip()
{
m_pRenderer->BeginCommand(c_nResetClipType);
m_pRenderer->EndCommand(c_nResetClipType);
}
void IntersectClip(const TRectD& oClip)
{
m_pRenderer->put_ClipMode(c_nClipRegionTypeWinding | c_nClipRegionIntersect);
m_pRenderer->BeginCommand(c_nClipType);
m_pRenderer->BeginCommand(c_nPathType);
m_pRenderer->PathCommandStart();
TPointD oTL = TranslatePoint(oClip.Left, oClip.Top);
TPointD oBR = TranslatePoint(oClip.Right, oClip.Bottom);
m_pRenderer->PathCommandMoveTo(oTL.X, oTL.Y);
m_pRenderer->PathCommandLineTo(oTL.X, oBR.Y);
m_pRenderer->PathCommandLineTo(oBR.X, oBR.Y);
m_pRenderer->PathCommandLineTo(oBR.X, oTL.Y);
m_pRenderer->PathCommandLineTo(oTL.X, oTL.Y);
m_pRenderer->EndCommand(c_nPathType);
m_pRenderer->EndCommand(c_nClipType);
m_pRenderer->PathCommandEnd();
}
void ExcludeClip(const TRectD& oClip, const TRectD& oBB)
{
StartClipPath(RGN_AND, ALTERNATE);
MoveTo(oClip.Left, oClip.Top);
LineTo(oClip.Right, oClip.Top);
LineTo(oClip.Right, oClip.Bottom);
LineTo(oClip.Left, oClip.Bottom);
ClosePath();
MoveTo(oBB.Left, oBB.Top);
LineTo(oBB.Right, oBB.Top);
LineTo(oBB.Right, oBB.Bottom);
LineTo(oBB.Left, oBB.Bottom);
ClosePath();
EndClipPath(RGN_AND);
}
void PathClip(const CPath& oPath, int nClipMode, TXForm *pTransform = NULL)
{
double dM11, dM12, dM21, dM22, dX, dY;
if (NULL != pTransform)
{
GetTransform(&dM11, &dM12, &dM21, &dM22, &dX, &dY);
SetTransform(pTransform->M11, pTransform->M12, pTransform->M21, pTransform->M22, pTransform->Dx, pTransform->Dy);
}
oPath.DrawOn(this, false, false, nClipMode);
if (NULL != pTransform)
SetTransform(dM11, dM12, dM21, dM22, dX, dY);
}
void StartClipPath(unsigned int unMode, int nFillMode = -1)
{
CheckEndPath();
m_bStartedPath = true;
unsigned int unClipMode = -1;
switch (unMode)
{
case RGN_AND: unClipMode = c_nClipRegionIntersect; break;
case RGN_OR: unClipMode = c_nClipRegionUnion; break;
case RGN_XOR: unClipMode = c_nClipRegionXor; break;
case RGN_DIFF: unClipMode = c_nClipRegionDiff; break;
default: unClipMode = c_nClipRegionIntersect; break;
}
unsigned int unFillMode = -1 == nFillMode ? m_pFile->GetFillMode() : nFillMode;
if (ALTERNATE == unFillMode)
unClipMode |= c_nClipRegionTypeEvenOdd;
else //if (WINDING == unFillMode)
unClipMode |= c_nClipRegionTypeWinding;
if (RGN_COPY == unMode)
ResetClip();
m_pRenderer->put_ClipMode(unClipMode);
m_pRenderer->BeginCommand(c_nClipType);
m_pRenderer->BeginCommand(c_nPathType);
m_pRenderer->PathCommandStart();
}
void EndClipPath(unsigned int unMode)
{
m_pRenderer->EndCommand(c_nPathType);
m_pRenderer->EndCommand(c_nClipType);
m_pRenderer->PathCommandEnd();
m_bStartedPath = false;
}
void SetTransform(double& dM11, double& dM12, double& dM21, double& dM22, double& dX, double& dY)
{
double dKoefX = m_dScaleX;
double dKoefY = m_dScaleY;
m_pRenderer->ResetTransform();
m_pRenderer->SetTransform(dM11, dM12 * dKoefY / dKoefX, dM21 * dKoefX / dKoefY, dM22, dX * dKoefX, dY * dKoefY);
}
void GetTransform(double* pdM11, double* pdM12, double* pdM21, double* pdM22, double* pdX, double* pdY)
{
double dKoefX = m_dScaleX;
double dKoefY = m_dScaleY;
m_pRenderer->GetTransform(pdM11, pdM12, pdM21, pdM22, pdX, pdY);
*pdM12 *= dKoefX / dKoefY;
*pdM21 *= dKoefY / dKoefX;
*pdX /= dKoefX;
*pdY /= dKoefY;
}
private:
void SaveConditional(TRenderConditional& oRenderConditional)
{
oRenderConditional.m_pFile = m_pFile;
oRenderConditional.m_lDrawPathType = m_lDrawPathType;
oRenderConditional.m_dX = m_dX;
oRenderConditional.m_dY = m_dY;
oRenderConditional.m_dW = m_dW;
oRenderConditional.m_dH = m_dH;
oRenderConditional.m_dScaleX = m_dScaleX;
oRenderConditional.m_dScaleY = m_dScaleY;
oRenderConditional.m_bStartedPath = m_bStartedPath;
}
void SetConditional(const TRenderConditional& oRenderConditional)
{
m_pFile = oRenderConditional.m_pFile;
m_lDrawPathType = oRenderConditional.m_lDrawPathType;
m_dX = oRenderConditional.m_dX;
m_dY = oRenderConditional.m_dY;
m_dW = oRenderConditional.m_dW;
m_dH = oRenderConditional.m_dH;
m_dScaleX = oRenderConditional.m_dScaleX;
m_dScaleY = oRenderConditional.m_dScaleY;
m_bStartedPath = oRenderConditional.m_bStartedPath;
}
void CheckStartPath(bool bMoveTo)
{
if (!m_bStartedPath)
{
StartPath();
if (!bMoveTo)
{
TPointD oCurPos = m_pFile->GetCurPos();
MoveTo(oCurPos.X, oCurPos.Y);
}
}
}
void CheckEndPath()
{
if (m_bStartedPath)
{
DrawPath();
EndPath();
}
}
TPointD TranslatePoint(double dX, double dY)
{
TPointD oPoint;
oPoint.X = m_dScaleX * dX + m_dX;
oPoint.Y = m_dScaleY * dY + m_dY;
return oPoint;
}
bool UpdateBrush()
{
const IBrush* pBrush = m_pFile->GetBrush();
if (!pBrush)
return false;
unsigned int unBrushStyle = pBrush->GetStyle();
if (BS_NULL == unBrushStyle)
return false;
else if (BS_DIBPATTERN == unBrushStyle)
{
m_pRenderer->put_BrushType(c_BrushTypeTexture);
m_pRenderer->put_BrushTextureMode(c_BrushTextureModeTile);
m_pRenderer->put_BrushTexturePath(pBrush->GetDibPatterPath());
}
else if (BS_PATTERN == unBrushStyle)
{
m_pRenderer->put_BrushType(c_BrushTypePattern);
m_pRenderer->put_BrushTextureMode(c_BrushTextureModeTileCenter);
m_pRenderer->put_BrushTexturePath(pBrush->GetDibPatterPath());
}
else if (BS_HATCHED == unBrushStyle)
{
m_pRenderer->put_BrushType(c_BrushTypeHatch1);
std::wstring wsBrushType = L"horz";
switch (pBrush->GetHatch())
{
case HS_HORIZONTAL: wsBrushType = L"horz"; break;
case HS_VERTICAL: wsBrushType = L"vert"; break;
case HS_FDIAGONAL: wsBrushType = L"dnDiag"; break;
case HS_BDIAGONAL: wsBrushType = L"upDiag"; break;
case HS_CROSS: wsBrushType = L"cross"; break;
case HS_DIAGCROSS: wsBrushType = L"diagCross"; break;
case HS_05Percent: wsBrushType = L"pct5"; break;
case HS_10Percent: wsBrushType = L"pct10"; break;
case HS_20Percent: wsBrushType = L"pct20"; break;
case HS_25Percent: wsBrushType = L"pct25"; break;
case HS_30Percent: wsBrushType = L"pct30"; break;
case HS_40Percent: wsBrushType = L"pct40"; break;
case HS_50Percent: wsBrushType = L"pct50"; break;
case HS_60Percent: wsBrushType = L"pct60"; break;
case HS_70Percent: wsBrushType = L"pct70"; break;
case HS_75Percent: wsBrushType = L"pct75"; break;
case HS_80Percent: wsBrushType = L"pct80"; break;
case HS_90Percent: wsBrushType = L"pct90"; break;
case HS_LTDOWNWARDDIAG: wsBrushType = L"ltDnDiag"; break;
case HS_LTUPWARDDIAG: wsBrushType = L"ltUpDiag"; break;
case HS_DNDOWNWARDDIAG: wsBrushType = L"dkDnDiag"; break;
case HS_DNUPWARDDIAG: wsBrushType = L"dkUpDiag"; break;
case HS_WDOWNWARDDIAG: wsBrushType = L"wdDnDiag"; break;
case HS_WUPWARDDIAG: wsBrushType = L"wdUpDiag"; break;
case HS_LTVERTICAL: wsBrushType = L"ltVert"; break;
case HS_LTHORIZONTAL: wsBrushType = L"ltHorz"; break;
case HS_NVERTICAL: wsBrushType = L"narVert"; break;
case HS_NHORIZONTAL: wsBrushType = L"narHorz"; break;
case HS_DNVERTICAL: wsBrushType = L"dkVert"; break;
case HS_DNHORIZONTAL: wsBrushType = L"dkHorz"; break;
case HS_DASHDOWNWARDDIAG: wsBrushType = L"dashDnDiag"; break;
case HS_DASHUPWARDDIAG: wsBrushType = L"dashUpDiag"; break;
case HS_DASHHORIZONTAL: wsBrushType = L"dashHorz"; break;
case HS_DASHVERTICAL: wsBrushType = L"dashVert"; break;
case HS_SMALLCONFETTI: wsBrushType = L"smConfetti"; break;
case HS_LARGECONFETTI: wsBrushType = L"lgConfetti"; break;
case HS_ZIGZAG: wsBrushType = L"zigZag"; break;
case HS_WAVE: wsBrushType = L"wave"; break;
case HS_DIAGBRICK: wsBrushType = L"diagBrick"; break;
case HS_HORIZBRICK: wsBrushType = L"horzBrick"; break;
case HS_WEAVE: wsBrushType = L"weave"; break;
case HS_PLAID: wsBrushType = L"plaid"; break;
case HS_DIVOT: wsBrushType = L"divot"; break;
case HS_DOTGRID: wsBrushType = L"dotGrid"; break;
case HS_DOTDIAMOND: wsBrushType = L"dotDmnd"; break;
case HS_SHINGLE: wsBrushType = L"shingle"; break;
case HS_TRELLIS: wsBrushType = L"trellis"; break;
case HS_SPHERE: wsBrushType = L"sphere"; break;
case HS_SGRID: wsBrushType = L"smGrid"; break;
case HS_SCHECHERBOARD: wsBrushType = L"smCheck"; break;
case HS_LCHECHERBOARD: wsBrushType = L"lgCheck"; break;
case HS_OUTLINEDDIAMOND: wsBrushType = L"openDmnd"; break;
case HS_SOLIDDIAMOND: wsBrushType = L"solidDmnd"; break;
default: break;
}
// TODO: Непонятно почему, но в Hatch все цвета идут не как RGB, а как BGR
if (TRANSPARENT == m_pFile->GetTextBgMode())
m_pRenderer->put_BrushAlpha2(0);
else
{
m_pRenderer->put_BrushAlpha2(255);
m_pRenderer->put_BrushColor2(m_pFile->GetTextBgColor());
}
m_pRenderer->put_BrushTexturePath(wsBrushType);
m_pRenderer->put_BrushAlpha1(255);
m_pRenderer->put_BrushColor1(pBrush->GetColor());
}
else if ( BS_LINEARGRADIENT == unBrushStyle ||
BS_RECTGRADIENT == unBrushStyle ||
BS_PATHGRADIENT == unBrushStyle
)
{
m_pRenderer->put_BrushType(c_BrushTypePathGradient1);
m_pRenderer->put_BrushColor1(pBrush->GetColor());
m_pRenderer->put_BrushColor2(pBrush->GetColor2());
m_pRenderer->put_BrushAlpha1(pBrush->GetAlpha());
m_pRenderer->put_BrushAlpha2(pBrush->GetAlpha2());
double dX, dY, dWidth, dHeight;
pBrush->GetBounds(dX, dY, dWidth, dHeight);
m_pRenderer->BrushBounds(dX, dY, dWidth, dHeight);
m_pRenderer->put_BrushLinearAngle(pBrush->GetStyleEx());
std::vector<long> arColors;
std::vector<double> arPositions;
pBrush->GetGradientColors(arColors, arPositions);
m_pRenderer->put_BrushGradientColors(arColors.data(), arPositions.data(), arColors.size());
}
else if ( BS_RADIALGRADIENT == unBrushStyle ||
BS_AXIALGRADIENT == unBrushStyle
)
{
m_pRenderer->put_BrushType(c_BrushTypePathGradient2);
m_pRenderer->put_BrushColor1(pBrush->GetColor());
m_pRenderer->put_BrushColor2(pBrush->GetColor2());
m_pRenderer->put_BrushAlpha1(pBrush->GetAlpha());
m_pRenderer->put_BrushAlpha2(pBrush->GetAlpha2());
long Colors[2];
Colors[0] = pBrush->GetColor() + (pBrush->GetAlpha() << 24);
Colors[1] = pBrush->GetColor2() + (pBrush->GetAlpha2() << 24);
double Position[2] = {0, 1};
m_pRenderer->put_BrushGradientColors(Colors,Position,2);
}
else //if (BS_SOLID == unBrushStyle)
{
m_pRenderer->put_BrushType(c_BrushTypeSolid);
m_pRenderer->put_BrushColor1(pBrush->GetColor());
m_pRenderer->put_BrushAlpha1(pBrush->GetAlpha());
}
return true;
}
void UpdateClip()
{
if (m_bUpdatedClip)
return;
const CClip *pClip = m_pFile->GetClip();
if (NULL == pClip)
return;
pClip->DrawOnRenderer(this);
m_bUpdatedClip = true;
}
void UpdateTransform(int iGraphicsMode = GM_ADVANCED)
{
double dKoefX = m_dScaleX;
double dKoefY = m_dScaleY;
TXForm oMatrix;
oMatrix.Copy(m_pFile->GetTransform(iGraphicsMode));
// if (std::fabs(oMatrix.M11) > 100. || std::fabs(oMatrix.M22) > 100.)
// {
// oMatrix.M11 /= std::fabs(oMatrix.M11);
// oMatrix.M22 /= std::fabs(oMatrix.M22);
// }
m_pRenderer->ResetTransform();
m_pRenderer->SetTransform(oMatrix.M11, oMatrix.M12 * dKoefY / dKoefX, oMatrix.M21 * dKoefX / dKoefY, oMatrix.M22, oMatrix.Dx * dKoefX, oMatrix.Dy * dKoefY);
}
bool UpdatePen()
{
const IPen* pPen = m_pFile->GetPen();
if (!pPen)
return false;
unsigned int unMetaPenStyle = pPen->GetStyle();
unsigned int ulPenStyle = unMetaPenStyle & PS_STYLE_MASK;
if (PS_NULL == ulPenStyle)
return false;
unsigned int ulPenType = unMetaPenStyle & PS_TYPE_MASK;
unsigned int ulPenStartCap = unMetaPenStyle & PS_STARTCAP_MASK;
unsigned int ulPenEndCap = unMetaPenStyle & PS_ENDCAP_MASK;
unsigned int ulPenJoin = unMetaPenStyle & PS_JOIN_MASK;
BYTE nStartCapStyle = 0;
if (PS_STARTCAP_ROUND == ulPenStartCap)
nStartCapStyle = Aggplus::LineCapRound;
else if (PS_STARTCAP_SQUARE == ulPenStartCap)
nStartCapStyle = Aggplus::LineCapSquare;
else if (PS_STARTCAP_FLAT == ulPenStartCap)
nStartCapStyle = Aggplus::LineCapFlat;
BYTE nEndCapStyle = 0;
if (PS_ENDCAP_ROUND == ulPenEndCap)
nEndCapStyle = Aggplus::LineCapRound;
else if (PS_ENDCAP_SQUARE == ulPenEndCap)
nEndCapStyle = Aggplus::LineCapSquare;
else if (PS_ENDCAP_FLAT == ulPenEndCap)
nEndCapStyle = Aggplus::LineCapFlat;
if (0 == nStartCapStyle)
nStartCapStyle = nEndCapStyle;
BYTE nJoinStyle = 0;
if (PS_JOIN_ROUND == ulPenJoin)
nJoinStyle = Aggplus::LineJoinRound;
else if (PS_JOIN_BEVEL == ulPenJoin)
nJoinStyle = Aggplus::LineJoinBevel;
else if (PS_JOIN_MITER == ulPenJoin)
nJoinStyle = Aggplus::LineJoinMiter;
double dWidth = pPen->GetWidth();
// Повторение кода из Graphics для вычисления минимальной ширины пера
double dM11, dM12, dM21, dM22, dDx, dDy;
m_pRenderer->GetTransform(&dM11, &dM12, &dM21, &dM22, &dDx, &dDy);
Aggplus::CMatrix oMatrix;
oMatrix.SetElements(dM11, dM12, dM21, dM22, dDx, dDy);
oMatrix.Scale(1. / m_dScaleX, 1. / m_dScaleY);
double *pDataDash;
unsigned int unSizeDash;
pPen->GetDashData(pDataDash, unSizeDash);
// Вычисление минимально возможной ширины пера
// # Код явялется дублированным из Graphics
const double dSqrtDet = sqrt(abs(oMatrix.Determinant()));
const double dWidthMinSize = (dSqrtDet != 0) ? (1.0 / dSqrtDet) : dWidth;
if (0 == pPen->GetWidth())
{
double dX = 0.72, dY = 0.72;
oMatrix.Invert();
oMatrix.TransformPoint(dX, dY);
dX -= oMatrix.OffsetX();
dY -= oMatrix.OffsetY();
dWidth = std::min(abs(dX), abs(dY));
}
//------------------------
else
dWidth *= m_dScaleX;
if (dWidth < dWidthMinSize)
dWidth = dWidthMinSize;
const double dMiterLimit = (0 != pPen->GetMiterLimit()) ? pPen->GetMiterLimit() : m_pFile->GetMiterLimit() * m_dScaleX;
BYTE nDashStyle = Aggplus::DashStyleSolid;
if (NULL != pDataDash && 0 != unSizeDash)
{
m_pRenderer->put_PenDashOffset(pPen->GetDashOffset());
std::vector<double> arDashes(unSizeDash);
for (unsigned int unIndex = 0; unIndex < unSizeDash; ++unIndex)
arDashes[unIndex] = pDataDash[unIndex] * dWidth;
m_pRenderer->PenDashPattern(arDashes.data(), unSizeDash);
nDashStyle = Aggplus::DashStyleCustom;
}
else if (PS_SOLID != ulPenStyle)
{
std::vector<double> arDashPattern;
switch (ulPenStyle)
{
case PS_DASH:
{
arDashPattern.push_back(9 * dWidth);
arDashPattern.push_back(3 * dWidth);
break;
}
case PS_DOT:
{
arDashPattern.push_back(3 * dWidth);
arDashPattern.push_back(3 * dWidth);
break;
}
case PS_DASHDOT:
{
arDashPattern.push_back(9 * dWidth);
arDashPattern.push_back(6 * dWidth);
arDashPattern.push_back(3 * dWidth);
arDashPattern.push_back(6 * dWidth);
break;
}
case PS_DASHDOTDOT:
{
arDashPattern.push_back(9 * dWidth);
arDashPattern.push_back(6 * dWidth);
arDashPattern.push_back(3 * dWidth);
arDashPattern.push_back(6 * dWidth);
arDashPattern.push_back(3 * dWidth);
arDashPattern.push_back(6 * dWidth);
break;
}
}
if (!arDashPattern.empty())
{
m_pRenderer->PenDashPattern(arDashPattern.data(), arDashPattern.size());
nDashStyle = Aggplus::DashStyleCustom;
nStartCapStyle = nEndCapStyle = Aggplus::LineCapFlat;
nJoinStyle = Aggplus::LineJoinMiter;
}
}
m_pRenderer->put_PenDashStyle(nDashStyle);
m_pRenderer->put_PenLineJoin(nJoinStyle);
m_pRenderer->put_PenLineStartCap(nStartCapStyle);
m_pRenderer->put_PenLineEndCap(nEndCapStyle);
m_pRenderer->put_PenColor(pPen->GetColor());
m_pRenderer->put_PenSize(dWidth);
m_pRenderer->put_PenAlpha(pPen->GetAlpha());
m_pRenderer->put_PenMiterLimit(dMiterLimit);
// TO DO: С текущим интерфейсом AVSRenderer, остальные случаи ushROPMode
// реализовать невозможно. Потому что данный параметр нужно протаскивать
// как параметр Pen'a, и тот кто рисует сам должен разруливать все случаи.
switch (m_pFile->GetRop2Mode())
{
case R2_BLACK: m_pRenderer->put_PenColor(METAFILE_RGBA(0, 0, 0, 0)); break;
case R2_NOP: m_pRenderer->put_PenAlpha(0); break;
case R2_COPYPEN: break;
case R2_WHITE: m_pRenderer->put_PenColor(METAFILE_RGBA(255, 255, 255, 0)); break;
}
return true;
}
private:
IRenderer* m_pRenderer;
IMetaFileBase* m_pFile;
int m_lDrawPathType;
double m_dX; // Координаты левого верхнего угла
double m_dY; //
double m_dW; //
double m_dH; //
double m_dScaleX; // Коэффициенты сжатия/растяжения, чтобы
double m_dScaleY; // результирующая картинка была нужных размеров.
bool m_bStartedPath;
bool m_bUpdatedClip;
TRenderConditional *m_pSecondConditional;
};
}
#endif // _METAFILE_COMMON_METAFILERENDERER_H