include/oox/export/shapes.hxx              |    2 +
 oox/source/export/shapes.cxx               |   36 +++++++++++++++++++++++++++++
 sc/source/filter/xcl97/xcl97rec.cxx        |    6 ++--
 sw/qa/extras/ooxmlexport/ooxmlexport16.cxx |   11 ++++++++
 sw/source/filter/ww8/docxsdrexport.cxx     |    4 +++
 5 files changed, 55 insertions(+), 4 deletions(-)

New commits:
commit 7bf632182a834a6b987b78b0e1c7d3e3dd43addd
Author:     Justin Luth <[email protected]>
AuthorDate: Tue Jan 20 17:41:15 2026 -0500
Commit:     Justin Luth <[email protected]>
CommitDate: Thu Jan 22 16:07:38 2026 +0100

    mso-test docx export: skip invalid when empty a:graphicData
    
    This focused on the document forum-mso-de-109776.docx.
    It was reported as corrupt by MS Word
    when LO round-tripped it as DOCX.
    
    This patch depends on the previous one:
        mso-test tdf#73254 xlsx export: invalid xdr:twoCellAnchor
    
    Unit test testTdf141173_missingFrames is interesting.
    Before (when we were exporting an empty graphicData)
    the import read the DML, saw an unusable graphic,
    and skipped it altogether.
    Now that is has to read a valid VML shape description,
    it creates the extra shape.
    So by not writing some shape data, we retain an extra shape.
    
    ake CppunitTest_sw_ooxmlexport16 CPPUNIT_TEST_NAME=testTdf148671
    
    Change-Id: I9db23dba4b1298a8193461b5452af54d0ca946de
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197705
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <[email protected]>
    Reviewed-by: Noel Grandin <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197826
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index 9210da630603..266105b85de4 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -484,6 +484,15 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf148671)
     // Preserve tag on SDT blocks. (Before the fix, these were all lost)
     xmlDocUniquePtr pXmlDoc = parseExport(u"word/document.xml"_ustr);
     assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tag", 3);
+
+    // Must not have an empty a:graphic a:graphicData.
+    // Header2 defines a simple (not visible) VML shape,
+    // which does not have a DML counterpart.
+    // Without the accompanying fix, an empty DML a:graphic was exported,
+    // which MS Word considered egregious enough to report it as corrupt.
+    xmlDocUniquePtr pXmlHeader = parseExport(u"word/header1.xml"_ustr);
+    assertXPath(pXmlHeader, "//mc:AlternateContent", 0); // no DML alternative
+    assertXPath(pXmlHeader, "//w:pict", 1);
 }
 
 DECLARE_OOXMLEXPORT_TEST(testTdf140668, "tdf140668.docx")
@@ -592,7 +601,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf141173_missingFrames)
     saveAndReload(TestFilter::DOCX);
     // Without the fix in place, almost all of the text and textboxes were 
missing.
     // Without the fix, there were only 2 shapes (mostly unseen).
-    CPPUNIT_ASSERT_EQUAL(13, getShapes());
+    CPPUNIT_ASSERT_EQUAL(14, getShapes());
 }
 
 DECLARE_OOXMLEXPORT_TEST(testTdf142404_tabSpacing, "tdf142404_tabSpacing.docx")
diff --git a/sw/source/filter/ww8/docxsdrexport.cxx 
b/sw/source/filter/ww8/docxsdrexport.cxx
index a6af45eec32f..b2cd4290c7d3 100644
--- a/sw/source/filter/ww8/docxsdrexport.cxx
+++ b/sw/source/filter/ww8/docxsdrexport.cxx
@@ -21,6 +21,7 @@
 #include <svx/svdobjkind.hxx>
 #include <svx/svditer.hxx>
 #include <svx/EnhancedCustomShape2d.hxx>
+#include <oox/export/shapes.hxx>
 #include <oox/token/namespaces.hxx>
 #include <oox/token/relationship.hxx>
 #include <textboxhelper.hxx>
@@ -1589,6 +1590,9 @@ bool DocxSdrExport::Impl::isSupportedDMLShape(const 
uno::Reference<drawing::XSha
         if (eFillStyle == css::drawing::FillStyle_BITMAP)
             return false;
     }
+    if (!oox::drawingml::ShapeExport::IsValidShape(xShape, 
drawingml::DOCUMENT_DOCX))
+        return false;
+
     return true;
 }
 
