include/oox/export/chartexport.hxx        |    1 +
 oox/source/export/chartexport.cxx         |    2 +-
 sw/qa/extras/ooxmlexport/ooxmlexport4.cxx |   15 +++++++++++++++
 sw/source/filter/ww8/docxexport.cxx       |   14 ++++++++++++++
 sw/source/filter/ww8/docxexport.hxx       |    2 ++
 5 files changed, 33 insertions(+), 1 deletion(-)

New commits:
commit 81a1539bf2e197de1275af762b26e98652551a8a
Author:     Justin Luth <[email protected]>
AuthorDate: Thu Jan 8 16:52:31 2026 -0500
Commit:     Justin Luth <[email protected]>
CommitDate: Fri Jan 9 20:10:47 2026 +0100

    tdf#168977 docx export: prevent multiple chart rels to embeddings/file
    
    MS Word considers a document to be corrupt
    if multiple files have a relationship
    to the same embeddings/file.
    
    Since we only round-trip existing embeddings,
    just make sure that if we duplicate a chart internally,
    that we only write an externalData link once.
    
    make CppunitTest_sw_ooxmlexport4 CPPUNIT_TEST_NAME=testChartInFooter
    
    Change-Id: I8905412b07fdf8dc065d1fed4c239c63aab24935
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/196895
    Reviewed-by: Justin Luth <[email protected]>
    Tested-by: Jenkins

diff --git a/include/oox/export/chartexport.hxx 
b/include/oox/export/chartexport.hxx
index 5248e244cbd4..385fda19f806 100644
--- a/include/oox/export/chartexport.hxx
+++ b/include/oox/export/chartexport.hxx
@@ -140,6 +140,7 @@ class ChartExport final : public DrawingML {
 public:
     // first: data sequence for label, second: data sequence for values.
     typedef ::std::vector< AxisIdPair > AxisVector;
+    bool mbLinkToExternalData = true;
 
 private:
     sal_Int32           mnXmlNamespace;
diff --git a/oox/source/export/chartexport.cxx 
b/oox/source/export/chartexport.cxx
index 2c695a94d7ca..f477e62664b2 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -1821,7 +1821,7 @@ void ChartExport::exportExternalData( const Reference< 
css::chart::XChartDocumen
     if (bIsChartex) return; // TODO!!
     // Embedded external data is grab bagged for docx file hence adding export 
part of
     // external data for docx files only.
-    if(GetDocumentType() != DOCUMENT_DOCX)
+    if(!mbLinkToExternalData || GetDocumentType() != DOCUMENT_DOCX)
         return;
 
     OUString externalDataPath;
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
index c5aeb4d1342d..bed61269e457 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
@@ -470,6 +470,21 @@ CPPUNIT_TEST_FIXTURE(Test, testChartInFooter)
         u"rId1");
 
     CPPUNIT_ASSERT_EQUAL(1, getShapes());
+
+    // tdf#168977: MS Word reports corrupt if same embeddings/file referred to 
by multiple charts
+    // Currently, we duplicate a chart into the first page footer (from the 
'default' footer)
+    xmlDocUniquePtr pXmlChart1Rels = 
parseExport(u"word/charts/_rels/chart1.xml.rels"_ustr);
+    assertXPath(pXmlChart1Rels,
+        
"//rels:Relationship[@Target='../embeddings/Microsoft_Excel_Worksheet1.xlsx']");
+
+    uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+        = 
packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory),
+                                                      maTempFile.GetURL());
+    CPPUNIT_ASSERT(xNameAccess->hasByName(u"word/charts/chart2.xml"_ustr)); // 
first page footer
+    // without the fix, this was true; both charts referred to the same 
'Microsoft_Excel_Worksheet1'
+    CPPUNIT_ASSERT_EQUAL(false,
+                         
bool(xNameAccess->hasByName(u"word/charts/_rels/chart2.xml.rels"_ustr)));
+
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testNestedTextFrames)
diff --git a/sw/source/filter/ww8/docxexport.cxx 
b/sw/source/filter/ww8/docxexport.cxx
index fa8ce467faf3..00d9a1005d8f 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -405,7 +405,21 @@ OString DocxExport::OutputChart( uno::Reference< 
frame::XModel > const & xModel,
     oox::drawingml::ChartExport aChartExport(XML_w, pChartFS, xModel, 
&m_rFilter, oox::drawingml::DOCUMENT_DOCX);
     css::uno::Reference<css::util::XModifiable> xModifiable(xModel, 
css::uno::UNO_QUERY);
     const bool bOldModified = xModifiable && xModifiable->isModified();
+
+    // Currently, content in ../embeddings is simply grab-bagged as 
OOEmbeddings
+    // and must only be referred to once or else MS Word considers the 
document corrupt,
+    // so if a chart is duplicated (common in headers/footers) then only 
exportExternalData once.
+    for (const auto& xExport : m_aExportedCharts)
+    {
+        if (xExport != xModel)
+            continue;
+
+        aChartExport.mbLinkToExternalData = false;
+        break;
+    }
+
     aChartExport.ExportContent();
+    m_aExportedCharts.push_back(xModel);
     if (!bOldModified && xModifiable && xModifiable->isModified())
         // tdf#134973: the model could get modified: e.g., calling 
XChartDocument::getSubTitle(),
         // which creates the object if absent, and sets the modified state.
diff --git a/sw/source/filter/ww8/docxexport.hxx 
b/sw/source/filter/ww8/docxexport.hxx
index 6f092664ad1a..ac5700d77867 100644
--- a/sw/source/filter/ww8/docxexport.hxx
+++ b/sw/source/filter/ww8/docxexport.hxx
@@ -126,6 +126,8 @@ class DocxExport : public MSWordExportBase
 
     std::set<SwNode*> m_aDummyFloatingTableAnchors;
 
+    std::vector<css::uno::Reference<frame::XModel>> m_aExportedCharts;
+
 public:
 
     DocxExportFilter& GetFilter() { return m_rFilter; };

Reply via email to