mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
844 lines
25 KiB
C++
844 lines
25 KiB
C++
/*
|
||
* (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
|