/* * (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 * */ #include "SpTreeElem.h" #include "Shape.h" #include "Pic.h" #include "CxnSp.h" #include "SpTree.h" #include "GraphicFrame.h" #include "Effects/AlphaModFix.h" #include "Effects/Duotone.h" #include "../SlideMaster.h" #include "../../DocxFormat/Media/Audio.h" #include "../../DocxFormat/Media/Video.h" #include "../../DocxFormat/Media/ActiveX.h" #include "../../DocxFormat/Logic/Pict.h" namespace PPTX { namespace Logic { std::wstring GetHexColor(const DWORD& ARGB) { BYTE r = (BYTE)((ARGB >> 16) & 0xFF); BYTE g = (BYTE)((ARGB >> 8) & 0xFF); BYTE b = (BYTE)((ARGB & 0xFF)); std::wstringstream sstream; sstream << boost::wformat(L"%02X%02X%02X") % r % g % b; return L"#" + sstream.str(); } void CalculateFill(BYTE lDocType, PPTX::Logic::SpPr& oSpPr, nullable& pShapeStyle, NSCommon::smart_ptr& oTheme, NSCommon::smart_ptr& oClrMap, NSCommon::smart_ptr& pContainer, std::wstring& strAttr, std::wstring& strNode, bool bOle, bool bSignature) { PPTX::Logic::UniFill fill; DWORD ARGB = 0; if (pShapeStyle.is_init() && oTheme.is_init()) { oTheme->GetFillStyle(pShapeStyle->fillRef.idx.get_value_or(0), fill); if (pShapeStyle->fillRef.Color.is_init()) { if (fill.is()) { fill.as().Color = pShapeStyle->fillRef.Color; } } ARGB = pShapeStyle->fillRef.Color.GetRGBColor(oTheme, oClrMap, ARGB); } if (oSpPr.Fill.is_init()) oSpPr.Fill.Merge(fill); if (fill.is()) { BlipFill& oBlip = fill.as(); if (oBlip.blip.is_init() && oBlip.blip->embed.is_init()) { std::wstring color2; std::wstring fopacity; std::wstring sType = oBlip.tile.IsInit() ? L"tile" : L"frame"; size_t eff_count = oBlip.blip->Effects.size(); for (size_t eff = 0; eff < eff_count; ++eff) { if (oBlip.blip->Effects[eff].is()) { PPTX::Logic::AlphaModFix& oAlpha = oBlip.blip->Effects[eff].as(); if (oAlpha.amt.is_init()) { double dA = (double)(oAlpha.amt.get()); dA = (dA * 65536 / 100000); int nA = (int)(dA + 0.5); if (nA < 0) nA = 0; if (nA > 65536) nA = 65536; fopacity = L" opacity=\"" + std::to_wstring(nA) + L"f\""; } } else if (oBlip.blip->Effects[eff].is()) { PPTX::Logic::Duotone& oDuotone = oBlip.blip->Effects[eff].as(); if (oDuotone.Colors.size() > 1) { sType = L"pattern"; ARGB = oDuotone.Colors[0].GetRGBColor(oTheme, oClrMap, ARGB); color2 = L" color2=\"" + GetHexColor(ARGB) + L"\""; ARGB = oDuotone.Colors[1].GetRGBColor(oTheme, oClrMap, ARGB); strAttr += L" fillcolor=\"" + GetHexColor(ARGB) + L"\""; } } } std::wstring strId = oBlip.blip->embed->ToString(); NSCommon::smart_ptr pImageFileVml(new OOX::Image(NULL, false)); pImageFileVml->set_filename(oBlip.blip->imageFilepath, false); smart_ptr pFileVml = pImageFileVml.smart_dynamic_cast(); if (pContainer.IsInit()) { pContainer->Add(strId, pFileVml); } if (XMLWRITER_DOC_TYPE_XLSX == lDocType) { strId = L"o:relid=\"" + strId + L"\""; } else { strId = L"r:id=\"" + strId + L"\""; } if (bOle || bSignature) { strAttr = L" filled=\"f\""; strNode = L""; } else { strNode = L""; } } } else if (fill.is()) { ARGB = fill.as().Color.GetRGBColor(oTheme, oClrMap, ARGB); strAttr = L" fillcolor=\"" + GetHexColor(ARGB) + L"\""; BYTE A = (BYTE)((ARGB >> 24) & 0xFF); if (A != 255) { int fopacity = (int)((double)A / 255. * 65536.); strNode = L""; } } else if (fill.is()) { GradFill& oGrad = fill.as(); std::wstring sType = L"gradient"; std::wstring sColors; std::wstring sColor; std::wstring sColor2; std::wstring sOpacity; std::wstring sOpacity2; std::wstring sAngle; std::wstring sFocus = L"100%"; std::wstring sFocusPosition = L""; std::wstring sFillNode; if (oGrad.lin.IsInit()) { if (oGrad.lin->ang.IsInit()) { int ang = *oGrad.lin->ang / 60000; sAngle = std::to_wstring(ang > 180 ? ang - 360 : ang); } if (oGrad.lin->scaled.IsInit()) { } } else if (oGrad.path.IsInit()) { sType = L"gradientRadial"; double focusposition_x = 0.5, focusposition_y = 0.5; if (oGrad.path->rect.IsInit()) { double l = XmlUtils::GetInteger(oGrad.path->rect->l.get_value_or(L"")) / 100.; double r = XmlUtils::GetInteger(oGrad.path->rect->r.get_value_or(L"")) / 100.; double t = XmlUtils::GetInteger(oGrad.path->rect->t.get_value_or(L"")) / 100.; double b = XmlUtils::GetInteger(oGrad.path->rect->b.get_value_or(L"")) / 100.; focusposition_y += (t - b) / 2.; focusposition_x += (l - r) / 2.; } sFocusPosition = XmlUtils::DoubleToString(focusposition_x, L"%.2f") + L"," + XmlUtils::DoubleToString(focusposition_y, L"%.2f"); sFillNode = L""; } for (size_t i = 0; i < oGrad.GsLst.size(); ++i) { std::wstring col, op, pos; ARGB = oGrad.GsLst[i].color.GetRGBColor(oTheme, oClrMap, ARGB); col = GetHexColor(ARGB); BYTE A = (BYTE)((ARGB >> 24) & 0xFF); if (A != 255) { int fopacity = (int)((double)A / 255. * 65536.); op = std::to_wstring(fopacity) + L"f"; } pos = std::to_wstring((int)(oGrad.GsLst[i].pos / 100000. * 65536)) + L"f"; if (i == 0) { sColor = col; sOpacity = op; } if (i == oGrad.GsLst.size() - 1) { sColor2 = col; sOpacity2 = op; } sColors += pos + L" " + col + L";"; } if (false == sColor.empty()) { strAttr = L" fillcolor=\"" + sColor + L"\""; } strNode += L"" + sFillNode + L""; } else strNode += L"/>"; } else if (fill.is() || !fill.is_init()) { strAttr = L" filled=\"f\""; } else { strAttr = L" fillcolor=\"" + GetHexColor(ARGB) + L"\""; BYTE A = (BYTE)((ARGB >> 24) & 0xFF); if (A != 255) { int fopacity = (int)(((double)A / 255.0) * 65536); strNode = L""; } } } void CalculateLine(BYTE lDocType, PPTX::Logic::SpPr& oSpPr, nullable& pShapeStyle, NSCommon::smart_ptr& oTheme, NSCommon::smart_ptr& oClrMap, std::wstring& strAttr, std::wstring& strNode, bool bOle) { PPTX::Logic::Ln line; DWORD ARGB = 0; if (pShapeStyle.is_init() && oTheme.is_init()) { oTheme->GetLineStyle(pShapeStyle->lnRef.idx.get_value_or(0), line); ARGB = pShapeStyle->lnRef.Color.GetRGBColor(oTheme, oClrMap, ARGB); } if (oSpPr.ln.is_init()) oSpPr.ln->Merge(line); if (line.Fill.is()) { ARGB = line.Fill.as().Color.GetRGBColor(oTheme, oClrMap, ARGB); strAttr = L" strokecolor=\"" + GetHexColor(ARGB) + L"\""; } else if (line.Fill.is() || bOle) strAttr = L" stroked=\"f\""; if (line.w.is_init()) { double dW = 72.0 * (*line.w) / (25.4 * 36000); std::wstring s = L" strokeweight=\"" + XmlUtils::ToString(dW, L"%.2lf") + L"pt\""; strAttr += s; } if (line.prstDash.IsInit() && line.prstDash->val.IsInit()) { std::wstring value; switch (line.prstDash->val->GetBYTECode()) { case 0: value = L"dash"; break; case 1: value = L"dashdot"; break; case 2: value = L"dot"; break; case 3: value = L"longdash"; break; case 4: value = L"longdashdot"; break; case 5: value = L"longdashdotdot"; break; case 6: value = L"solid"; break; case 7: value = L"shortdash"; break; case 8: value = L"shortdashdot"; break; case 9: value = L"shortdashdotdot"; break; case 10: value = L"shortdot"; break; default: value = L"solid"; break; } if (false == value.empty()) strNode = L""; } } SpTreeElem::SpTreeElem() { } OOX::EElementType SpTreeElem::getType () const { if (m_elem.IsInit()) return m_elem->getType(); return OOX::et_Unknown; } SpTreeElem::~SpTreeElem() { } SpTreeElem::SpTreeElem(XmlUtils::CXmlNode& node) { fromXML(node); } const SpTreeElem& SpTreeElem::operator =(XmlUtils::CXmlNode& node) { fromXML(node); return *this; } SpTreeElem& SpTreeElem::operator=(const SpTreeElem& oSrc) { m_elem = oSrc.m_elem; return *this; } SpTreeElem::SpTreeElem(XmlUtils::CXmlLiteReader& oReader) { fromXML(oReader); } const SpTreeElem& SpTreeElem::operator =(XmlUtils::CXmlLiteReader& oReader) { fromXML(oReader); return *this; } void SpTreeElem::fromXML(XmlUtils::CXmlLiteReader& oReader) { std::wstring name = XmlUtils::GetNameNoNS(oReader.GetName()); if (name == L"sp" || name == L"wsp") { if (m_bAlternative) m_elem_alternative.reset(new Logic::Shape(oReader)); else m_elem.reset(new Logic::Shape(oReader)); } else if (name == L"pic") { if (m_bAlternative) m_elem_alternative.reset(new Logic::Pic(oReader)); else m_elem.reset(new Logic::Pic(oReader)); } else if (name == L"cxnSp") m_elem.reset(new Logic::CxnSp(oReader)); else if (name == L"lockedCanvas") m_elem.reset(CreatePtrXmlContent(oReader)); else if (name == L"grpSp" || name == L"wgp" || name == L"spTree" || name == L"wpc") { if (m_bAlternative) m_elem_alternative.reset(CreatePtrXmlContent(oReader)); else m_elem.reset(CreatePtrXmlContent(oReader)); } else if (name == L"graphicFrame") { Logic::GraphicFrame *pGraphic = new Logic::GraphicFrame(); pGraphic->m_sRequires = m_sRequires; pGraphic->fromXML(oReader); if (pGraphic && pGraphic->IsEmpty() == false) { if (m_bAlternative) m_elem_alternative.reset(pGraphic); else m_elem.reset(pGraphic); } else RELEASEOBJECT(pGraphic); } else if (name == L"AlternateContent") { if ( oReader.IsEmptyNode() ) return; int nCurDepth = oReader.GetDepth(); while( oReader.ReadNextSiblingNode( nCurDepth ) ) { std::wstring strName = oReader.GetName(); if ( oReader.IsEmptyNode() ) continue; if (strName == L"mc:Choice") { ReadAttributesRequires(oReader); oReader.ReadNextSiblingNode(nCurDepth + 1); fromXML(oReader); m_bAlternative = (L"cx1" == m_sRequires || L"cx2" == m_sRequires); m_sRequires = L""; if (m_elem.is_init() && !m_bAlternative) break; } else if (strName == L"mc:Fallback") { oReader.ReadNextSiblingNode(nCurDepth + 1); fromXML(oReader); } } } m_bAlternative = false; } void SpTreeElem::fromXML(XmlUtils::CXmlNode& node) { std::wstring name = XmlUtils::GetNameNoNS(node.GetName()); if (name == L"sp" || name == L"wsp") { if (m_bAlternative) m_elem_alternative.reset(new Logic::Shape(node)); else m_elem.reset(new Logic::Shape(node)); } else if (name == L"pic") { if (m_bAlternative) m_elem_alternative.reset(new Logic::Pic(node)); else m_elem.reset(new Logic::Pic(node)); } else if (name == L"cxnSp") m_elem.reset(new Logic::CxnSp(node)); else if (name == L"lockedCanvas") m_elem.reset(CreatePtrXmlContent(node)); else if (name == L"grpSp" || name == L"wgp" || name == L"spTree" || name == L"wpc") { if (m_bAlternative) m_elem_alternative.reset(CreatePtrXmlContent(node)); else m_elem.reset(CreatePtrXmlContent(node)); } else if (name == L"graphicFrame") { if (m_bAlternative) m_elem_alternative.reset(new Logic::GraphicFrame(node)); else m_elem.reset(new Logic::GraphicFrame(node)); Logic::GraphicFrame *graphic_frame = dynamic_cast(m_elem.GetPointer()); if (graphic_frame) { if (graphic_frame->IsEmpty()) m_elem.reset(); } } else if (name == L"AlternateContent") { bool isEmpty = true; XmlUtils::CXmlNode oNodeChoice; if (node.GetNode(L"mc:Choice", oNodeChoice)) { XmlUtils::CXmlNode oNodeFall; std::vector oNodesC; //todo better check (a14 can be math, slicer) oNodeChoice.GetAttributeIfExist(L"Requires", m_sRequires); if (L"a14" == m_sRequires || L"cx1" == m_sRequires || L"cx2" == m_sRequires) { oNodeChoice.GetNodes(L"*", oNodesC); if (oNodesC.size() > 0) { XmlUtils::CXmlNode & oNodeC = oNodesC[0]; fromXML(oNodeC); isEmpty = (false == m_elem.IsInit()); } } m_bAlternative = (L"cx1" == m_sRequires || L"cx2" == m_sRequires); if ((isEmpty || m_bAlternative) && node.GetNode(L"mc:Fallback", oNodeFall)) { oNodeFall.GetNodes(L"*", oNodesC); if (oNodesC.size() > 0) { XmlUtils::CXmlNode & oNodeC = oNodesC[0]; fromXML(oNodeC); isEmpty = false; } } } if (isEmpty) { m_elem.reset(); } } else if (name == L"binData") { m_binaryData = node; } else m_elem.reset(); m_bAlternative = false; } void SpTreeElem::ReadAttributesRequires(XmlUtils::CXmlLiteReader& oReader) { WritingElement_ReadAttributes_Start( oReader ) WritingElement_ReadAttributes_ReadSingle ( oReader, _T("Requires"), m_sRequires ) WritingElement_ReadAttributes_End( oReader ) } std::wstring SpTreeElem::GetUriElem() { if (m_elem.IsInit() == false) { return L""; //return L"http://schemas.microsoft.com/office/word/2010/wordprocessingShape"; } else if (m_elem->getType() == OOX::et_lc_LockedCanvas) { return L"http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"; } else if (m_elem->getType() == OOX::et_p_ShapeTree) { return L"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"; } else if (m_elem->getType() == OOX::et_pic) { return L"http://schemas.openxmlformats.org/drawingml/2006/picture"; } else { return L"http://schemas.microsoft.com/office/word/2010/wordprocessingShape"; } } void SpTreeElem::fromPPTY(NSBinPptxRW::CBinaryFileReader* pReader) { BYTE _type = pReader->GetUChar(); switch (_type) { case SPTREE_TYPE_SHAPE: { Logic::Shape* p = new Logic::Shape(); p->fromPPTY(pReader); m_elem.reset(p); }break; case SPTREE_TYPE_OLE: case SPTREE_TYPE_PIC: case SPTREE_TYPE_AUDIO: case SPTREE_TYPE_VIDEO: { Logic::Pic* p = new Logic::Pic(); if (_type == SPTREE_TYPE_AUDIO) { OOX::Audio *pAudio = new OOX::Audio(NULL, pReader->m_nDocumentType == XMLWRITER_DOC_TYPE_DOCX); p->blipFill.additionalFiles.emplace_back(); p->blipFill.additionalFiles.back() = smart_ptr(dynamic_cast(pAudio)); } else if (_type == SPTREE_TYPE_VIDEO) { OOX::Video* pVideo = new OOX::Video(NULL, pReader->m_nDocumentType == XMLWRITER_DOC_TYPE_DOCX); p->blipFill.additionalFiles.emplace_back(); p->blipFill.additionalFiles.back() = smart_ptr(dynamic_cast(pVideo)); } p->fromPPTY(pReader); m_elem.reset(p); }break; case SPTREE_TYPE_CXNSP: { Logic::CxnSp* p = new Logic::CxnSp(); p->fromPPTY(pReader); m_elem.reset(p); }break; case SPTREE_TYPE_LOCKED_CANVAS: { Logic::LockedCanvas* p = new Logic::LockedCanvas(); pReader->Seek(pReader->GetPos() - 5); // type back + len p->fromPPTY(pReader); if (getType() == OOX::et_lc_LockedCanvas) { smart_ptr parent = GetElem().smart_dynamic_cast(); p->m_lGroupIndex = parent->m_lGroupIndex + 1; } m_elem.reset(p); }break; case SPTREE_TYPE_SPTREE: { Logic::SpTree* p = new Logic::SpTree(); pReader->Seek(pReader->GetPos() - 5); // type back + len p->fromPPTY(pReader); if (getType() == OOX::et_p_ShapeTree) { smart_ptr parent = GetElem().smart_dynamic_cast(); p->m_lGroupIndex = parent->m_lGroupIndex + 1; } m_elem.reset(p); }break; case SPTREE_TYPE_GRFRAME: { Logic::GraphicFrame* pFrame = new Logic::GraphicFrame(); pFrame->fromPPTY(pReader); m_elem.reset(pFrame); }break; case SPTREE_TYPE_NONE: default: { pReader->SkipRecord(); }break; } } void SpTreeElem::toPPTY(NSBinPptxRW::CBinaryFileWriter* pWriter) const { if (m_elem.is_init()) m_elem->toPPTY(pWriter); if (m_elem_alternative.is_init()) { pWriter->StartRecord(SPTREE_TYPE_ALTERNATIVE); m_elem_alternative->toPPTY(pWriter); pWriter->EndRecord(); } } void SpTreeElem::InitElem(WrapperWritingElement* pElem) { m_elem.reset(pElem); } std::wstring SpTreeElem::toXML() const { if (m_elem.IsInit()) return m_elem->toXML(); return L""; } void SpTreeElem::toXmlWriterVML (NSBinPptxRW::CXmlWriter* pWriter, smart_ptr& oTheme, smart_ptr& oClrMap, NSCommon::smart_ptr& pContainer) const { if (m_elem.IsInit() == false) return; switch(m_elem->getType()) { case OOX::et_a_Shape: { smart_ptr oShape = m_elem.smart_dynamic_cast(); if (oShape.IsInit()) oShape->toXmlWriterVML(pWriter, oTheme, oClrMap, pContainer); }break; case OOX::et_pic: { smart_ptr oPic = m_elem.smart_dynamic_cast(); if (oPic.IsInit()) oPic->toXmlWriterVML(pWriter, oTheme, oClrMap); }break; case OOX::et_p_ShapeTree: case OOX::et_lc_LockedCanvas: { smart_ptr oSpTree = m_elem.smart_dynamic_cast(); if (oSpTree.IsInit()) oSpTree->toXmlWriterVML(pWriter, oTheme, oClrMap, pContainer); }break; default: break; } } void SpTreeElem::toXmlWriter(NSBinPptxRW::CXmlWriter* pWriter) const { if (m_elem.is_init()) m_elem->toXmlWriter(pWriter); } std::wstring SpTreeElem::GetSlicerRequires() { if (m_elem.IsInit() && m_elem.is()) { PPTX::Logic::GraphicFrame& oGraphicFrame = m_elem.as(); if(oGraphicFrame.slicer.IsInit()) { return L"a14"; } else if(oGraphicFrame.slicerExt.IsInit()) { return L"sle15"; } } return L""; } smart_ptr SpTreeElem::GetElem() { return m_elem; } smart_ptr SpTreeElem::GetElemAlternative() { return m_elem_alternative; } void SpTreeElem::SetParentPointer(const WrapperWritingElement* pParent) { if (m_elem.is_init()) m_elem->SetParentPointer(pParent); if (m_elem_alternative.is_init()) m_elem_alternative->SetParentPointer(pParent); } void SpTreeElem::FillParentPointersForChilds(){} } // namespace Logic } // namespace PPTX