Files
core/DesktopEditor/raster/Metafile/Common/MetaFileRenderer.h
Ilya Kirillov 867b0634f3 Fix bug #36423
Fix problem with the clip in the EMF
2018-05-29 18:33:49 +03:00

844 lines
25 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-2018
*
* 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 Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* 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
namespace MetaFile
{
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;
if (!pRenderer)
return;
m_pRenderer = pRenderer;
TRect* pBounds = m_pFile->GetDCBounds();
int nL = pBounds->nLeft;
int nR = pBounds->nRight;
int nT = pBounds->nTop;
int nB = pBounds->nBottom;
m_dScaleX = (nR - nL <= 0) ? 1 : m_dW / (double)(nR - nL);
m_dScaleY = (nB - nT <= 0) ? 1 : m_dH / (double)(nB - nT);
m_bStartedPath = 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();
}
~CMetaFileRenderer()
{
}
void Begin()
{
}
void End()
{
CheckEndPath();
}
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;
BYTE* pBufferPtr = new BYTE[4 * unWidth * unHeight];
oImage.Create(pBufferPtr, unWidth, unHeight, 4 * unWidth);
for (int nIndex = 0, nSize = 4 * unWidth * unHeight; nIndex < nSize; nIndex += 4)
{
pBufferPtr[0] = (unsigned char)pBuffer[nIndex + 0];
pBufferPtr[1] = (unsigned char)pBuffer[nIndex + 1];
pBufferPtr[2] = (unsigned char)pBuffer[nIndex + 2];
pBufferPtr[3] = (unsigned char)pBuffer[nIndex + 3];
pBufferPtr += 4;
}
TPointD oTL = TranslatePoint(dX, dY);
TPointD oBR = TranslatePoint(dX + dW, dY + dH);
m_pRenderer->DrawImage(&oImage, oTL.x, oTL.y, oBR.x - oTL.x, oBR.y - oTL.y);
}
void DrawString(std::wstring& wsText, unsigned int unCharsCount, double _dX, double _dY, double* pDx)
{
CheckEndPath();
UpdateTransform();
UpdateClip();
IFont* pFont = m_pFile->GetFont();
if (!pFont)
return;
int lLogicalFontHeight = pFont->GetHeight();
if (lLogicalFontHeight < 0)
lLogicalFontHeight = -lLogicalFontHeight;
if (lLogicalFontHeight < 0.01)
lLogicalFontHeight = 18;
double dFontHeight = fabs(lLogicalFontHeight * m_dScaleY * m_pFile->GetPixelHeight() / 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 = (float)cos(dTheta);
double dSinTheta = (float)sin(dTheta);
float fL = 0, fT = 0, fW = 0, fH = 0;
float fUndX1 = 0, fUndY1 = 0, fUndX2 = 0, fUndY2 = 0, fUndSize = 1;
double dFontCharSpace = m_pFile->GetCharSpace() * m_dScaleX * m_pFile->GetPixelWidth();
m_pRenderer->put_FontCharSpace(dFontCharSpace);
CFontManager* pFontManager = m_pFile->GetFontManager();
if (pFontManager)
{
pFontManager->LoadFontByName(wsFaceName, dFontHeight, lStyle, 72, 72);
pFontManager->SetCharSpacing(dFontCharSpace * 72 / 25.4);
double dMmToPt = 25.4 / 72;
double dFHeight = dFontHeight * pFontManager->m_pFont->GetHeight() / pFontManager->m_pFont->m_lUnits_Per_Em * dMmToPt;
double dFDescent = dFontHeight * pFontManager->m_pFont->GetDescender() / pFontManager->m_pFont->m_lUnits_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 += wsText.at(wsText.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(wsText, 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, _dY);
double dX = oTextPoint.x;
double dY = oTextPoint.y;
// Найдем начальную точку текста
unsigned int ulTextAlign = m_pFile->GetTextAlign();
if (ulTextAlign & TA_BASELINE)
{
// Ничего не делаем
}
else if (ulTextAlign & TA_BOTTOM)
{
float fTemp = -(-fT + fH);
dX += -fTemp * dSinTheta;
dY += fTemp * dCosTheta;
}
else // if (ulTextAlign & TA_TOP)
{
float fTemp = -fT;
dX += -fTemp * dSinTheta;
dY += fTemp * dCosTheta;
}
if (ulTextAlign & TA_CENTER)
{
dX += -fW / 2 * dCosTheta;
dY += -fW / 2 * dSinTheta;
}
else if (ulTextAlign & TA_RIGHT)
{
dX += -fW * dCosTheta;
dY += -fW * 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 (0 != pFont->GetEscapement())
{
// TODO: тут реализован только параметр shEscapement, еще нужно реализовать параметр Orientation
m_pRenderer->SetTransform(dCosTheta, dSinTheta, -dSinTheta, dCosTheta, dX - dX * dCosTheta + dY * dSinTheta, dY - dX * dSinTheta - dY * dCosTheta);
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->PathCommandClose();
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(wsText, dX, dY, 0, 0);
}
else
{
unsigned int unUnicodeLen = 0;
unsigned int* pUnicode = NSStringExt::CConverter::GetUtf32FromUnicode(wsText, unUnicodeLen);
if (pUnicode && unUnicodeLen)
{
double dOffset = 0;
double dKoefX = m_dScaleX;
for (unsigned int unCharIndex = 0; unCharIndex < unUnicodeLen; unCharIndex++)
{
std::wstring wsChar = NSStringExt::CConverter::GetUnicodeFromUTF32(&*(pUnicode + unCharIndex), 1);
m_pRenderer->CommandDrawText(wsChar, 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)
{
if (-1 != m_lDrawPathType)
m_pRenderer->DrawPath(m_lDrawPathType);
}
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(double dLeft, double dTop, double dRight, double dBottom)
{
m_pRenderer->put_ClipMode(c_nClipRegionTypeWinding | c_nClipRegionIntersect);
m_pRenderer->BeginCommand(c_nClipType);
m_pRenderer->BeginCommand(c_nPathType);
m_pRenderer->PathCommandStart();
TPointD oTL = TranslatePoint(dLeft, dTop);
TPointD oBR = TranslatePoint(dRight, dBottom);
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 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;
}
private:
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()
{
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_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;
}
// TODO: Непонятно почему, но в Hatch все цвета идут не как RGB, а как BGR
if (TRANSPARENT == m_pFile->GetTextBgMode())
m_pRenderer->put_BrushAlpha2(0);
else
{
m_pRenderer->put_BrushAlpha2(255);
TColor oBgColor(m_pFile->GetTextBgColor());
m_pRenderer->put_BrushColor2(oBgColor.ToInt());
}
TColor oFgColor(pBrush->GetColor());
m_pRenderer->put_BrushTexturePath(wsBrushType);
m_pRenderer->put_BrushAlpha1(255);
m_pRenderer->put_BrushColor1(oFgColor.ToInt());
}
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());
m_pRenderer->put_BrushLinearAngle(pBrush->GetStyleEx());
long Colors[2];
Colors[0] = (pBrush->GetColor()<<8) + pBrush->GetAlpha();
Colors[1] = (pBrush->GetColor2()<<8) + pBrush->GetAlpha2();
double Position[2] = {0, 1};
m_pRenderer->put_BrushGradientColors(Colors,Position,2);
}
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()<<8) + pBrush->GetAlpha();
Colors[1] = (pBrush->GetColor2()<<8) + pBrush->GetAlpha2();
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 UpdateTransform()
{
double dKoefX = m_dScaleX;
double dKoefY = m_dScaleY;
TEmfXForm* pMatrix = m_pFile->GetTransform();
m_pRenderer->ResetTransform();
m_pRenderer->SetTransform(pMatrix->M11, pMatrix->M12 * dKoefY / dKoefX, pMatrix->M21 * dKoefX / dKoefY, pMatrix->M22, pMatrix->Dx * dKoefX, pMatrix->Dy * dKoefY);
}
bool UpdatePen()
{
IPen* pPen = m_pFile->GetPen();
if (!pPen)
return false;
int nColor = pPen->GetColor();
double dPixelWidth = m_pFile->GetPixelWidth();
// TODO: dWidth зависит еще от флага PS_GEOMETRIC в стиле карандаша
double dWidth = pPen->GetWidth() * m_dScaleX * dPixelWidth;
if (dWidth <= 0.01)
dWidth = 0;
unsigned int unMetaPenStyle = pPen->GetStyle();
unsigned int ulPenType = unMetaPenStyle & PS_TYPE_MASK;
unsigned int ulPenEndCap = unMetaPenStyle & PS_ENDCAP_MASK;
unsigned int ulPenJoin = unMetaPenStyle & PS_JOIN_MASK;
unsigned int ulPenStyle = unMetaPenStyle & PS_STYLE_MASK;
BYTE nCapStyle = 0;
if (PS_ENDCAP_ROUND == ulPenEndCap)
nCapStyle = Aggplus::LineCapRound;
else if (PS_ENDCAP_SQUARE == ulPenEndCap)
nCapStyle = Aggplus::LineCapSquare;
else if (PS_ENDCAP_FLAT == ulPenEndCap)
nCapStyle = Aggplus::LineCapFlat;
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 dMiterLimit = m_pFile->GetMiterLimit() * m_dScaleX * dPixelWidth;
// TODO: Реализовать PS_USERSTYLE
BYTE nDashStyle = Aggplus::DashStyleSolid;;
// В WinGDI все карандаши толщиной больше 1px рисуются в стиле PS_SOLID
if (1 >= pPen->GetWidth() && PS_SOLID != ulPenStyle)
{
dWidth = 0; // Специальное значение для 1pх карандаша
double dDpiX;
m_pRenderer->get_DpiX(&dDpiX);
double dPixelW = dDpiX > 1 ? 25.4 / dDpiX : 25.4 / 72;
double dDashOff = 0;
double* pDashPattern = NULL;
int nDashLen = 0;
switch (ulPenStyle)
{
case PS_DASH:
{
dDashOff = 0 * dPixelW;
nDashLen = 2;
pDashPattern = new double[2];
if (pDashPattern)
{
pDashPattern[0] = 18 * dPixelW;
pDashPattern[1] = 3 * dPixelW;
}
break;
}
case PS_DOT:
{
dDashOff = 4 * dPixelW;
nDashLen = 2;
pDashPattern = new double[2];
if (pDashPattern)
{
pDashPattern[0] = 3 * dPixelW;
pDashPattern[1] = 3 * dPixelW;
}
break;
}
case PS_DASHDOT:
{
dDashOff = 22 * dPixelW;
nDashLen = 4;
pDashPattern = new double[4];
if (pDashPattern)
{
pDashPattern[0] = 9 * dPixelW;
pDashPattern[1] = 6 * dPixelW;
pDashPattern[2] = 3 * dPixelW;
pDashPattern[3] = 6 * dPixelW;
}
break;
}
case PS_DASHDOTDOT:
{
dDashOff = 22 * dPixelW;
nDashLen = 6;
pDashPattern = new double[6];
if (pDashPattern)
{
pDashPattern[0] = 9 * dPixelW;
pDashPattern[1] = 3 * dPixelW;
pDashPattern[2] = 3 * dPixelW;
pDashPattern[3] = 3 * dPixelW;
pDashPattern[4] = 3 * dPixelW;
pDashPattern[5] = 3 * dPixelW;
}
break;
}
}
if (NULL != pDashPattern)
{
m_pRenderer->put_PenDashOffset(dDashOff);
m_pRenderer->PenDashPattern(pDashPattern, nDashLen);
nDashStyle = Aggplus::DashStyleCustom;
delete[] pDashPattern;
}
}
m_pRenderer->put_PenDashStyle(nDashStyle);
m_pRenderer->put_PenLineJoin(nJoinStyle);
m_pRenderer->put_PenLineStartCap(nCapStyle);
m_pRenderer->put_PenLineEndCap(nCapStyle);
m_pRenderer->put_PenColor(nColor);
m_pRenderer->put_PenSize(dWidth);
m_pRenderer->put_PenAlpha(255);
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)); 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)); break;
}
if (PS_NULL == ulPenStyle)
return false;
return true;
}
bool UpdateClip()
{
IClip* pClip = m_pFile->GetClip();
if (!pClip)
return false;
pClip->ClipOnRenderer(this);
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;
};
}
#endif // _METAFILE_COMMON_METAFILERENDERER_H