commit 9adb153769ffdccde149262eb55753f903df81c1
Author:     Justin Luth <[email protected]>
AuthorDate: Tue Jan 20 13:51:47 2026 -0500
Commit:     Justin Luth <[email protected]>
CommitDate: Thu Jan 22 16:07:26 2026 +0100

    mso-test tdf#73254 xlsx export: invalid xdr:twoCellAnchor
    
    The example document fdo73254-1.xls
    was being reported by MS Excel as corrupt after LO saved it as XLSX.
    
    xdr:twoCellAnchor has mandatory subelements
    so we can't start one unless we have a valid graphic/URL.
    
    Fortunately, it is not corrupt to have an empty drawing1.xml
    containing only a <xdr:wsDr/>.
    That would have been practically impossible to avoid.
    
    Change-Id: Ia0251eb0cee1798cbeb1b8d4f545537ab2485668
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197699
    Reviewed-by: Justin Luth <[email protected]>
    Tested-by: Jenkins
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/197825
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/include/oox/export/shapes.hxx b/include/oox/export/shapes.hxx
index d05d0438a4e6..6bd7bd94124f 100644
--- a/include/oox/export/shapes.hxx
+++ b/include/oox/export/shapes.hxx
@@ -111,6 +111,8 @@ public:
 
     static bool         NonEmptyText( const css::uno::Reference< 
css::uno::XInterface >& xIface );
     static bool         IsShapeTypeKnown( const css::uno::Reference< 
css::drawing::XShape >& xShape );
+    static bool IsValidShape(const css::uno::Reference<css::drawing::XShape>& 
xShape,
+                             DocumentType eDocumentType);
 
     ShapeExport&
                         WritePolyPolygonShape( const css::uno::Reference< 
css::drawing::XShape >& xShape, bool bClosed );
diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx
index 4adb4f2a187c..937094ab6755 100644
--- a/oox/source/export/shapes.cxx
+++ b/oox/source/export/shapes.cxx
@@ -2225,6 +2225,42 @@ bool ShapeExport::IsShapeTypeKnown(const 
Reference<XShape>& xShape)
     return constMap.contains(sShapeType);
 }
 
+bool ShapeExport::IsValidShape(const Reference<XShape>& xShape, DocumentType 
eDocumentType)
+{
+    if (!xShape)
+        return false;
+
+    auto aConverterIterator = constMap.find(xShape->getShapeType());
+    if (aConverterIterator == constMap.end())
+        return false;
+
+    if (aConverterIterator->second == &ShapeExport::WriteGraphicObjectShape)
+    {
+        if (IsNonEmptySimpleText(xShape))
+            return true;
+
+        Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
+        Reference<XPropertySetInfo> xShapePropSetInfo
+            = xShapeProps.is() ? xShapeProps->getPropertySetInfo() : nullptr;
+        if (!xShapePropSetInfo.is())
+            return false;
+
+        uno::Reference<graphic::XGraphic> xGraphic;
+        xShapeProps->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
+
+        // tdf#155903 Only for PPTX. Microsoft does not support this feature 
in Word and Excel.
+        OUString sMediaURL;
+        bool bHasMediaURL = eDocumentType == DOCUMENT_PPTX
+                            && 
xShapePropSetInfo->hasPropertyByName(u"MediaURL"_ustr)
+                            && 
(xShapeProps->getPropertyValue(u"MediaURL"_ustr) >>= sMediaURL);
+
+        if (!xGraphic.is() && !bHasMediaURL)
+            return false;
+    }
+
+    return true;
+}
+
 ShapeExport& ShapeExport::WriteShape( const Reference< XShape >& xShape )
 {
     if (!xShape)
diff --git a/sc/source/filter/xcl97/xcl97rec.cxx 
b/sc/source/filter/xcl97/xcl97rec.cxx
index e8518fc540ff..8d78df5fe0e8 100644
--- a/sc/source/filter/xcl97/xcl97rec.cxx
+++ b/sc/source/filter/xcl97/xcl97rec.cxx
@@ -1307,10 +1307,10 @@ bool ScURLTransformer::isExternalURL(const OUString& 
rURL) const
 
 void XclObjAny::SaveXml( XclExpXmlStream& rStrm )
 {
-    // Return early if unknown shape type, otherwise bogus drawing XML gets 
written
-    if (!ShapeExport::IsShapeTypeKnown(mxShape))
+    // Return early if unknown/invalid shape; otherwise bogus drawing XML gets 
written
+    if (!ShapeExport::IsValidShape(mxShape, drawingml::DOCUMENT_XLSX))
     {
-        SAL_INFO("sc.filter", "unknown shape");
+        SAL_INFO("sc.filter", "unknown or invalid/incomplete shape");
         return;
     }
 

Reply via email to