#include "CSvgParser.h" #include #include #include "CSvgFile.h" #include "SvgObjects/CPolyline.h" #include "SvgObjects/CGradient.h" #include "SvgObjects/CClipPath.h" #include "SvgObjects/CPattern.h" #include "SvgObjects/CEllipse.h" #include "SvgObjects/CSymbol.h" #include "SvgObjects/CSwitch.h" #include "SvgObjects/CMarker.h" #include "SvgObjects/CCircle.h" #include "SvgObjects/CStyle.h" #include "SvgObjects/CImage.h" #include "SvgObjects/CRect.h" #include "SvgObjects/CLine.h" #include "SvgObjects/CPath.h" #include "SvgObjects/CFont.h" #include "SvgObjects/CText.h" #include "SvgObjects/CMask.h" #include "SvgObjects/CUse.h" #include "../../../../Common/3dParty/html/css/src/StaticFunctions.h" namespace SVG { CSvgParser::CSvgParser(NSFonts::IFontManager* pFontManager) : m_pFontManager(pFontManager) {} CSvgParser::~CSvgParser() {} void CSvgParser::SetFontManager(NSFonts::IFontManager *pFontManager) { m_pFontManager = pFontManager; } std::string FindEncoding(const std::string& wsContent) { size_t unEncodingBegin = wsContent.find("encoding"); if (std::string::npos == unEncodingBegin) return std::string(); unEncodingBegin += 8; while (unEncodingBegin < wsContent.length() && std::isspace(wsContent[unEncodingBegin])) ++unEncodingBegin; if (unEncodingBegin >= wsContent.length() || '=' != wsContent[unEncodingBegin++]) return std::string(); while (unEncodingBegin < wsContent.length() && std::isspace(wsContent[unEncodingBegin])) ++unEncodingBegin; if (unEncodingBegin >= wsContent.length() || ('\'' != wsContent[unEncodingBegin] && '"' != wsContent[unEncodingBegin])) return std::string(); std::string::const_iterator itEncodingValueBegin = std::find_if(wsContent.cbegin() + unEncodingBegin + 1, wsContent.cend(), [](char chElement){ return !isspace(chElement);}); if (wsContent.cend() == itEncodingValueBegin) return std::string(); std::string::const_iterator itEncodingValueEnd = std::find_if(itEncodingValueBegin, wsContent.cend(), [](char chElement){ return isspace(chElement) || '\'' == chElement || '\"' == chElement;}); if (wsContent.cend() == itEncodingValueEnd) return std::string(); return std::string(itEncodingValueBegin, itEncodingValueEnd); } bool CSvgParser::LoadFromFile(const std::wstring &wsFile, CGraphicsContainer*& pContainer, CSvgFile* pFile) const { if (wsFile.empty() || NULL == pFile) return false; std::string sXml; if (!NSFile::CFileBinary::ReadAllTextUtf8A(wsFile, sXml)) return false; size_t unFoundBegin = sXml.find("(oReader, pFile); if (NULL == pContainer) return false; return ReadChildrens(oReader, pContainer, pFile, pContainer); } bool CSvgParser::ScanStyles(CSvgReader& oReader, CSvgFile *pFile) const { if (oReader.IsEmptyNode() || NULL == pFile) return false; const std::string sElementName = oReader.GetName(); if ("style" == sElementName) { ParseStyles(oReader.GetText(), pFile); return true; } bool bScanResult = false; if ("svg" == sElementName || "g" == sElementName || "defs" == sElementName) { WHILE_READ_NEXT_NODE(oReader) { if (ScanStyles(oReader, pFile)) bScanResult = true; } END_WHILE } return bScanResult; } void CSvgParser::ParseStyles(const std::wstring &wsStyles, CSvgFile *pFile) const { if (NULL == pFile) return; pFile->AddStyles(wsStyles); std::wregex oRegex(L"@font-face\\s*(\\{[^}]*\\})"); std::wsmatch oMatch; std::wstring::const_iterator oSearchStart(wsStyles.cbegin()); while (std::regex_search(oSearchStart, wsStyles.cend(), oMatch, oRegex)) { if (oMatch[1].str().empty()) continue; std::wstring wsValue{oMatch[1].str()}; std::wstring::const_iterator itStart = std::find_if(wsValue.cbegin(), wsValue.cend(), [](const wchar_t& wChar) { return !std::iswspace(wChar) && L'{' != wChar; }); std::wstring::const_reverse_iterator itEnd = std::find_if(wsValue.crbegin(), wsValue.crend(), [](const wchar_t& wChar) { return !std::iswspace(wChar) && L'}' != wChar; }); if (wsValue.cend() != itStart && wsValue.crend() != itEnd) wsValue = std::wstring(itStart, itEnd.base()); const std::vector arWords{NSCSS::NS_STATIC_FUNCTIONS::GetWordsW(wsValue, true, L":;")}; SvgURL oURL; TFontArguments m_oArguments; for (unsigned int unIndex = 0; unIndex < arWords.size(); ++unIndex) { if (arWords[unIndex].length() > 3 && L"src" == arWords[unIndex].substr(0, 3) && L':' == arWords[unIndex].back() && unIndex + 1 < arWords.size() && oURL.SetValue(arWords[++unIndex])) { continue; } else if (arWords[unIndex].length() > 11 && L"font-family" == arWords[unIndex].substr(0, 11) && L':' == arWords[unIndex].back() && unIndex + 1 < arWords.size()) { const std::vector arFontFamily{NSCSS::NS_STATIC_FUNCTIONS::GetWordsW(arWords[++unIndex], false, L"\"\',;")}; if (arFontFamily.empty()) continue; m_oArguments.m_wsFontFamily = arFontFamily.back(); } } if (!oURL.Empty() && !m_oArguments.m_wsFontFamily.empty()) pFile->AddFontFace(m_oArguments, oURL.GetValue()); oSearchStart = oMatch.suffix().first; } } template bool CSvgParser::ReadObject(CSvgReader& oReader, CContainer *pContainer, CSvgFile *pFile, CRenderedObject *pParent) const { if (NULL == pFile) return false; const std::string sElementName = oReader.GetName(); CObject *pObject = NULL; if ("svg" == sElementName || "g" == sElementName || "a" == sElementName) { pObject = CObject::Create(oReader, pFile, pParent); if (!ReadChildrens(oReader, (CGraphicsContainer*)pObject, pFile, (CGraphicsContainer*)pObject)) { RELEASEINTERFACE(pObject); return false; } } else if ("line" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("rect" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("circle" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("ellipse" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("path" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("polyline" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("polygon" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("image" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("use" == sElementName) pObject = CObject::Create(oReader, pFile, pParent); else if ("text" == sElementName) pObject = CObject::Create(oReader, pFile, pParent, m_pFontManager); else if ("tspan" == sElementName) pObject = CObject::Create(oReader, pFile, pParent, m_pFontManager); else if ("textPath" == sElementName) pObject = CObject::Create(oReader, pFile, pParent, m_pFontManager); else if ("switch" == sElementName) { pObject = CObject::Create(oReader, pFile, pParent); ReadChildrens(oReader, (CSwitch*)pObject, pFile); } //defs else if ("defs" == sElementName) return ReadChildrens(oReader, NULL, pFile); else if("linearGradient" == sElementName) pObject = CObject::Create(oReader, pFile); else if ("radialGradient" == sElementName) pObject = CObject::Create(oReader, pFile); else if ("pattern" == sElementName) { pObject = CObject::Create(oReader, pFile); ReadChildrens(oReader, (CGraphicsContainer*)(&((CPattern*)pObject)->GetContainer()), pFile); } else if ("clipPath" == sElementName) { pObject = CObject::Create(oReader, pFile); ReadChildrens(oReader, (CGraphicsContainer*)(&((CClipPath*)pObject)->GetContainer()), pFile); } else if ("marker" == sElementName) { pObject = CObject::Create(oReader, pFile); ReadChildrens(oReader, (CMarker*)pObject, pFile); } else if ("mask" == sElementName) { pObject = CObject::Create(oReader, pFile); ReadChildrens(oReader, (CGraphicsContainer*)(&((CMask*)pObject)->GetContainer()), pFile); } else if ("symbol" == sElementName) { pObject = CObject::Create(oReader, pFile); if (ReadChildrens(oReader, (CSymbol*)pObject, pFile)) return true; else RELEASEINTERFACE(pObject); } else if ("font" == sElementName) { pObject = CObject::Create(oReader, pFile, pFile); } if (NULL == pObject) return false; if ((RendererObject == pObject->GetType() && (AddObject((ObjectType*)pObject, pContainer) || pObject->Marked())) || AppliedObject == pObject->GetType()) return true; RELEASEINTERFACE(pObject); return false; } template bool CSvgParser::AddObject(ObjectType *pObject, CContainer *pContainer) const { return (NULL != pContainer && pContainer->AddObject(pObject)); } template bool CSvgParser::ReadChildrens(CSvgReader& oReader, CContainer* pContainer, CSvgFile* pFile, CRenderedObject *pParent) const { bool bResult = false; WHILE_READ_NEXT_NODE(oReader) if (ReadObject(oReader, pContainer, pFile, pParent)) bResult = true; END_WHILE return bResult; } }