include/oox/export/drawingml.hxx | 9 +-- include/svx/diagram/DomMapFlag.hxx | 13 ++--- oox/source/drawingml/diagram/diagram.cxx | 15 ++++- oox/source/drawingml/shape.cxx | 78 ++++++++++++++++++++++--------- oox/source/export/drawingml.cxx | 60 +++++++++++++++++++++-- 5 files changed, 133 insertions(+), 42 deletions(-)
New commits: commit 58aaf1b33a35885b595e23a97611ca157c015e7d Author: Karthik Godha <[email protected]> AuthorDate: Tue Dec 23 14:15:00 2025 +0530 Commit: Michael Stahl <[email protected]> CommitDate: Tue Jan 27 14:37:37 2026 +0100 tdf#170094: PPTX->PPTX export SmartArt hyperlinks SmartArt hyperlinks are not preserved after roundtrip. This leads to XML having relationship IDs which are invalid. Change-Id: I3fa3d6f79b8eb8d086b1061d26c30568e3b5793f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196152 Reviewed-by: Michael Stahl <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> (cherry picked from commit 8a049c8a1482260f0ffe85b6da8c5e8834c20652) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198182 Tested-by: Jenkins diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index cb39c05bf2c5..36378c9dbdb4 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -521,10 +521,11 @@ public: OOX_DLLPUBLIC bool PrepareToWriteAsDiagram(const css::uno::Reference<css::drawing::XShape>& rXRootShape); OOX_DLLPUBLIC void WriteDiagram(const css::uno::Reference<css::drawing::XShape>& rXShape, sal_Int32 nDiagramId, sal_Int32 nShapeId = -1); - void writeDiagramRels(const css::uno::Sequence<css::uno::Sequence<css::uno::Any>>& xRelSeq, - const css::uno::Reference<css::io::XOutputStream>& xOutStream, - std::u16string_view sGrabBagProperyName, int nDiagramId); - + void writeDiagramImageRels(const css::uno::Sequence<css::uno::Sequence<css::uno::Any>>& xRelSeq, + const css::uno::Reference<css::io::XOutputStream>& xOutStream, + std::u16string_view sGrabBagProperyName, int nDiagramId); + void writeDiagramHlinkRels(const css::uno::Sequence<css::uno::Sequence<css::uno::Any>>& xRelSeq, + const css::uno::Reference<css::io::XOutputStream>& xOutStream); static void WriteFromTo(const css::uno::Reference<css::drawing::XShape>& rXShape, const css::awt::Size& aPageSize, const sax_fastparser::FSHelperPtr& pDrawing); diff --git a/include/svx/diagram/DomMapFlag.hxx b/include/svx/diagram/DomMapFlag.hxx index f698da928cc0..0ceb4186f7f3 100644 --- a/include/svx/diagram/DomMapFlag.hxx +++ b/include/svx/diagram/DomMapFlag.hxx @@ -28,12 +28,13 @@ namespace svx::diagram enum class SVXCORE_DLLPUBLIC DomMapFlag : sal_uInt16 { OOXData = 0, - OOXDataRels = 1, - OOXLayout = 2, - OOXStyle = 3, - OOXColor = 4, - OOXDrawing = 5, - OOXDrawingRels = 6 + OOXDataImageRels = 1, + OOXDataHlinkRels = 2, + OOXLayout = 3, + OOXStyle = 4, + OOXColor = 5, + OOXDrawing = 6, + OOXDrawingRels = 7 }; typedef std::vector<DomMapFlag> DomMapFlags; diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx index 75f84c3b7340..b567a48e0890 100644 --- a/oox/source/drawingml/diagram/diagram.cxx +++ b/oox/source/drawingml/diagram/diagram.cxx @@ -410,10 +410,17 @@ void loadDiagram( ShapePtr const & pShape, pDiagram, xRefDataModel); - uno::Sequence< uno::Sequence< uno::Any > > aDataRelsMap( - pShape->resolveRelationshipsOfTypeFromOfficeDoc( rFilter, xRefDataModel->getFragmentPath(), u"image" )); - - pDiagram->setOOXDomValue(svx::diagram::DomMapFlag::OOXDataRels, uno::Any(aDataRelsMap)); + uno::Sequence<uno::Sequence<uno::Any>> aDataImageRelsMap( + pShape->resolveRelationshipsOfTypeFromOfficeDoc( + rFilter, xRefDataModel->getFragmentPath(), u"image")); + uno::Sequence<uno::Sequence<uno::Any>> aDataHlinkRelsMap( + pShape->resolveRelationshipsOfTypeFromOfficeDoc( + rFilter, xRefDataModel->getFragmentPath(), u"hlink")); + + pDiagram->setOOXDomValue(svx::diagram::DomMapFlag::OOXDataImageRels, + uno::Any(aDataImageRelsMap)); + pDiagram->setOOXDomValue(svx::diagram::DomMapFlag::OOXDataHlinkRels, + uno::Any(aDataHlinkRelsMap)); // Pass the info to pShape for (auto const& extDrawing : pData->getExtDrawings()) diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 59c3ce0c93a3..324bdb913e10 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -2876,36 +2876,72 @@ uno::Sequence< uno::Sequence< uno::Any > > Shape::resolveRelationshipsOfTypeFro core::RelationsRef xRels = rFilter.importRelations( sFragment ); if ( xRels ) { - core::RelationsRef xImageRels = xRels->getRelationsFromTypeFromOfficeDoc( sType ); - if ( xImageRels ) + if (sType == u"image") { - xRelListTemp.realloc( xImageRels->size() ); - auto pxRelListTemp = xRelListTemp.getArray(); - for (auto const& imageRel : *xImageRels) + core::RelationsRef xImageRels = xRels->getRelationsFromTypeFromOfficeDoc(sType); + if (xImageRels) { - uno::Sequence< uno::Any > diagramRelTuple (3); - auto pdiagramRelTuple = diagramRelTuple.getArray(); - // [0] => RID, [1] => InputStream [2] => extension - OUString sRelId = imageRel.second.maId; + xRelListTemp.realloc(xImageRels->size()); + auto pxRelListTemp = xRelListTemp.getArray(); + for (auto const& imageRel : *xImageRels) + { + uno::Sequence<uno::Any> diagramRelTuple(3); + auto pdiagramRelTuple = diagramRelTuple.getArray(); + // [0] => RID, [1] => InputStream [2] => extension + OUString sRelId = imageRel.second.maId; + + pdiagramRelTuple[0] <<= sRelId; + OUString sTarget = xImageRels->getFragmentPathFromRelId(sRelId); + + uno::Reference<io::XInputStream> xImageInputStrm( + rFilter.openInputStream(sTarget), uno::UNO_SET_THROW); + StreamDataSequence dataSeq; + if (rFilter.importBinaryData(dataSeq, sTarget)) + { + pdiagramRelTuple[1] <<= dataSeq; + } - pdiagramRelTuple[0] <<= sRelId; - OUString sTarget = xImageRels->getFragmentPathFromRelId( sRelId ); + pdiagramRelTuple[2] <<= sTarget.copy(sTarget.lastIndexOf(".")); - uno::Reference< io::XInputStream > xImageInputStrm( rFilter.openInputStream( sTarget ), uno::UNO_SET_THROW ); - StreamDataSequence dataSeq; - if ( rFilter.importBinaryData( dataSeq, sTarget ) ) - { - pdiagramRelTuple[1] <<= dataSeq; + pxRelListTemp[counter] = std::move(diagramRelTuple); + ++counter; } + } + } + else if (sType == u"hlink") + { + // Hyperlink can be internal or external + core::RelationsRef xSlideRels = xRels->getRelationsFromTypeFromOfficeDoc(u"slide"); + core::RelationsRef xHlinkRels = xRels->getRelationsFromTypeFromOfficeDoc(u"hyperlink"); - pdiagramRelTuple[2] <<= sTarget.copy( sTarget.lastIndexOf(".") ); + sal_Int32 totalSize + = (xSlideRels ? xSlideRels->size() : 0) + (xHlinkRels ? xHlinkRels->size() : 0); + xRelListTemp.realloc(totalSize); + auto pxRelListTemp = xRelListTemp.getArray(); - pxRelListTemp[counter] = std::move(diagramRelTuple); - ++counter; - } - xRelListTemp.realloc(counter); + // Helper to create relation tuple + auto addRelation = [&](const auto& rel, const OUString& relType) + { + uno::Sequence<uno::Any> tuple(3); + auto pTuple = tuple.getArray(); + pTuple[0] <<= rel.second.maId; + pTuple[1] <<= rel.second.maTarget; + pTuple[2] <<= relType; + pxRelListTemp[counter++] = std::move(tuple); + }; + if (xSlideRels) + { + for (auto const& slideRel : *xSlideRels) + addRelation(slideRel, "slide"); + } + if (xHlinkRels) + { + for (auto const& hlinkRel : *xHlinkRels) + addRelation(hlinkRel, "hyperlink"); + } } + xRelListTemp.realloc(counter); } return xRelListTemp; } diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 3544d9b4aa9c..a986078dc1f1 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -6837,8 +6837,13 @@ void DrawingML::WriteDiagram(const css::uno::Reference<css::drawing::XShape>& rX uno::Reference<xml::dom::XDocument> drawingDom; rIDiagramHelper->getOOXDomValue(svx::diagram::DomMapFlag::OOXDrawing) >>= drawingDom; - uno::Sequence<uno::Sequence<uno::Any>> xDataRelSeq; - rIDiagramHelper->getOOXDomValue(svx::diagram::DomMapFlag::OOXDataRels) >>= xDataRelSeq; + uno::Sequence<uno::Sequence<uno::Any>> xDataImageRelSeq; + rIDiagramHelper->getOOXDomValue(svx::diagram::DomMapFlag::OOXDataImageRels) + >>= xDataImageRelSeq; + + uno::Sequence<uno::Sequence<uno::Any>> xDataHlinkRelSeq; + rIDiagramHelper->getOOXDomValue(svx::diagram::DomMapFlag::OOXDataHlinkRels) + >>= xDataHlinkRelSeq; // generate a unique id rtl::Reference<sax_fastparser::FastAttributeList> pDocPrAttrList @@ -6977,7 +6982,8 @@ void DrawingML::WriteDiagram(const css::uno::Reference<css::drawing::XShape>& rX uno::Sequence<beans::StringPair>()); // write the associated Images and rels for data file - writeDiagramRels(xDataRelSeq, xDataOutputStream, u"OOXDiagramDataRels", nDiagramId); + writeDiagramImageRels(xDataImageRelSeq, xDataOutputStream, u"OOXDiagramDataRels", nDiagramId); + writeDiagramHlinkRels(xDataHlinkRelSeq, xDataOutputStream); // write layout file serializer.set(layoutDom, uno::UNO_QUERY); @@ -7018,12 +7024,13 @@ void DrawingML::WriteDiagram(const css::uno::Reference<css::drawing::XShape>& rX // write the associated Images and rels for drawing file uno::Sequence<uno::Sequence<uno::Any>> xDrawingRelSeq; rIDiagramHelper->getOOXDomValue(svx::diagram::DomMapFlag::OOXDrawingRels) >>= xDrawingRelSeq; - writeDiagramRels(xDrawingRelSeq, xDrawingOutputStream, u"OOXDiagramDrawingRels", nDiagramId); + writeDiagramImageRels(xDrawingRelSeq, xDrawingOutputStream, u"OOXDiagramDrawingRels", + nDiagramId); } -void DrawingML::writeDiagramRels(const uno::Sequence<uno::Sequence<uno::Any>>& xRelSeq, - const uno::Reference<io::XOutputStream>& xOutStream, - std::u16string_view sGrabBagProperyName, int nDiagramId) +void DrawingML::writeDiagramImageRels(const uno::Sequence<uno::Sequence<uno::Any>>& xRelSeq, + const uno::Reference<io::XOutputStream>& xOutStream, + std::u16string_view sGrabBagProperyName, int nDiagramId) { // add image relationships of OOXData, OOXDiagram OUString sType(oox::getRelationship(Relationship::IMAGE)); @@ -7081,6 +7088,45 @@ void DrawingML::writeDiagramRels(const uno::Sequence<uno::Sequence<uno::Any>>& x } } +void DrawingML::writeDiagramHlinkRels(const uno::Sequence<uno::Sequence<uno::Any>>& xRelSeq, + const uno::Reference<io::XOutputStream>& xOutStream) +{ + uno::Reference<xml::sax::XWriter> xWriter + = xml::sax::Writer::create(comphelper::getProcessComponentContext()); + xWriter->setOutputStream(xOutStream); + + // retrieve the relationships from Sequence + for (sal_Int32 j = 0; j < xRelSeq.getLength(); j++) + { + // diagramDataRelTuple[0] => RID, + // diagramDataRelTuple[1] => Target + // diagramDataRelTuple[2] => Type + const uno::Sequence<uno::Any>& diagramDataRelTuple = xRelSeq[j]; + + OUString sRelId; + OUString sTarget; + OUString sType; + diagramDataRelTuple[0] >>= sRelId; + sRelId = sRelId.copy(3); + diagramDataRelTuple[1] >>= sTarget; + diagramDataRelTuple[2] >>= sType; + + OUString sRelType; + bool bExtURL = true; + if (sType == u"slide") + { + sRelType = oox::getRelationship(Relationship::SLIDE); + bExtURL = false; + } + else + sRelType = oox::getRelationship(Relationship::HYPERLINK); + + PropertySet aProps(xOutStream); + aProps.setAnyProperty(PROP_RelId, uno::Any(sRelId.toInt32())); + mpFB->addRelation(xOutStream, sRelType, sTarget, bExtURL); + } +} + void DrawingML::WriteFromTo(const uno::Reference<css::drawing::XShape>& rXShape, const awt::Size& aPageSize, const FSHelperPtr& pDrawing) {
