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; }
