include/oox/shape/ShapeContextHandler.hxx | 2 oox/source/shape/ShapeContextHandler.cxx | 6 + writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx | 52 ++++++++++ writerfilter/qa/cppunittests/dmapper/data/tdf149840_SmartArtBackground.docx |binary writerfilter/source/dmapper/GraphicHelpers.cxx | 47 +++++++++ writerfilter/source/dmapper/GraphicHelpers.hxx | 14 ++ writerfilter/source/ooxml/OOXMLFastContextHandler.cxx | 38 +++++++ 7 files changed, 158 insertions(+), 1 deletion(-)
New commits: commit e4515c1305e4b7bf6e7f105636e9cf6eb50b382d Author: Regina Henschel <[email protected]> AuthorDate: Tue Oct 11 14:46:37 2022 +0200 Commit: Miklos Vajna <[email protected]> CommitDate: Thu Oct 13 08:56:22 2022 +0200 tdf#149840 Use actual outer size for SmartArt in Writer SmartArt import needs the outer size of the diagram for to define a background shape in the correct size and calculate the size of the diagram shapes relative to the outer size. The patch passes the values read from wp:extent in writerfilter to DiagramGraphicDataContext in oox. Change-Id: Ib39227bc645ac353336bab2c558d041974188f6f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141223 Tested-by: Jenkins Reviewed-by: Regina Henschel <[email protected]> Reviewed-by: Miklos Vajna <[email protected]> diff --git a/include/oox/shape/ShapeContextHandler.hxx b/include/oox/shape/ShapeContextHandler.hxx index 1b024c6013e1..239ff8ec63b8 100644 --- a/include/oox/shape/ShapeContextHandler.hxx +++ b/include/oox/shape/ShapeContextHandler.hxx @@ -95,6 +95,7 @@ public: void pushStartToken( sal_Int32 _starttoken ); void setPosition(const css::awt::Point& rPosition); + void setSize(const css::awt::Size& rSize); const bool& getFullWPGSupport() { return m_bFullWPGSUpport; } void setFullWPGSupport(bool bUse) { m_bFullWPGSUpport = bUse; } @@ -118,6 +119,7 @@ private: std::stack<sal_uInt32> mnStartTokenStack; css::awt::Point maPosition; + css::awt::Size maSize; // from cx and cy, in EMU bool m_bFullWPGSUpport; // Is this DrawingML shape supposed to be processed as WPG? drawingml::ShapePtr mpShape; diff --git a/oox/source/shape/ShapeContextHandler.cxx b/oox/source/shape/ShapeContextHandler.cxx index 2e4018e4703c..54a455452365 100644 --- a/oox/source/shape/ShapeContextHandler.cxx +++ b/oox/source/shape/ShapeContextHandler.cxx @@ -215,6 +215,7 @@ ShapeContextHandler::getDiagramShapeContext() { auto pFragmentHandler = std::make_shared<ShapeFragmentHandler>(*mxShapeFilterBase, msRelationFragmentPath); mpShape = std::make_shared<Shape>(); + mpShape->setSize(maSize); mxDiagramShapeContext.set(new DiagramGraphicDataContext(*pFragmentHandler, mpShape)); } @@ -564,6 +565,11 @@ void ShapeContextHandler::setPosition(const awt::Point& rPosition) maPosition = rPosition; } +void ShapeContextHandler::setSize(const awt::Size& rSize) +{ + maSize = rSize; +} + void ShapeContextHandler::setDocumentProperties(const uno::Reference<document::XDocumentProperties>& xDocProps) { mxDocumentProperties = xDocProps; diff --git a/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx index a20c8490501b..6d77ece16d9d 100644 --- a/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx +++ b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx @@ -23,6 +23,7 @@ #include <com/sun/star/drawing/PointSequenceSequence.hpp> #include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <officecfg/Office/Common.hxx> using namespace ::com::sun::star; @@ -406,6 +407,57 @@ CPPUNIT_TEST_FIXTURE(Test, testLayoutInCellOfHraphics) CPPUNIT_ASSERT(xShape->getPropertyValue("IsFollowingTextFlow") >>= bFollowingTextFlow); CPPUNIT_ASSERT(bFollowingTextFlow); } + +CPPUNIT_TEST_FIXTURE(Test, testTdf149840SmartArtBackground) +{ + // Make sure SmartArt is loaded as group shape + bool bUseGroup = officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::get(); + if (!bUseGroup) + { + std::shared_ptr<comphelper::ConfigurationChanges> pChange( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::set(true, pChange); + pChange->commit(); + } + + OUString aURL + = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf149840_SmartArtBackground.docx"; + getComponent() = loadFromDesktop(aURL); + uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage(); + uno::Reference<container::XIndexAccess> xGroup(xDrawPage->getByIndex(0), uno::UNO_QUERY); + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(3), xGroup->getCount()); + + // The first shape in the group, which represents the SmartArt, corresponds to the background of + // the diagram. Without fix in place it has widht and height zero, which does not only result in + // not visible background but in wrong sizes of the diagram shapes too. + uno::Reference<drawing::XShape> xBackgroundShape(xGroup->getByIndex(0), uno::UNO_QUERY); + awt::Size aBackgroundSize = xBackgroundShape->getSize(); + // Toleranzes are for rounding inaccuracies. + // The test would have failed with Expected: 9560x5036, Actual: 2x2 + CPPUNIT_ASSERT_DOUBLES_EQUAL(static_cast<sal_Int32>(9560), aBackgroundSize.Width, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(static_cast<sal_Int32>(5036), aBackgroundSize.Height, 1); + + uno::Reference<drawing::XShape> xShapeOne(xGroup->getByIndex(1), uno::UNO_QUERY); + awt::Size aShapeOneSize = xShapeOne->getSize(); + // The test would have failed with Expected: 3282x3709, Actual: 3972x3709 + CPPUNIT_ASSERT_DOUBLES_EQUAL(static_cast<sal_Int32>(3282), aShapeOneSize.Width, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(static_cast<sal_Int32>(3709), aShapeOneSize.Height, 1); + + uno::Reference<drawing::XShape> xShapeTwo(xGroup->getByIndex(2), uno::UNO_QUERY); + awt::Size aShapeTwoSize = xShapeTwo->getSize(); + // The test would have failed with Expected: 2404x5226, Actual: 2910x5226 + CPPUNIT_ASSERT_DOUBLES_EQUAL(static_cast<sal_Int32>(2404), aShapeTwoSize.Width, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(static_cast<sal_Int32>(5226), aShapeTwoSize.Height, 1); + + if (!bUseGroup) + { + std::shared_ptr<comphelper::ConfigurationChanges> pChange( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::set(false, pChange); + pChange->commit(); + } +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf149840_SmartArtBackground.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf149840_SmartArtBackground.docx new file mode 100644 index 000000000000..318cef8f3c4b Binary files /dev/null and b/writerfilter/qa/cppunittests/dmapper/data/tdf149840_SmartArtBackground.docx differ diff --git a/writerfilter/source/dmapper/GraphicHelpers.cxx b/writerfilter/source/dmapper/GraphicHelpers.cxx index 2c1a054b5c58..44949e28e754 100644 --- a/writerfilter/source/dmapper/GraphicHelpers.cxx +++ b/writerfilter/source/dmapper/GraphicHelpers.cxx @@ -324,6 +324,53 @@ sal_Int32 GraphicZOrderHelper::findZOrder( sal_Int32 relativeHeight, bool bOldSt return 0; // this should not(?) happen } +ExtentHandler::ExtentHandler() +{ +} + +ExtentHandler::~ExtentHandler() +{ +} + +void ExtentHandler::attribute(Id nName, Value & rValue) +{ + sal_Int32 nIntValue = rValue.getInt(); + switch (nName) + { + case NS_ooxml::LN_CT_PositiveSize2D_cx: + { + m_Extent.Width = nIntValue; + } + break; + case NS_ooxml::LN_CT_PositiveSize2D_cy: + { + m_Extent.Height = nIntValue; + } + break; + default: + break; + } +} + +void ExtentHandler::sprm(Sprm & rSprm) +{ + sal_uInt32 nSprmId = rSprm.getId(); + switch(nSprmId) + { + case NS_ooxml::LN_CT_Inline_extent: + case NS_ooxml::LN_CT_Anchor_extent: + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if( pProperties ) + { + pProperties->resolve(*this); + } + } + break; + default: + break; + } +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/source/dmapper/GraphicHelpers.hxx b/writerfilter/source/dmapper/GraphicHelpers.hxx index 1e7e7a5b3b5b..21eb65f88402 100644 --- a/writerfilter/source/dmapper/GraphicHelpers.hxx +++ b/writerfilter/source/dmapper/GraphicHelpers.hxx @@ -63,6 +63,20 @@ private: sal_Int32 m_nType; sal_Int32 m_nSide; }; + +class ExtentHandler : public Properties +{ + css::awt::Size m_Extent; // width and height in EMU + +public: + typedef ::tools::SvRef<ExtentHandler> Pointer_t; + explicit ExtentHandler(); + virtual ~ExtentHandler() override; + + virtual void attribute(Id nName, Value& rValue) override; + virtual void sprm(Sprm& rSprm) override; + css::awt::Size getExtent() const { return m_Extent; } +}; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx index f91fbf0d9b2f..16169b318971 100644 --- a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx @@ -39,6 +39,8 @@ #include <dmapper/PropertyIds.hxx> #include <comphelper/propertysequence.hxx> #include <comphelper/sequenceashashmap.hxx> +#include "OOXMLPropertySet.hxx" +#include <dmapper/GraphicHelpers.hxx> const sal_Unicode uCR = 0xd; const sal_Unicode uFtnEdnRef = 0x2; @@ -231,7 +233,6 @@ void OOXMLFastContextHandler::lcl_startFastElement inPositionV = true; else if( Element == (NMSP_dmlWordDr|XML_positionH) ) inPositionV = false; - } void OOXMLFastContextHandler::lcl_endFastElement @@ -1684,6 +1685,41 @@ void OOXMLFastContextHandlerShape::lcl_startFastElement if (mrShapeContext.is()) { + if (Element == DGM_TOKEN(relIds)) + { + // It is a SmartArt. Make size available for generated group. + // Search for PropertySet in parents + OOXMLFastContextHandler* pHandler = getParent(); + while (pHandler && pHandler->getId() != NS_ooxml::LN_anchor_anchor + && pHandler->getId() != NS_ooxml::LN_inline_inline) + { + pHandler = pHandler->getParent(); + } + // Search for extent + if (pHandler) + { + if (const OOXMLPropertySet::Pointer_t pPropSet = pHandler->getPropertySet()) + { + auto aIt = pPropSet->begin(); + auto aItEnd = pPropSet->end(); + while (aIt != aItEnd && (*aIt)->getId() != NS_ooxml::LN_CT_Inline_extent + && (*aIt)->getId() != NS_ooxml::LN_CT_Anchor_extent) + { + ++aIt; + } + if (aIt != aItEnd) + { + writerfilter::Reference<Properties>::Pointer_t pProperties = (*aIt)->getProps(); + if (pProperties) + { + writerfilter::dmapper::ExtentHandler::Pointer_t pExtentHandler(new writerfilter::dmapper::ExtentHandler()); + pProperties->resolve(*pExtentHandler); + mrShapeContext->setSize(pExtentHandler->getExtent()); + } + } + } + } + } mrShapeContext->startFastElement(Element, Attribs); } }
