mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 14:00:32 +08:00
642 lines
15 KiB
C++
642 lines
15 KiB
C++
#pragma once
|
|
|
|
#include "Const.h"
|
|
#include "StringWriter.h"
|
|
|
|
namespace NSHtmlRenderer
|
|
{
|
|
// ïðèõîäèòñÿ â html ðàçðóëèâàòü ïðîñòóþ ãðàôèêó.
|
|
// (ëèíèè (ãîðèçîíòàëüíûå/âåêòèêàëüíûå), ðåêòû (íå ïîâåðíóòûå)).
|
|
// äëÿ íèõ íå íóæíî ãåíåðèòü html5-êîä, êîòîðûé ãåíåðèò òÿæåëóþ êàðòèíêó
|
|
// è ïîäãðóæàåò åå â ïàìÿòü
|
|
|
|
const LONG g_lSimpleCommandsCountMax = 100;
|
|
|
|
class CVectorGraphicsWriter
|
|
{
|
|
public:
|
|
enum SimpleCommand
|
|
{
|
|
scMoveTo = 0,
|
|
scLineTo = 1,
|
|
scClose = 2
|
|
};
|
|
class CSimpleCommand
|
|
{
|
|
public:
|
|
SimpleCommand m_eType;
|
|
double m_dX;
|
|
double m_dY;
|
|
};
|
|
|
|
public:
|
|
CStringWriter m_oWriterSimpleGraphics;
|
|
CStringWriter m_oWriterVMLPath;
|
|
CStringWriter m_oWriterCanvas;
|
|
CStringWriter m_oWriterVML;
|
|
|
|
Graphics::IASCGraphicSimpleComverter* m_pSimpleConverter;
|
|
|
|
NSStructures::CPen* m_pPen;
|
|
NSStructures::CBrush* m_pBrush;
|
|
|
|
CMatrix* m_pFullTransform;
|
|
|
|
double m_dCurrentMoveToX;
|
|
double m_dCurrentMoveToY;
|
|
|
|
bool m_bIsSimpleGraphics;
|
|
|
|
public:
|
|
BOOL m_bIsSimple;
|
|
|
|
BOOL m_bIsClip;
|
|
BOOL m_bIsClipping;
|
|
|
|
CSimpleCommand* m_arSimpleCommands;
|
|
LONG m_lCountSC;
|
|
|
|
public:
|
|
CVectorGraphicsWriter() : m_oWriterVML(), m_oWriterCanvas(), m_oWriterSimpleGraphics(), m_oWriterVMLPath()
|
|
{
|
|
m_bIsClip = FALSE;
|
|
m_bIsClipping = FALSE;
|
|
|
|
m_bIsSimple = TRUE;
|
|
|
|
m_pSimpleConverter = NULL;
|
|
|
|
m_pPen = NULL;
|
|
m_pBrush = NULL;
|
|
|
|
m_pFullTransform = NULL;
|
|
|
|
m_dCurrentMoveToX = 0;
|
|
m_dCurrentMoveToY = 0;
|
|
|
|
m_lCountSC = 0;
|
|
|
|
m_bIsSimpleGraphics = true;
|
|
|
|
m_arSimpleCommands = new CSimpleCommand[g_lSimpleCommandsCountMax];
|
|
}
|
|
~CVectorGraphicsWriter()
|
|
{
|
|
RELEASEARRAYOBJECTS(m_arSimpleCommands);
|
|
}
|
|
|
|
inline void EndPage()
|
|
{
|
|
m_oWriterSimpleGraphics.ClearNoAttack();
|
|
m_oWriterVMLPath.ClearNoAttack();
|
|
m_oWriterCanvas.ClearNoAttack();
|
|
m_oWriterVML.ClearNoAttack();
|
|
|
|
m_bIsSimpleGraphics = true;
|
|
}
|
|
|
|
inline void WriteBeginPath()
|
|
{
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_StartPath);
|
|
}
|
|
|
|
inline void WriteEndPath()
|
|
{
|
|
m_oWriterVMLPath.ClearNoAttack();
|
|
|
|
m_bIsSimple = TRUE;
|
|
m_lCountSC = 0;
|
|
}
|
|
|
|
void WritePathStart()
|
|
{
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_StartPath);
|
|
}
|
|
void WritePathClose()
|
|
{
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_ClosePath);
|
|
|
|
if (!m_bIsClipping)
|
|
{
|
|
m_oWriterVMLPath.WriteString(g_bstr_vml_ClosePath);
|
|
}
|
|
|
|
if (m_bIsSimple)
|
|
{
|
|
if (0 < m_lCountSC)
|
|
{
|
|
m_arSimpleCommands[m_lCountSC].m_eType = scLineTo;
|
|
m_arSimpleCommands[m_lCountSC].m_dX = m_dCurrentMoveToX;
|
|
m_arSimpleCommands[m_lCountSC].m_dY = m_dCurrentMoveToY;
|
|
|
|
++m_lCountSC;
|
|
|
|
if (m_lCountSC == g_lSimpleCommandsCountMax)
|
|
{
|
|
m_bIsSimple = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WritePathMoveTo(double& x, double& y)
|
|
{
|
|
CString str1 = _T("");
|
|
//str1.Format(g_string_canvas_MoveTo, x, y);
|
|
str1.Format(g_string_canvas_MoveToD, round(x), round(y));
|
|
m_oWriterCanvas.WriteString(str1);
|
|
|
|
if (!m_bIsClipping)
|
|
{
|
|
CString str2 = _T("");
|
|
str2.Format(g_string_vml_MoveTo, round(x), round(y));
|
|
m_oWriterVMLPath.WriteString(str2);
|
|
}
|
|
|
|
if (m_bIsSimple)
|
|
{
|
|
m_arSimpleCommands[m_lCountSC].m_eType = scMoveTo;
|
|
m_arSimpleCommands[m_lCountSC].m_dX = x;
|
|
m_arSimpleCommands[m_lCountSC].m_dY = y;
|
|
|
|
m_dCurrentMoveToX = x;
|
|
m_dCurrentMoveToY = y;
|
|
|
|
++m_lCountSC;
|
|
if (m_lCountSC == g_lSimpleCommandsCountMax)
|
|
{
|
|
m_bIsSimple = FALSE;
|
|
}
|
|
}
|
|
}
|
|
void WritePathLineTo(double& x, double& y)
|
|
{
|
|
if (0 == m_oWriterVMLPath.GetCurSize())
|
|
{
|
|
CString str3 = _T("");
|
|
//str3.Format(g_string_canvas_MoveTo, x, y);
|
|
str3.Format(g_string_canvas_MoveToD, round(x), round(y));
|
|
m_oWriterCanvas.WriteString(str3);
|
|
|
|
str3 = _T("");
|
|
str3.Format(g_string_vml_MoveTo, round(x), round(y));
|
|
|
|
m_oWriterVMLPath.WriteString(str3);
|
|
}
|
|
|
|
CString str1 = _T("");
|
|
//str1.Format(g_string_canvas_LineTo, x, y);
|
|
str1.Format(g_string_canvas_LineToD, round(x), round(y));
|
|
m_oWriterCanvas.WriteString(str1);
|
|
|
|
if (!m_bIsClipping)
|
|
{
|
|
CString str2 = _T("");
|
|
str2.Format(g_string_vml_LineTo, round(x), round(y));
|
|
m_oWriterVMLPath.WriteString(str2);
|
|
}
|
|
|
|
if (m_bIsSimple)
|
|
{
|
|
if (0 == m_lCountSC)
|
|
{
|
|
m_arSimpleCommands[m_lCountSC].m_eType = scMoveTo;
|
|
m_arSimpleCommands[m_lCountSC].m_dX = x;
|
|
m_arSimpleCommands[m_lCountSC].m_dY = y;
|
|
|
|
m_dCurrentMoveToX = x;
|
|
m_dCurrentMoveToY = y;
|
|
|
|
++m_lCountSC;
|
|
}
|
|
else
|
|
{
|
|
double _x = m_arSimpleCommands[m_lCountSC - 1].m_dX;
|
|
double _y = m_arSimpleCommands[m_lCountSC - 1].m_dY;
|
|
|
|
if ((FABS(_x - x) < 0.01) || (FABS(_y - y) < 0.01))
|
|
{
|
|
// ïðîäîëæàåì ñèìïë!
|
|
m_arSimpleCommands[m_lCountSC].m_eType = scLineTo;
|
|
m_arSimpleCommands[m_lCountSC].m_dX = x;
|
|
m_arSimpleCommands[m_lCountSC].m_dY = y;
|
|
|
|
++m_lCountSC;
|
|
|
|
if (m_lCountSC == g_lSimpleCommandsCountMax)
|
|
{
|
|
m_bIsSimple = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
void WritePathCurveTo(double& x1, double& y1, double& x2, double& y2, double& x3, double& y3)
|
|
{
|
|
if (0 == m_oWriterVMLPath.GetCurSize())
|
|
{
|
|
CString str3 = _T("");
|
|
//str3.Format(g_string_canvas_MoveTo, x1, y1);
|
|
str3.Format(g_string_canvas_MoveToD, round(x1), round(y1));
|
|
m_oWriterCanvas.WriteString(str3);
|
|
|
|
str3 = _T("");
|
|
str3.Format(g_string_vml_MoveTo, round(x1), round(y1));
|
|
|
|
m_oWriterVMLPath.WriteString(str3);
|
|
}
|
|
|
|
CString str1 = _T("");
|
|
//str1.Format(g_string_canvas_CurveTo, x1, y1, x2, y2, x3, y3);
|
|
str1.Format(g_string_canvas_CurveToD, round(x1), round(y1), round(x2), round(y2), round(x3), round(y3));
|
|
m_oWriterCanvas.WriteString(str1);
|
|
|
|
if (!m_bIsClipping)
|
|
{
|
|
CString str2 = _T("");
|
|
str2.Format(g_string_vml_CurveTo, round(x1), round(y1), round(x2), round(y2), round(x3), round(y3));
|
|
m_oWriterVMLPath.WriteString(str2);
|
|
}
|
|
|
|
m_bIsSimple = FALSE;
|
|
}
|
|
void WriteDrawPath(LONG lType, LONG lIDTx, LONG& lCurTxNumber, LONG& lPageNumber)
|
|
{
|
|
if (m_bIsSimple && (-1 == lIDTx))
|
|
{
|
|
// ïèøåì ïî-êðóòîìó
|
|
double x = 0;
|
|
double y = 0;
|
|
double w = 0;
|
|
double h = 0;
|
|
|
|
bool bIsRect = IsRect(x, y, w, h);
|
|
|
|
if (bIsRect)
|
|
{
|
|
if ((0 == w && 0 == h))
|
|
return;
|
|
|
|
w = max(1, w);
|
|
h = max(1, h);
|
|
|
|
if (bIsRect)
|
|
{
|
|
CString strLineColor = GetStringColor(m_pPen->Color);
|
|
CString strFillColor = GetStringColor(m_pBrush->Color1);
|
|
|
|
if (0 == m_pBrush->Alpha1)
|
|
strFillColor = _T("transparent");
|
|
|
|
if ((1 >= w) || (1 >= h) && (lType < 0xFF))
|
|
{
|
|
CString strRect = _T("");
|
|
strRect.Format(g_string_rect, 0, strLineColor, strLineColor, (double)m_pPen->Alpha / 255.0, round(x), round(y), round(w), round(h));
|
|
|
|
m_oWriterSimpleGraphics.WriteString(strRect);
|
|
}
|
|
else
|
|
{
|
|
if (0x00 == (lType & 0xFF))
|
|
{
|
|
CString strRect = _T("");
|
|
strRect.Format(g_string_rect, 0, strFillColor, strLineColor, (double)m_pBrush->Alpha1 / 255.0, round(x), round(y), round(w), round(h));
|
|
|
|
m_oWriterSimpleGraphics.WriteString(strRect);
|
|
}
|
|
else if (lType < 0xFF)
|
|
{
|
|
CString strRect = _T("");
|
|
strRect.Format(g_string_rect, 1, strFillColor, strLineColor, (double)m_pPen->Alpha / 255.0, round(x), round(y), round(w), round(h));
|
|
|
|
m_oWriterSimpleGraphics.WriteString(strRect);
|
|
}
|
|
else
|
|
{
|
|
double dAlpha = (double)m_pBrush->Alpha1 / 255.0;
|
|
|
|
CString strRect = _T("");
|
|
strRect.Format(g_string_rect, 1, strFillColor, strLineColor, dAlpha, round(x), round(y), round(w), round(h));
|
|
|
|
m_oWriterSimpleGraphics.WriteString(strRect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bIsSimpleGraphics = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_bIsSimpleGraphics = false;
|
|
}
|
|
|
|
CString strStroked = _T("false");
|
|
CString strFilled = _T("false");
|
|
|
|
//if (0x00 != (0x02 & (lType >> 8)) && ((lType & 0xFF) == 0x00))
|
|
//{
|
|
// lType = 1;
|
|
// m_pPen->Color = m_pBrush->Color1;
|
|
// m_pPen->Alpha = m_pBrush->Alpha1;
|
|
//}
|
|
|
|
bool bStroke = false;
|
|
|
|
if (m_pPen->Alpha == 0)
|
|
lType &= 0xFF00;
|
|
|
|
if ((-1 == lIDTx) && (0 == m_pBrush->Alpha1))
|
|
lType &= 0xFF;
|
|
|
|
// canvas
|
|
if ((lType & 0x01) == 0x01)
|
|
{
|
|
CString strStrokeStyle = SetStrokeColor(m_pPen->Color, m_pPen->Alpha);
|
|
|
|
//CString strStrokeStyle = _T("");
|
|
//strStrokeStyle.Format(g_string_canvas_StrokeColor, ConvertColor(m_pPen->Color));
|
|
|
|
m_oWriterCanvas.WriteString(strStrokeStyle);
|
|
|
|
bStroke = true;
|
|
|
|
if (0x00 != m_pPen->Alpha)
|
|
{
|
|
strStroked = _T("true");
|
|
}
|
|
}
|
|
if (lType > 0x01)
|
|
{
|
|
if (-1 != lIDTx)
|
|
{
|
|
// òåêñòóðà!
|
|
CString strImage = _T("");
|
|
|
|
double x = 0;
|
|
double y = 0;
|
|
double w = 0;
|
|
double h = 0;
|
|
|
|
m_pSimpleConverter->PathCommandGetBounds(&x, &y, &w, &h);
|
|
|
|
double r = x + w;
|
|
double b = y + h;
|
|
|
|
m_pFullTransform->TransformPoint(x, y);
|
|
m_pFullTransform->TransformPoint(r, b);
|
|
|
|
w = r - x;
|
|
h = b - y;
|
|
|
|
strImage.Format(g_string_canvas_drawImage, lIDTx, lIDTx, lIDTx, lIDTx, lIDTx, round(x), round(y), round(w), round(h), lPageNumber, lCurTxNumber, lPageNumber, lCurTxNumber);
|
|
m_oWriterCanvas.WriteString(strImage);
|
|
}
|
|
else
|
|
{
|
|
CString strFillStyle = SetFillColor(m_pBrush->Color1, m_pBrush->Alpha1);
|
|
|
|
//CString strFillStyle = _T("");
|
|
//strFillStyle.Format(g_string_canvas_FillColor, ConvertColor(m_pBrush->Color1));
|
|
|
|
m_oWriterCanvas.WriteString(strFillStyle);
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_Fill);
|
|
}
|
|
|
|
strFilled = _T("true");
|
|
}
|
|
|
|
if (bStroke)
|
|
{
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_Stroke);
|
|
}
|
|
|
|
CString str = m_oWriterVMLPath.GetData();
|
|
CString strVML = _T("");
|
|
if (-1 != lIDTx)
|
|
{
|
|
strVML.Format(g_string_shape_vmlTexture, strStroked, ConvertColor(m_pPen->Color), strFilled, str, lIDTx, (double)m_pBrush->Alpha1 / 255);
|
|
}
|
|
else if (0xFF == m_pBrush->Alpha1)
|
|
{
|
|
strVML.Format(g_string_shape_vml, strStroked, ConvertColor(m_pPen->Color), strFilled, ConvertColor(m_pBrush->Color1), str);
|
|
}
|
|
else
|
|
{
|
|
strVML.Format(g_string_shape_vmlAlpha, strStroked, ConvertColor(m_pPen->Color), strFilled, ConvertColor(m_pBrush->Color1), str, (double)m_pBrush->Alpha1 / 255);
|
|
}
|
|
m_oWriterVML.WriteString(strVML);
|
|
|
|
if (-1 != lIDTx)
|
|
{
|
|
++lCurTxNumber;
|
|
}
|
|
}
|
|
|
|
void WritePathClip()
|
|
{
|
|
m_bIsClipping = TRUE;
|
|
}
|
|
void WritePathClipEnd()
|
|
{
|
|
m_bIsClipping = FALSE;
|
|
|
|
double x = 0;
|
|
double y = 0;
|
|
double w = 0;
|
|
double h = 0;
|
|
|
|
m_pSimpleConverter->PathCommandGetBounds(&x, &y, &w, &h);
|
|
if ((0 > w) || (0 > h))
|
|
{
|
|
// íèêàêîãî êëèïà íåò!
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (!m_bIsClip)
|
|
{
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_Save);
|
|
}
|
|
m_bIsClip = TRUE;
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_Clip);
|
|
}
|
|
}
|
|
void WritePathResetClip()
|
|
{
|
|
if (m_bIsClip)
|
|
{
|
|
m_oWriterCanvas.WriteString(g_bstr_canvas_Restore);
|
|
}
|
|
|
|
m_bIsClip = FALSE;
|
|
m_bIsClipping = FALSE;
|
|
}
|
|
|
|
protected:
|
|
|
|
bool IsRect(double& x, double& y, double& w, double& h)
|
|
{
|
|
if (1 >= m_lCountSC)
|
|
return false;
|
|
|
|
double dPrevX = m_arSimpleCommands[0].m_dX;
|
|
double dPrevY = m_arSimpleCommands[0].m_dY;
|
|
|
|
long lCurDirection = 0;
|
|
|
|
CSimpleArray<double> arX;
|
|
CSimpleArray<double> arY;
|
|
|
|
arX.Add(dPrevX);
|
|
arY.Add(dPrevY);
|
|
|
|
double dXmin = dPrevX;
|
|
double dXmax = dPrevX;
|
|
double dYmin = dPrevY;
|
|
double dYmax = dPrevY;
|
|
|
|
double _dX = m_arSimpleCommands[m_lCountSC - 1].m_dX;
|
|
double _dY = m_arSimpleCommands[m_lCountSC - 1].m_dY;
|
|
|
|
for (LONG i = 1; i < m_lCountSC; ++i)
|
|
{
|
|
CSimpleCommand* pComm = &m_arSimpleCommands[i];
|
|
|
|
if (scLineTo != pComm->m_eType)
|
|
return false;
|
|
|
|
long lDir = SkipCurDirection(lCurDirection, i, dPrevX, dPrevY);
|
|
|
|
double dX = _dX;
|
|
double dY = _dY;
|
|
|
|
if (i < m_lCountSC)
|
|
{
|
|
dX = m_arSimpleCommands[i - 1].m_dX;
|
|
dY = m_arSimpleCommands[i - 1].m_dY;
|
|
}
|
|
|
|
if (dX > dXmax)
|
|
dXmax = dX;
|
|
else if (dX < dXmin)
|
|
dXmin = dX;
|
|
|
|
if (dY > dYmax)
|
|
dYmax = dY;
|
|
else if (dY < dYmin)
|
|
dYmin = dY;
|
|
|
|
arX.Add(dX);
|
|
arY.Add(dY);
|
|
|
|
lCurDirection = lDir;
|
|
}
|
|
|
|
// âñå, ìàññèâû çàïîëíåíû.
|
|
// òåïåðü îñòàëîñü îïðåäåëèòü, ðåêò ëè ýòî
|
|
// äîëæíî:
|
|
// 1) êðîìå ìèíèìóìîâ è ìàêñèìóìîâ íè÷åãî íå ìîæåò áûòü.
|
|
// 2) âñå òî÷êè ðåêòà äîëæíû ïðèñóòñòâîâàòü
|
|
|
|
bool b1 = false;
|
|
bool b2 = false;
|
|
bool b3 = false;
|
|
bool b4 = false;
|
|
|
|
int lCount = arX.GetSize();
|
|
for (int i = 0; i < lCount; ++i)
|
|
{
|
|
double ___x = arX[i];
|
|
double ___y = arY[i];
|
|
bool bBreak = false;
|
|
|
|
if (IsEqualPoint(___x, ___y, dXmin, dYmin))
|
|
b1 = true;
|
|
else if (IsEqualPoint(___x, ___y, dXmax, dYmin))
|
|
b2 = true;
|
|
else if (IsEqualPoint(___x, ___y, dXmin, dYmax))
|
|
b4 = true;
|
|
else if (IsEqualPoint(___x, ___y, dXmax, dYmax))
|
|
b3 = true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
x = dXmin;
|
|
y = dYmin;
|
|
w = dXmax - dXmin;
|
|
h = dYmax - dYmin;
|
|
|
|
if (b1 && b2 && !b3 && !b4)
|
|
return true;
|
|
if (b1 && !b2 && !b3 && b4)
|
|
return true;
|
|
if (!b1 && b2 && b3 && !b4)
|
|
return true;
|
|
if (!b1 && !b2 && b3 && b4)
|
|
return true;
|
|
if (b1 && b2 && b3 && b4)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// direction: (0 - âïðàâî, 1 - âíèç, 2 - âëåâî, 3 - ââåðõ)
|
|
inline long SkipCurDirection(const long& lDirection, long& lIndexCur, double& dPrevX, double& dPrevY)
|
|
{
|
|
for (; lIndexCur < m_lCountSC; ++lIndexCur)
|
|
{
|
|
long lDir = GetCurDirection(lIndexCur, dPrevX, dPrevY);
|
|
|
|
dPrevX = m_arSimpleCommands[lIndexCur].m_dX;
|
|
dPrevY = m_arSimpleCommands[lIndexCur].m_dY;
|
|
|
|
if ((-1 == lDir) || (lDir == lDirection))
|
|
continue;
|
|
|
|
return lDir;
|
|
}
|
|
return -1;
|
|
}
|
|
inline long GetCurDirection(const long& lIndex, const double& dPrevX, const double& dPrevY)
|
|
{
|
|
double x = m_arSimpleCommands[lIndex].m_dX;
|
|
double y = m_arSimpleCommands[lIndex].m_dY;
|
|
|
|
if (FABS(y - dPrevY) < 0.01)
|
|
{
|
|
if (FABS(x - dPrevX) < 0.01)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return (x >= dPrevX) ? 0 : 2;
|
|
}
|
|
else
|
|
{
|
|
return (y >= dPrevY) ? 1 : 3;
|
|
}
|
|
}
|
|
|
|
inline bool IsEqualPoint(double& x, double&y, double& _x, double& _y)
|
|
{
|
|
if ((FABS(x - _x) < 0.1) && (FABS(y - _y) < 0.1))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool IsTwoRectOneDirection()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
LONG SkipRect(LONG& lStart, LONG& lEnd)
|
|
{
|
|
|
|
}
|
|
};
|
|
} |