summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2021-04-19 20:27:32 +0200
committerMichael Stahl <michael.stahl@allotropia.de>2021-04-21 11:58:37 +0200
commit7b3ea547bddd08e483c49ed5b3ff822f782a0aae (patch)
treeae5582c99189b8f702f7046cea8666847d99500a
parent054d0f8f5e6791d03081be7be19abeaad8aab918 (diff)
tdf#122962 DOCX drawingML export: fix polygon shape in group shape
Regression from commit cfb5b20cdc230320ff9f864d1cfd81aaea221da0 (DocxAttributeOutput::OutputFlyFrame_Impl: enable DML export by default, 2013-12-18), there were two problems here. First, <a:chOff> and <a:chExt> was not written for docx group shapes. This can be done for toplevel shapes just by writing what would be the shape position and size (but for docx, we don't write the size). Second, (poly)polygon shapes used the bounding rectangle of their points as size, which doesn't necessarily match the shape size. Given that the group shape is meant to simply contain its children in LibreOffice (and not have an own size), switch to using the UNO API for polygon shapes as well, that way the two sizes will always match. Change-Id: I4406ddefe5f6105aa2fc74d805359add452936bb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114305 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit 4cb71fefc61d9015a0142f3a4fdafc5250913f2c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114279 Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
-rw-r--r--include/oox/export/drawingml.hxx2
-rw-r--r--oox/CppunitTest_oox_export.mk46
-rw-r--r--oox/Module_oox.mk1
-rw-r--r--oox/qa/unit/data/dml-groupshape-polygon.docxbin0 -> 24492 bytes
-rw-r--r--oox/qa/unit/export.cxx157
-rw-r--r--oox/source/export/drawingml.cxx29
-rw-r--r--oox/source/export/shapes.cxx8
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport6.cxx4
8 files changed, 235 insertions, 12 deletions
diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx
index 0a42eb84f001..00049fd94103 100644
--- a/include/oox/export/drawingml.hxx
+++ b/include/oox/export/drawingml.hxx
@@ -250,7 +250,7 @@ public:
void WriteShapeTransformation(const css::uno::Reference< css::drawing::XShape >& rXShape,
sal_Int32 nXmlNamespace, bool bFlipH = false, bool bFlipV = false, bool bSuppressRotation = false, bool bSuppressFlipping = false, bool bFlippedBeforeRotation = false);
- void WriteTransformation(const tools::Rectangle& rRectangle,
+ void WriteTransformation(const css::uno::Reference< css::drawing::XShape >& xShape, const tools::Rectangle& rRectangle,
sal_Int32 nXmlNamespace, bool bFlipH = false, bool bFlipV = false, sal_Int32 nRotation = 0, bool bIsGroupShape = false);
void WriteText( const css::uno::Reference< css::uno::XInterface >& rXIface, bool bBodyPr, bool bText = true, sal_Int32 nXmlNamespace = 0);
diff --git a/oox/CppunitTest_oox_export.mk b/oox/CppunitTest_oox_export.mk
new file mode 100644
index 000000000000..011ce3d2a5de
--- /dev/null
+++ b/oox/CppunitTest_oox_export.mk
@@ -0,0 +1,46 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,oox_export))
+
+$(eval $(call gb_CppunitTest_use_externals,oox_export,\
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,oox_export, \
+ oox/qa/unit/export \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,oox_export, \
+ comphelper \
+ cppu \
+ oox \
+ sal \
+ test \
+ unotest \
+ utl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,oox_export))
+
+$(eval $(call gb_CppunitTest_use_ure,oox_export))
+$(eval $(call gb_CppunitTest_use_vcl,oox_export))
+
+$(eval $(call gb_CppunitTest_use_rdb,oox_export,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,oox_export,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,oox_export))
+
+# vim: set noet sw=4 ts=4:
diff --git a/oox/Module_oox.mk b/oox/Module_oox.mk
index ed85ee68da2d..75ef85051f85 100644
--- a/oox/Module_oox.mk
+++ b/oox/Module_oox.mk
@@ -29,6 +29,7 @@ $(eval $(call gb_Module_add_check_targets,oox,\
CppunitTest_oox_drawingml \
CppunitTest_oox_vml \
CppunitTest_oox_shape \
+ CppunitTest_oox_export \
))
# vim: set noet sw=4 ts=4:
diff --git a/oox/qa/unit/data/dml-groupshape-polygon.docx b/oox/qa/unit/data/dml-groupshape-polygon.docx
new file mode 100644
index 000000000000..6d20b0342f68
--- /dev/null
+++ b/oox/qa/unit/data/dml-groupshape-polygon.docx
Binary files differ
diff --git a/oox/qa/unit/export.cxx b/oox/qa/unit/export.cxx
new file mode 100644
index 000000000000..6e6620ab63a4
--- /dev/null
+++ b/oox/qa/unit/export.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+#include <test/xmltesttools.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
+
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Covers ooox/source/export/ fixes.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+ utl::TempFile maTempFile;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ void registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) override;
+ utl::TempFile& getTempFile() { return maTempFile; }
+ void loadAndSave(const OUString& rURL, const OUString& rFilterName);
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+void Test::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx)
+{
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w"),
+ BAD_CAST("http://schemas.openxmlformats.org/wordprocessingml/2006/main"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("v"), BAD_CAST("urn:schemas-microsoft-com:vml"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("mc"),
+ BAD_CAST("http://schemas.openxmlformats.org/markup-compatibility/2006"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("wps"),
+ BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingShape"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("wpg"),
+ BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("wp"),
+ BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("wp14"),
+ BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("a"),
+ BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/main"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("pic"),
+ BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/picture"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("rels"),
+ BAD_CAST("http://schemas.openxmlformats.org/package/2006/relationships"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w14"),
+ BAD_CAST("http://schemas.microsoft.com/office/word/2010/wordml"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("m"),
+ BAD_CAST("http://schemas.openxmlformats.org/officeDocument/2006/math"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("ContentType"),
+ BAD_CAST("http://schemas.openxmlformats.org/package/2006/content-types"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("lc"),
+ BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("cp"),
+ BAD_CAST("http://schemas.openxmlformats.org/package/2006/metadata/core-properties"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("extended-properties"),
+ BAD_CAST("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("custom-properties"),
+ BAD_CAST("http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"));
+ xmlXPathRegisterNs(
+ pXmlXpathCtx, BAD_CAST("vt"),
+ BAD_CAST("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("dcterms"), BAD_CAST("http://purl.org/dc/terms/"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("a14"),
+ BAD_CAST("http://schemas.microsoft.com/office/drawing/2010/main"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("c"),
+ BAD_CAST("http://schemas.openxmlformats.org/drawingml/2006/chart"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("o"),
+ BAD_CAST("urn:schemas-microsoft-com:office:office"));
+ xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("w10"),
+ BAD_CAST("urn:schemas-microsoft-com:office:word"));
+}
+
+void Test::loadAndSave(const OUString& rURL, const OUString& rFilterName)
+{
+ mxComponent = loadFromDesktop(rURL);
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= rFilterName;
+ maTempFile.EnableKillingFile();
+ xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+ mxComponent->dispose();
+ mxComponent.clear();
+ // too many DOCX validation errors right now
+ if (rFilterName != "Office Open XML Text")
+ {
+ validate(maTempFile.GetFileName(), test::OOXML);
+ }
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/oox/qa/unit/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testDmlGroupshapePolygon)
+{
+ // Given a document with a group shape, containing a single polygon child shape:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "dml-groupshape-polygon.docx";
+
+ // When saving that to DOCX:
+ loadAndSave(aURL, "Office Open XML Text");
+
+ // Then make sure that the group shape, the group shape's child size and the child shape's size
+ // match:
+ uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
+ = packages::zip::ZipFileAccess::createWithURL(mxComponentContext, getTempFile().GetURL());
+ uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName("word/document.xml"),
+ uno::UNO_QUERY);
+ std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
+ xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get());
+ assertXPath(pXmlDoc, "//wpg:grpSpPr/a:xfrm/a:ext", "cx", "5328360");
+ // Without the accompanying fix in place, this test would have failed, the <a:chExt> element was
+ // not written.
+ assertXPath(pXmlDoc, "//wpg:grpSpPr/a:xfrm/a:chExt", "cx", "5328360");
+ assertXPath(pXmlDoc, "//wps:spPr/a:xfrm/a:ext", "cx", "5328360");
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 94b67cb379f2..8cfd4a6dabc5 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -1686,7 +1686,22 @@ void DrawingML::WriteXGraphicStretch(uno::Reference<beans::XPropertySet> const &
mpFS->endElementNS(XML_a, XML_stretch);
}
-void DrawingML::WriteTransformation(const tools::Rectangle& rRect,
+namespace
+{
+bool IsTopGroupObj(const uno::Reference<drawing::XShape>& xShape)
+{
+ SdrObject* pObject = GetSdrObjectFromXShape(xShape);
+ if (!pObject)
+ return false;
+
+ if (pObject->getParentSdrObjectFromSdrObject())
+ return false;
+
+ return pObject->IsGroupObject();
+}
+}
+
+void DrawingML::WriteTransformation(const Reference< XShape >& xShape, const tools::Rectangle& rRect,
sal_Int32 nXmlNamespace, bool bFlipH, bool bFlipV, sal_Int32 nRotation, bool bIsGroupShape)
{
@@ -1696,7 +1711,9 @@ void DrawingML::WriteTransformation(const tools::Rectangle& rRect,
XML_rot, sax_fastparser::UseIf(OString::number(nRotation), nRotation % 21600000 != 0));
sal_Int32 nLeft = rRect.Left();
+ sal_Int32 nChildLeft = nLeft;
sal_Int32 nTop = rRect.Top();
+ sal_Int32 nChildTop = nTop;
if (GetDocumentType() == DOCUMENT_DOCX && !m_xParent.is())
{
nLeft = 0;
@@ -1710,11 +1727,11 @@ void DrawingML::WriteTransformation(const tools::Rectangle& rRect,
XML_cx, OString::number(oox::drawingml::convertHmmToEmu(rRect.GetWidth())),
XML_cy, OString::number(oox::drawingml::convertHmmToEmu(rRect.GetHeight())));
- if (GetDocumentType() != DOCUMENT_DOCX && bIsGroupShape)
+ if (bIsGroupShape && (GetDocumentType() != DOCUMENT_DOCX || IsTopGroupObj(xShape)))
{
mpFS->singleElementNS(XML_a, XML_chOff,
- XML_x, OString::number(oox::drawingml::convertHmmToEmu(nLeft)),
- XML_y, OString::number(oox::drawingml::convertHmmToEmu(nTop)));
+ XML_x, OString::number(oox::drawingml::convertHmmToEmu(nChildLeft)),
+ XML_y, OString::number(oox::drawingml::convertHmmToEmu(nChildTop)));
mpFS->singleElementNS(XML_a, XML_chExt,
XML_cx, OString::number(oox::drawingml::convertHmmToEmu(rRect.GetWidth())),
XML_cy, OString::number(oox::drawingml::convertHmmToEmu(rRect.GetHeight())));
@@ -1798,7 +1815,7 @@ void DrawingML::WriteShapeTransformation( const Reference< XShape >& rXShape, sa
if(bFlipH != bFlipV)
nRotation = nRotation * -1 + 36000;
- WriteTransformation(tools::Rectangle(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height)), nXmlNamespace,
+ WriteTransformation(rXShape, tools::Rectangle(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height)), nXmlNamespace,
bFlipHWrite, bFlipVWrite, ExportRotateClockwisify(nRotation + nCameraRotation), IsGroupShape( rXShape ));
}
@@ -4809,7 +4826,7 @@ void DrawingML::WriteDiagram(const css::uno::Reference<css::drawing::XShape>& rX
awt::Point aPos = xShapeBg->getPosition();
awt::Size aSize = xShapeBg->getSize();
WriteTransformation(
- tools::Rectangle(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height)),
+ xShapeBg, tools::Rectangle(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height)),
XML_p, false, false, 0, false);
}
diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx
index aae5ed633d85..b217358b6197 100644
--- a/oox/source/export/shapes.cxx
+++ b/oox/source/export/shapes.cxx
@@ -400,7 +400,9 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const Reference< XShape >& xSha
pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp));
tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon( xShape );
- tools::Rectangle aRect( aPolyPolygon.GetBoundRect() );
+ awt::Point aPos = xShape->getPosition();
+ awt::Size aSize = xShape->getSize();
+ tools::Rectangle aRect(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height));
#if OSL_DEBUG_LEVEL > 0
awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) );
@@ -425,7 +427,7 @@ ShapeExport& ShapeExport::WritePolyPolygonShape( const Reference< XShape >& xSha
// visual shape properties
pFS->startElementNS(mnXmlNamespace, XML_spPr);
- WriteTransformation( aRect, XML_a );
+ WriteTransformation( xShape, aRect, XML_a );
WritePolyPolygon(xShape, aPolyPolygon, bClosed);
Reference< XPropertySet > xProps( xShape, UNO_QUERY );
if( xProps.is() ) {
@@ -1344,7 +1346,7 @@ ShapeExport& ShapeExport::WriteConnectorShape( const Reference< XShape >& xShape
// visual shape properties
pFS->startElementNS(mnXmlNamespace, XML_spPr);
- WriteTransformation( aRect, XML_a, bFlipH, bFlipV );
+ WriteTransformation( xShape, aRect, XML_a, bFlipH, bFlipV );
// TODO: write adjustments (ppt export doesn't work well there either)
WritePresetShape( sGeometry );
Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
index d7bdc09c0c34..a8477c523e53 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
@@ -126,11 +126,11 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testDmlTextshapeB, "dml-textshapeB.docx")
uno::Reference<drawing::XShape> xShape(xGroup->getByIndex(3), uno::UNO_QUERY);
// Connector was incorrectly shifted towards the top left corner, X was 192, Y was -5743.
CPPUNIT_ASSERT_EQUAL(sal_Int32(3778), xShape->getPosition().X);
- CPPUNIT_ASSERT_EQUAL(sal_Int32(-5064), xShape->getPosition().Y);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-5066), xShape->getPosition().Y);
xShape.set(xGroup->getByIndex(5), uno::UNO_QUERY);
// This was incorrectly shifted towards the top of the page, Y was -5011.
- CPPUNIT_ASSERT_EQUAL(sal_Int32(-4713), xShape->getPosition().Y);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-4715), xShape->getPosition().Y);
}
DECLARE_OOXMLEXPORT_TEST(testDMLSolidfillAlpha, "dml-solidfill-alpha.docx")