From 4a4a05fd8a83d99a90a70a793b8f9578fe74a973 Mon Sep 17 00:00:00 2001 From: Kirill Poljakov Date: Tue, 23 May 2023 22:23:00 +0300 Subject: [PATCH] Added partial support for record Mask in svg-reader --- Common/3dParty/html/css/src/StaticFunctions.h | 3 ++ DesktopEditor/graphics/pro/metafile.pri | 2 + .../raster/Metafile/svg/CSvgParser.cpp | 6 ++- .../Metafile/svg/SvgObjects/CClipPath.cpp | 7 +++- .../Metafile/svg/SvgObjects/CContainer.h | 2 + .../raster/Metafile/svg/SvgObjects/CImage.cpp | 39 +++++++++++++----- .../raster/Metafile/svg/SvgObjects/CMask.cpp | 29 ++++++++++++++ .../raster/Metafile/svg/SvgObjects/CMask.h | 17 ++++++++ .../Metafile/svg/SvgObjects/CObjectBase.cpp | 40 +++++++++---------- .../Metafile/svg/SvgObjects/CObjectBase.h | 13 +++--- 10 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.cpp create mode 100644 DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.h diff --git a/Common/3dParty/html/css/src/StaticFunctions.h b/Common/3dParty/html/css/src/StaticFunctions.h index 7c337a2f1f..9cc28f989e 100644 --- a/Common/3dParty/html/css/src/StaticFunctions.h +++ b/Common/3dParty/html/css/src/StaticFunctions.h @@ -364,6 +364,9 @@ namespace NSCSS mRules.insert({std::wstring(oStartProperty, oEndProperty), std::wstring(oStartValue, oEndValue)}); + if (wsStyles.end() == oEndValue) + break; + oStartProperty = std::find_if_not(oEndValue + 1, wsStyles.end(), std::iswspace); } diff --git a/DesktopEditor/graphics/pro/metafile.pri b/DesktopEditor/graphics/pro/metafile.pri index 3e23dea1cc..719c299c9b 100644 --- a/DesktopEditor/graphics/pro/metafile.pri +++ b/DesktopEditor/graphics/pro/metafile.pri @@ -76,6 +76,7 @@ METAFILE_PATH = $$PWD/../../raster/Metafile $$METAFILE_PATH/svg/SvgObjects/CContainer.h \ $$METAFILE_PATH/svg/SvgObjects/CGradient.h \ $$METAFILE_PATH/svg/SvgObjects/CClipPath.h \ + $$METAFILE_PATH/svg/SvgObjects/CMask.h \ $$METAFILE_PATH/svg/SvgObjects/CDefs.h \ $$METAFILE_PATH/svg/SvgObjects/CPattern.h \ $$METAFILE_PATH/svg/SvgObjects/CMarker.h \ @@ -100,6 +101,7 @@ METAFILE_PATH = $$PWD/../../raster/Metafile $$METAFILE_PATH/svg/SvgObjects/CContainer.cpp \ $$METAFILE_PATH/svg/SvgObjects/CGradient.cpp \ $$METAFILE_PATH/svg/SvgObjects/CClipPath.cpp \ + $$METAFILE_PATH/svg/SvgObjects/CMask.cpp \ $$METAFILE_PATH/svg/SvgObjects/CDefs.cpp \ $$METAFILE_PATH/svg/SvgObjects/CMarker.cpp \ $$METAFILE_PATH/svg/SvgObjects/CPattern.cpp \ diff --git a/DesktopEditor/raster/Metafile/svg/CSvgParser.cpp b/DesktopEditor/raster/Metafile/svg/CSvgParser.cpp index fadcb0c5e1..cb480f629f 100644 --- a/DesktopEditor/raster/Metafile/svg/CSvgParser.cpp +++ b/DesktopEditor/raster/Metafile/svg/CSvgParser.cpp @@ -20,6 +20,7 @@ #include "SvgObjects/CLine.h" #include "SvgObjects/CPath.h" #include "SvgObjects/CText.h" +#include "SvgObjects/CMask.h" #include "SvgObjects/CUse.h" namespace SVG @@ -180,6 +181,8 @@ namespace SVG pDefObject = CreateAndReadChildrens(oElement, pFile); else if (L"marker" == wsElementName) pDefObject = CreateAndReadChildrens(oElement, pFile); + else if (L"mask" == wsElementName) + pDefObject = CreateAndReadChildrens(oElement, pFile); return AddObject(pDefObject, pDefs, pFile); } @@ -225,7 +228,8 @@ namespace SVG bool CSvgParser::IsDefs(const std::wstring &wsNodeName) const { - return L"defs" == wsNodeName || L"pattern" == wsNodeName || L"clipPath" == wsNodeName || L"linearGradient" == wsNodeName || L"radialGradient" == wsNodeName || L"marker" == wsNodeName; + return L"defs" == wsNodeName || L"pattern" == wsNodeName || L"clipPath" == wsNodeName || L"linearGradient" == wsNodeName || + L"radialGradient" == wsNodeName || L"marker" == wsNodeName || L"mask" == wsNodeName; } template diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CClipPath.cpp b/DesktopEditor/raster/Metafile/svg/SvgObjects/CClipPath.cpp index b75df03483..a0720418c2 100644 --- a/DesktopEditor/raster/Metafile/svg/SvgObjects/CClipPath.cpp +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CClipPath.cpp @@ -16,11 +16,16 @@ namespace SVG if (NULL == pRenderer || NULL == pDefs) return false; - CGraphicsContainer::Apply(pRenderer, &m_oStyles.m_oClip, pDefs); + pRenderer->BeginCommand(c_nClipType); + pRenderer->PathCommandStart(); for (const CSvgGraphicsObject* pGraphicsObject : m_arObjects) pGraphicsObject->Draw(pRenderer, pDefs, true); + pRenderer->EndCommand(c_nClipType); + pRenderer->PathCommandEnd(); + + return true; } } diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CContainer.h b/DesktopEditor/raster/Metafile/svg/SvgObjects/CContainer.h index 5c9b07927a..c528f1021b 100644 --- a/DesktopEditor/raster/Metafile/svg/SvgObjects/CContainer.h +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CContainer.h @@ -66,6 +66,7 @@ namespace SVG friend class CDefs; friend class CText; + friend class CMask; friend class CTSpan; friend class CMarker; friend class CPattern; @@ -95,6 +96,7 @@ namespace SVG friend class CPattern; friend class CMarker; + friend class CMask; TRect m_oWindow; TRect m_oViewBox; diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CImage.cpp b/DesktopEditor/raster/Metafile/svg/SvgObjects/CImage.cpp index b2967ce667..ba57683f20 100644 --- a/DesktopEditor/raster/Metafile/svg/SvgObjects/CImage.cpp +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CImage.cpp @@ -22,11 +22,12 @@ namespace SVG { SetTransform(mAttributes, ushLevel, bHardMode); SetClip(mAttributes, ushLevel, bHardMode); + SetMask(mAttributes, ushLevel, bHardMode); } bool CImage::Draw(IRenderer *pRenderer, const CDefs *pDefs, bool bIsClip, const TSvgStyles *pOtherStyles) const { - if (NULL == pRenderer || m_wsHref.empty() || bIsClip) + if (NULL == pRenderer || m_wsHref.empty()) return false; TBounds oBounds = (NULL != m_pParent) ? m_pParent->GetBounds() : TBounds{0., 0., 0., 0.}; @@ -61,28 +62,46 @@ namespace SVG Aggplus::CImage oImage; oImage.Create(oBgraFrame.get_Data(), dImageW, dImageH, -4 * dImageW, true); - if (dImageW / dImageH == dWidth / dHeight) - pRenderer->DrawImage(&oImage, dX, dY, dWidth, dHeight); - else if (dImageW / dWidth > dImageH / dHeight) + StartPath(pRenderer, pDefs, bIsClip); + + Aggplus::CMatrix oOldMatrix; + Apply(pRenderer, &m_oStyles.m_oTransform, oOldMatrix); + + if (dImageW / dWidth > dImageH / dHeight) { double dValue = dImageW / dWidth; - pRenderer->DrawImage(&oImage, dX, dY + (dHeight - (dImageH / dValue)) / 2, dWidth, dImageH / dValue); + dY += (dHeight - (dImageH / dValue)) / 2.; + dHeight = dImageH / dValue; } - else + else if (dImageW / dWidth < dImageH / dHeight) { double dValue = dImageH / dHeight; - pRenderer->DrawImage(&oImage, dX + (dWidth - (dImageW / dValue)) / 2, dY, dImageW / dValue, dHeight); + dX += (dWidth - (dImageW / dValue)) / 2.; + dWidth = dImageW / dValue; } + if (!bIsClip) + pRenderer->DrawImage(&oImage, dX, dY, dWidth, dHeight); + else + { + pRenderer->PathCommandMoveTo(dX, dY); + pRenderer->PathCommandLineTo(dX + dWidth, dY); + pRenderer->PathCommandLineTo(dX + dWidth, dY + dHeight); + pRenderer->PathCommandLineTo(dX, dY + dHeight); + pRenderer->PathCommandClose(); + } + + EndPath(pRenderer, pDefs, bIsClip, pOtherStyles); + + pRenderer->SetTransform(oOldMatrix.sx(), oOldMatrix.shy(), oOldMatrix.shx(), oOldMatrix.sy(), oOldMatrix.tx(), oOldMatrix.ty()); + delete[] pBuffer; } return true; } void CImage::ApplyStyle(IRenderer *pRenderer, const TSvgStyles *pStyles, const CDefs *pDefs, int &nTypePath, Aggplus::CMatrix &oOldMatrix) const - { - Apply(pRenderer, &pStyles->m_oTransform, oOldMatrix); - } + {} TBounds CImage::GetBounds() const { diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.cpp b/DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.cpp new file mode 100644 index 0000000000..66e20e73b1 --- /dev/null +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.cpp @@ -0,0 +1,29 @@ +#include "CMask.h" + +namespace SVG +{ + CMask::CMask(XmlUtils::CXmlNode &oNode, CSvgGraphicsObject *pParent, NSFonts::IFontManager *pFontManager) + : CClipPath(oNode, pParent, pFontManager) + { + + } + + bool CMask::Apply(IRenderer *pRenderer, const CDefs *pDefs, const TBounds &oObjectBounds) + { + if (NULL == pRenderer || NULL == pDefs) + return false; + + CGraphicsContainer::ApplyMask(pRenderer, &m_oStyles.m_oMask, pDefs); + + pRenderer->BeginCommand(c_nClipType); + pRenderer->PathCommandStart(); + + for (const CSvgGraphicsObject* pGraphicsObject : m_arObjects) + pGraphicsObject->Draw(pRenderer, pDefs, true); + + pRenderer->EndCommand(c_nClipType); + pRenderer->PathCommandEnd(); + + return true; + } +} diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.h b/DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.h new file mode 100644 index 0000000000..1536917a8b --- /dev/null +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CMask.h @@ -0,0 +1,17 @@ +#ifndef CMASK_H +#define CMASK_H + +#include "CClipPath.h" + +namespace SVG +{ + class CMask : public CClipPath + { + public: + CMask(XmlUtils::CXmlNode& oNode, CSvgGraphicsObject* pParent = NULL, NSFonts::IFontManager *pFontManager = NULL); + + bool Apply(IRenderer* pRenderer, const CDefs *pDefs, const TBounds &oObjectBounds) override; + }; +} + +#endif // CMASK_H diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp index 8d4ebabb01..9cea5e1938 100644 --- a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.cpp @@ -61,31 +61,29 @@ namespace SVG m_oStyles.m_oClip.m_oRule.SetValue(mAttributes.at(L"clip-rule"), std::vector{L"nonzero", L"evenodd"}, ushLevel, bHardMode); } + void CSvgGraphicsObject::SetMask(const std::map &mAttributes, unsigned short ushLevel, bool bHardMode) + { + if (mAttributes.end() != mAttributes.find(L"mask")) + m_oStyles.m_oMask.SetValue(mAttributes.at(L"mask"), ushLevel, bHardMode); + } + void CSvgGraphicsObject::StartPath(IRenderer *pRenderer, const CDefs *pDefs, bool bIsClip) const { Apply(pRenderer, &m_oStyles.m_oClip, pDefs); - (bIsClip) ? StartClipPath(pRenderer) : StartStandardPath(pRenderer); - } + ApplyMask(pRenderer, &m_oStyles.m_oMask, pDefs); + + if (bIsClip) + return; - void CSvgGraphicsObject::StartStandardPath(IRenderer *pRenderer) const - { pRenderer->BeginCommand(c_nPathType); pRenderer->PathCommandStart(); } - void CSvgGraphicsObject::StartClipPath(IRenderer *pRenderer) const - { - pRenderer->BeginCommand(c_nClipType); - pRenderer->PathCommandStart(); - } - void CSvgGraphicsObject::EndPath(IRenderer *pRenderer, const CDefs *pDefs, bool bIsClip, const TSvgStyles* pOtherStyles) const { - (bIsClip) ? EndClipPath(pRenderer) : EndStandardPath(pRenderer, pDefs, pOtherStyles); - } + if (bIsClip) + return; - void CSvgGraphicsObject::EndStandardPath(IRenderer *pRenderer, const CDefs *pDefs, const TSvgStyles *pOtherStyles) const - { int nPathType = 0; Aggplus::CMatrix oOldMatrix(1., 0., 0., 1., 0, 0); @@ -105,12 +103,6 @@ namespace SVG pRenderer->SetTransform(oOldMatrix.sx(), oOldMatrix.shy(), oOldMatrix.shx(), oOldMatrix.sy(), oOldMatrix.tx(), oOldMatrix.ty()); } - void CSvgGraphicsObject::EndClipPath(IRenderer *pRenderer) const - { - pRenderer->EndCommand(c_nClipType); - pRenderer->PathCommandEnd(); - } - bool CSvgGraphicsObject::Apply(IRenderer *pRenderer, const TStroke *pStroke, bool bUseDefault) const { if (NULL == pRenderer || NULL == pStroke || NSCSS::NSProperties::ColorType::ColorNone == pStroke->m_oColor.GetType() || (!bUseDefault && ((pStroke->m_oWidth.Empty() || pStroke->m_oWidth.Zero()) && pStroke->m_oColor.Empty()))) @@ -229,6 +221,14 @@ namespace SVG return pClipObject->Apply(pRenderer, pDefs, GetBounds()); } + bool CSvgGraphicsObject::ApplyMask(IRenderer *pRenderer, const NSCSS::NSProperties::CColor *pMask, const CDefs *pDefs) const + { + if (NULL == pRenderer || NULL == pMask || NULL == pDefs || NSCSS::NSProperties::ColorType::ColorUrl != pMask->GetType()) + return false; + + return ApplyDef(pRenderer, pDefs, pMask->ToWString()); + } + bool CSvgGraphicsObject::ApplyDef(IRenderer *pRenderer, const CDefs *pDefs, const std::wstring &wsUrl) const { if (NULL == pRenderer || NULL == pDefs || wsUrl.empty()) diff --git a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h index 348f6d7620..7470b1be1b 100644 --- a/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h +++ b/DesktopEditor/raster/Metafile/svg/SvgObjects/CObjectBase.h @@ -16,7 +16,8 @@ namespace SVG SvgColor m_oFill; TStroke m_oStroke; SvgTransform m_oTransform; - TClip m_oClip; + TClip m_oClip; + SvgColor m_oMask; TSvgStyles& operator+=(const TSvgStyles& oSvgStyles) { @@ -43,6 +44,9 @@ namespace SVG if (m_oClip.m_oRule.Empty() && !oSvgStyles.m_oClip.m_oRule.Empty()) m_oClip.m_oRule = oSvgStyles.m_oClip.m_oRule; + if (m_oMask.Empty() && !oSvgStyles.m_oMask.Empty() && NSCSS::NSProperties::ColorUrl == oSvgStyles.m_oMask.GetType()) + m_oMask= oSvgStyles.m_oMask; + return *this; } }; @@ -136,13 +140,10 @@ namespace SVG void SetFill(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); void SetTransform(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); void SetClip(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); + void SetMask(const std::map& mAttributes, unsigned short ushLevel, bool bHardMode = false); void StartPath(IRenderer* pRenderer, const CDefs *pDefs, bool bIsClip) const; - void StartStandardPath(IRenderer* pRenderer) const; - void StartClipPath(IRenderer* pRenderer) const; void EndPath(IRenderer* pRenderer, const CDefs *pDefs, bool bIsClip, const TSvgStyles* pOtherStyles = NULL) const; - void EndStandardPath(IRenderer* pRenderer, const CDefs *pDefs, const TSvgStyles* pOtherStyles) const; - void EndClipPath(IRenderer* pRenderer) const; virtual void ApplyStyle(IRenderer* pRenderer, const TSvgStyles* pStyles, const CDefs *pDefs, int& nTypePath, Aggplus::CMatrix& oOldMatrix) const = 0; @@ -151,12 +152,14 @@ namespace SVG bool Apply(IRenderer* pRenderer, const SvgTransform* pTransform, Aggplus::CMatrix& oOldMatrix) const; bool Apply(IRenderer* pRenderer, const TClip* pClip, const CDefs *pDefs) const; + bool ApplyMask(IRenderer* pRenderer, const SvgColor* pMask, const CDefs *pDefs) const; bool ApplyDef(IRenderer* pRenderer, const CDefs *pDefs, const std::wstring& wsUrl) const; friend class CUse; friend class CLine; friend class CRect; friend class CPath; + friend class CMask; friend class CTSpan; friend class CImage; friend class CCircle;