475 lines
16 KiB
C++
475 lines
16 KiB
C++
/*
|
||
* (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 _BUILD_GRAPHICS_H_
|
||
#define _BUILD_GRAPHICS_H_
|
||
|
||
//#define _WINDOWS_GDIPLUS_USE_
|
||
#include "AggPlusEnums.h"
|
||
|
||
#include "../agg-2.4/include/agg_pixfmt_rgba.h"
|
||
#include "../agg-2.4/include/agg_conv_curve.h"
|
||
#include "../agg-2.4/include/agg_conv_stroke.h"
|
||
#include "../agg-2.4/include/agg_conv_dash.h"
|
||
#include "../agg-2.4/include/agg_span_gradient.h"
|
||
#include "../agg-2.4/include/agg_span_hatch.h"
|
||
#include "../agg-2.4/include/agg_span_interpolator_linear.h"
|
||
#include "../agg-2.4/include/agg_conv_transform.h"
|
||
#include "../agg-2.4/include/agg_span_image_filter_rgba.h"
|
||
#include "../agg-2.4/include/agg_span_pattern_rgba.h"
|
||
#include "../agg-2.4/include/agg_image_accessors.h"
|
||
#include "../agg-2.4/include/agg_span_allocator.h"
|
||
#include "../agg-2.4/include/agg_image_filters.h"
|
||
|
||
#include "../agg-2.4/include/agg_basics.h"
|
||
|
||
#include "../agg-2.4/include/agg_color_rgba.h"
|
||
#include "../agg-2.4/include/agg_pixfmt_rgba.h"
|
||
#include "../agg-2.4/include/agg_rasterizer_scanline_aa.h"
|
||
#include "../agg-2.4/include/agg_renderer_scanline.h"
|
||
#include "../agg-2.4/include/agg_scanline_u.h"
|
||
|
||
#include "../agg-2.4/include/agg_pixfmt_amask_adaptor.h"
|
||
#include "../agg-2.4/include/agg_scanline_boolean_algebra.h"
|
||
|
||
#include "../agg-2.4/svg/agg_svg_rasterizer.h"
|
||
|
||
#include "Color.h"
|
||
#include "Matrix.h"
|
||
#include "GraphicsLayerBlend.h"
|
||
#include "GraphicsPath.h"
|
||
#include "AlphaMask_p.h"
|
||
#include "Clip.h"
|
||
#include "Brush.h"
|
||
#include "Image.h"
|
||
#include "../fontengine/FontManager.h"
|
||
|
||
#include <stack>
|
||
#include <vector>
|
||
|
||
#if defined(_WIN32) || defined (_WIN64)
|
||
namespace NSStringFormat
|
||
{
|
||
// printf-like formatting using variable arguments parameter
|
||
static std::wstring FormatV(wchar_t* lpszFormat, va_list argList)
|
||
{
|
||
std::wstring s;
|
||
|
||
int sizeBuff = 512 * 2;
|
||
wchar_t* szFormat = NULL;
|
||
int write = -1;
|
||
do
|
||
{
|
||
szFormat = new wchar_t[sizeBuff];
|
||
write = _vsnwprintf(szFormat, sizeBuff - 1, lpszFormat, argList);
|
||
if (write >= 0)
|
||
{
|
||
s = szFormat;
|
||
}
|
||
delete [] szFormat;
|
||
} while (write < 0);
|
||
|
||
return s;
|
||
}
|
||
static std::wstring Format(wchar_t* lpszFormat, ...)
|
||
{
|
||
va_list arglist;
|
||
va_start(arglist, lpszFormat);
|
||
std::wstring s = FormatV(lpszFormat, arglist);
|
||
va_end(arglist);
|
||
return s;
|
||
}
|
||
}
|
||
#endif
|
||
|
||
const double c_ag_Inch_to_MM = 25.4;
|
||
const double c_ag_Inch_to_Point = 72;
|
||
|
||
const long c_ag_CombineModeReplace = 0;
|
||
const long c_ag_CombineModeIntersect = 1;
|
||
const long c_ag_CombineModeUnion = 2;
|
||
const long c_ag_CombineModeXor = 3;
|
||
const long c_ag_CombineModeExclude = 4;
|
||
const long c_ag_CombineModeComplement = 5;
|
||
|
||
const long c_ag_PageUnitPixel = 0;
|
||
const long c_ag_PageUnitPoint = 1;
|
||
const long c_ag_PageUnitInch = 2;
|
||
const long c_ag_PageUnitMillimeter = 3;
|
||
|
||
namespace Aggplus
|
||
{
|
||
typedef agg::rendering_buffer rendering_buffer_type;
|
||
typedef agg::pixfmt_bgra32 pixformat_type;
|
||
|
||
typedef agg::blender_rgba_unpre< agg::svg::color_type, agg::svg::component_order > blender_type;
|
||
typedef agg::comp_op_adaptor_rgba< agg::svg::color_type, agg::svg::component_order > blender_type_comp;
|
||
typedef agg::pixfmt_alpha_blend_rgba< blender_type, agg::rendering_buffer, agg::svg::pixel_type > pixfmt_type;
|
||
typedef agg::pixfmt_custom_blend_rgba< blender_type_comp, agg::rendering_buffer> pixfmt_type_comp;
|
||
|
||
typedef agg::renderer_base<pixfmt_type> base_renderer_type;
|
||
typedef agg::renderer_base<pixfmt_type_comp> comp_renderer_type;
|
||
typedef agg::scanline_u8 scanline_type;
|
||
|
||
typedef agg::span_interpolator_linear<> interpolator_type_linear;
|
||
|
||
typedef agg::span_allocator<agg::rgba8> span_alloc_type;
|
||
|
||
#define def_flag_G_ExtBuffer 0x0001
|
||
#define def_flag_G_FromHDC 0x0002
|
||
|
||
|
||
// Расстояние от центра до контрольных точек Безье для аппроксимации окружности = (4 * (sqrt(2) - 1) / 3) * r
|
||
static const double c_dKappa = ((double)0.55228475);
|
||
static const double c_dKappa_2 = ((double)(0.5 * 0.55228475));
|
||
|
||
// Делим 16-битное значение [0, 255*255] на 255, возвращаем 8-битное значение.
|
||
static inline unsigned char Div255(int nValue)
|
||
{
|
||
return (unsigned char)((nValue + (nValue >> 8) + 0x80) >> 8);
|
||
}
|
||
|
||
//-------------------------------------------------------------------------------------------------------------------------------
|
||
|
||
class CDIB;
|
||
|
||
class CGraphics_ClipStateRecord
|
||
{
|
||
public:
|
||
CGraphicsPath* Path;
|
||
Aggplus::CMatrix* Transform;
|
||
agg::sbool_op_e Operation;
|
||
|
||
public:
|
||
CGraphics_ClipStateRecord()
|
||
{
|
||
Path = NULL;
|
||
Transform = NULL;
|
||
Operation = agg::sbool_and;
|
||
}
|
||
~CGraphics_ClipStateRecord()
|
||
{
|
||
RELEASEOBJECT(Path);
|
||
RELEASEOBJECT(Transform);
|
||
}
|
||
|
||
CGraphics_ClipStateRecord* Clone() const
|
||
{
|
||
CGraphics_ClipStateRecord* pRet = new CGraphics_ClipStateRecord();
|
||
if (Path)
|
||
pRet->Path = Path->Clone();
|
||
if (Transform)
|
||
pRet->Transform = new CMatrix(*Transform);
|
||
pRet->Operation = Operation;
|
||
|
||
return pRet;
|
||
}
|
||
};
|
||
|
||
class CGraphics_ClipState
|
||
{
|
||
public:
|
||
std::vector<CGraphics_ClipStateRecord*> Records;
|
||
|
||
public:
|
||
CGraphics_ClipState()
|
||
{
|
||
}
|
||
CGraphics_ClipState(const CGraphics_ClipState& oSrc)
|
||
{
|
||
for (std::vector<CGraphics_ClipStateRecord*>::const_iterator i = oSrc.Records.begin(); i != oSrc.Records.end(); i++)
|
||
{
|
||
Records.push_back((*i)->Clone());
|
||
}
|
||
}
|
||
~CGraphics_ClipState()
|
||
{
|
||
Clear();
|
||
}
|
||
|
||
void AddRecord(CGraphics_ClipStateRecord* pRecord)
|
||
{
|
||
Records.push_back(pRecord);
|
||
}
|
||
void Clear()
|
||
{
|
||
for (std::vector<CGraphics_ClipStateRecord*>::iterator i = Records.begin(); i != Records.end(); i++)
|
||
{
|
||
CGraphics_ClipStateRecord* pRec = *i;
|
||
RELEASEOBJECT(pRec);
|
||
}
|
||
Records.clear();
|
||
}
|
||
|
||
CGraphics_ClipState* Clone() const
|
||
{
|
||
CGraphics_ClipState* pRet = new CGraphics_ClipState();
|
||
|
||
for (std::vector<CGraphics_ClipStateRecord*>::const_iterator i = Records.begin(); i != Records.end(); i++)
|
||
{
|
||
pRet->Records.push_back((*i)->Clone());
|
||
}
|
||
|
||
return pRet;
|
||
}
|
||
};
|
||
|
||
class CGraphics
|
||
{
|
||
friend class CGlyphImage;
|
||
friend class CMatrix;
|
||
friend class CGraphicsPath;
|
||
friend class CColor;
|
||
friend class CBrush;
|
||
friend class CBrushLinearGradient;
|
||
friend class CBrushTexture;
|
||
friend class CImage;
|
||
friend class CGraphicsRenderer;
|
||
|
||
protected:
|
||
BYTE* m_pPixels;
|
||
|
||
DWORD m_dwConfigFlags;
|
||
|
||
double m_dWidthPix;
|
||
double m_dHeightPix;
|
||
|
||
double m_dDpiX;
|
||
double m_dDpiY;
|
||
|
||
Unit m_ePageUnits;
|
||
|
||
Aggplus::CMatrix m_oCoordTransform;
|
||
Aggplus::CMatrix m_oBaseTransform;
|
||
Aggplus::CMatrix m_oTransform;
|
||
|
||
Aggplus::CMatrix m_oFullTransform;
|
||
|
||
|
||
double m_dClipLeft;
|
||
double m_dClipTop;
|
||
double m_dClipWidth;
|
||
double m_dClipHeight;
|
||
|
||
CClipMulti m_oClip;
|
||
|
||
CAlphaMask* m_pAlphaMask;
|
||
CSoftMask* m_pSoftMask;
|
||
|
||
std::stack<CGraphicsLayer*> m_arLayers;
|
||
|
||
agg::svg::frame_buffer_rgba<blender_type> m_frame_buffer;
|
||
agg::svg::rasterizer m_rasterizer;
|
||
|
||
|
||
#ifdef _WINDOW_GRAPHIS_USE_
|
||
// для отрисовки картинок - используем Gdiplus
|
||
Gdiplus::Graphics* m_pGraphics;
|
||
Gdiplus::Bitmap* m_pBitmap;
|
||
|
||
CGdiPlusInit m_oInitGdiplus;
|
||
#endif
|
||
|
||
CDIB* m_pDib;
|
||
|
||
public:
|
||
|
||
bool m_bIntegerGrid;
|
||
double m_dGlobalAlpha;
|
||
|
||
// for RGBA painting
|
||
bool m_bSwapRGB;
|
||
bool m_bIsDarkMode;
|
||
|
||
double m_dDpiTile;
|
||
|
||
CGraphics_ClipState m_oClipState;
|
||
|
||
int m_nTextRenderMode;
|
||
unsigned int m_nBlendMode;
|
||
|
||
bool m_bIs0PenWidthAs1px;
|
||
|
||
public:
|
||
|
||
CGraphics();
|
||
CGraphics(int dwWidth, int dwHeight, int stride, BYTE* pBuffer);
|
||
CGraphics(CImage* pImage);
|
||
~CGraphics();
|
||
|
||
INT IsDib();
|
||
|
||
Status Create(BYTE* pPixels, int lWidth, int lHeight, int lStride, LONG lPitch);
|
||
Status Create2(BYTE* pPixels, int lWidth, int lHeight, int lStride, LONG lPitch, LONG x, LONG y, LONG w, LONG h, double dW, double dH, CDIB* pDib = NULL);
|
||
Status CreatePart(LONG lLeft, LONG lTop, LONG lWidth, LONG lHeight, CGraphics** ppPart);
|
||
|
||
double GetDpiX();
|
||
double GetDpiY();
|
||
Status SetDpiX(double dDpiX);
|
||
Status SetDpiY(double dDpiY);
|
||
|
||
Status SetPageWidth(double lWidth, LONG lUnit);
|
||
Status SetPageHeight(double lHeight, LONG lUnit);
|
||
|
||
Unit GetPageUnit();
|
||
Status SetPageUnit(Unit lUnits);
|
||
|
||
Aggplus::CMatrix* GetTransform();
|
||
Status SetTransform(CMatrix* pTransform);
|
||
Aggplus::CMatrix* GetBaseTransform();
|
||
Status SetBaseTransform(CMatrix* pTransform);
|
||
Status TranslateTransform(double x, double y, MatrixOrder order = MatrixOrderPrepend);
|
||
Status RotateTransform(double dAngle, MatrixOrder order = MatrixOrderPrepend);
|
||
Status ScaleTransform(double dScaleX, double dScaleY, MatrixOrder order = MatrixOrderPrepend);
|
||
Status ShearTransform(double shearX, double shearY, MatrixOrder order = MatrixOrderPrepend);
|
||
Status MultiplyTransform(CMatrix* pMatrix, MatrixOrder order = MatrixOrderPrepend);
|
||
|
||
// функции отсечения
|
||
Status SetClipRect(double dLeft, double dTop, double dWidth, double dHeight);
|
||
Status SetClipRect2(double dLeft, double dTop, double dWidth, double dHeight);
|
||
Status SetClipRect3(double dLeft, double dTop, double dWidth, double dHeight);
|
||
|
||
Status SetClip(CGraphicsPath* pPath);
|
||
Status ResetClip();
|
||
Status ExclugeClip(CGraphicsPath* pPath);
|
||
Status CombineClip(CGraphicsPath* pPath, agg::sbool_op_e op, NSStructures::CPen* pPen = NULL);
|
||
Status InternalClip(CGraphicsPath* pPath, CMatrix* pTransform, agg::sbool_op_e op, NSStructures::CPen* pPen = NULL);
|
||
|
||
// измерение текста
|
||
INT MeasureString(const std::wstring& strText, CFontManager* pManager, double* lWidth, double* lHeight);
|
||
Status Clear(CColor oColor);
|
||
|
||
Status DrawArc(NSStructures::CPen* pPen, double x, double y, double width, double height, double startAngle, double sweepAngle);
|
||
Status DrawBezier(NSStructures::CPen* pPen, double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4);
|
||
Status DrawBeziers(NSStructures::CPen* pPen, double* pPoints, LONG lCount);
|
||
Status DrawCurve(NSStructures::CPen* pPen, double* pPoints, LONG lCount);
|
||
Status DrawLine(NSStructures::CPen* pPen, double x1, double y1, double x2, double y2);
|
||
Status DrawLines(NSStructures::CPen* pPen, double* pPoints, LONG lCount);
|
||
Status DrawRectangle(NSStructures::CPen* pPen, double x, double y, double width, double height);
|
||
Status DrawEllipse(NSStructures::CPen* pPen, double x, double y, double width, double height);
|
||
Status DrawPath(NSStructures::CPen* pPen, CGraphicsPath* pPath, const double& gamma = -1);
|
||
Status DrawPathNoTransform(NSStructures::CPen* pPen, CGraphicsPath* pPath);
|
||
|
||
// заливка
|
||
Status FillEllipse(CBrush* pBrush, double x, double y, double width, double height);
|
||
Status FillRectangle(CBrush* pBrush, double x, double y, double width, double height);
|
||
Status FillPolygon(CBrush* pBrush, double* pPoints, LONG lCount);
|
||
Status FillPath(CBrush* pBrush, CGraphicsPath* pPath);
|
||
|
||
// отрисовка картинки
|
||
Status DrawImage(CImage* pImage, double x, double y, double width, double height);
|
||
Status DrawMeta(const std::wstring& strFile, double x, double y, double width, double height);
|
||
|
||
#ifdef _WINDOWS_GDIPLUS_USE_
|
||
Status DrawGdiplusImage(Gdiplus::Bitmap* pImage, double x, double y, double width, double height);
|
||
#endif
|
||
|
||
INT DrawImageUnscaled(CImage* pImage, double x, double y);
|
||
|
||
// отрисовка текста
|
||
INT DrawString(const std::wstring& strText, CFontManager* pFont, CBrush* pBrush, double x, double y);
|
||
INT DrawString(const unsigned int* pGids, const unsigned int nGidsCount, CFontManager* pFont, CBrush* pBrush, double x, double y);
|
||
INT DrawStringC(const LONG& lText, CFontManager* pFont, CBrush* pBrush, double x, double y);
|
||
INT DrawStringPath(const std::wstring& strText, CFontManager* pFont, CBrush* pBrush, double x, double y);
|
||
INT DrawStringPathC(const LONG& lText, CFontManager* pFont, CBrush* pBrush, double x, double y);
|
||
|
||
//Работа с альфа-маской
|
||
Status SetAlphaMask(CAlphaMask* pAlphaMask);
|
||
Status StartCreatingAlphaMask();
|
||
Status EndCreatingAlphaMask();
|
||
Status ResetAlphaMask();
|
||
|
||
CSoftMask* CreateSoftMask(bool bAlpha);
|
||
Status SetSoftMask(CSoftMask* pSoftMask);
|
||
|
||
//Работа со слоями
|
||
Status AddLayer(CGraphicsLayer* pGraphicsLayer);
|
||
Status CreateLayer();
|
||
Status BlendLayer();
|
||
Status RemoveLayer();
|
||
|
||
Status SetLayerSettings(const TGraphicsLayerSettings& oSettings);
|
||
Status SetLayerOpacity(double dOpacity);
|
||
|
||
void CalculateFullTransform();
|
||
bool IsClip();
|
||
|
||
inline Aggplus::CMatrix* GetFullTransform() { return &m_oFullTransform; }
|
||
inline Aggplus::CMatrix* GetCoordTransform() { return &m_oCoordTransform; }
|
||
|
||
inline double GetPixW() { return m_dWidthPix; }
|
||
inline double GetPixH() { return m_dHeightPix; }
|
||
|
||
protected:
|
||
|
||
template<class Renderer>
|
||
void render_scanlines(Renderer& ren);
|
||
template<class Rasterizer, class Renderer>
|
||
void render_scanlines_2(Rasterizer& ras, Renderer& ren);
|
||
template<class Renderer>
|
||
void render_scanlines_alpha(Renderer& ren, BYTE Alpha);
|
||
template<class Rasterizer, class Renderer, class Scanline>
|
||
void render_scanlines_3(Rasterizer& ras, Renderer& ren, Scanline& sl);
|
||
|
||
void DoFillPathSolid(CColor dwColor);
|
||
void DoFillPathGradient(CBrushLinearGradient *pBrush);
|
||
void DoFillPathGradient2(CBrushLinearGradient *pBrush);
|
||
//--Test
|
||
void DoFillPathGradientType(CBrushLinearGradient *pBrush);
|
||
//--test
|
||
void DoFillPathHatch(CBrushHatch *pBrush);
|
||
void DoFillPathTextureClampSz(const CMatrix &mImgMtx, const void *pImgBuff, DWORD dwImgWidth, DWORD dwImgHeight, int nImgStride);
|
||
void DoFillPathTextureClampSz2(const CMatrix &mImgMtx, const void *pImgBuff, DWORD dwImgWidth, DWORD dwImgHeight, int nImgStride, BYTE Alpha = 255);
|
||
|
||
template<class ColorSpacePix>
|
||
void DoFillPathTextureClampSz3(const CMatrix &mImgMtx, const void *pImgBuff, DWORD dwImgWidth, DWORD dwImgHeight, int nImgStride, Aggplus::WrapMode wrapmode, BYTE Alpha = 255);
|
||
|
||
void DoFillPath(const CBrush* Brush);
|
||
template<class Rasterizer>
|
||
agg::trans_affine* DoStrokePath(NSStructures::CPen* pPen, CGraphicsPath* pPath, Rasterizer* ras);
|
||
|
||
// text methods
|
||
int FillGlyph2(int nX, int nY, TGlyph* pGlyph, Aggplus::CBrush* pBrush);
|
||
int FillGlyphSimple(int nX, int nY, LONG lWidth, LONG lHeight, BYTE* pData, Aggplus::CBrush* pBrush);
|
||
|
||
void PrepareScanlineStorage(agg::scanline_storage_aa8* storage, int x, int y, TGlyphBitmap *pGlyph);
|
||
|
||
void UpdateUnits();
|
||
|
||
//test
|
||
|
||
void ScaleGranientInfo(long Type, NSStructures::GradientInfo &ginfo);
|
||
void ScaleCoords(float &x, float &y);
|
||
};
|
||
}
|
||
|
||
#endif // _BUILD_GRAPHICS_H_
|