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 <rb.henschel@t-online.de>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
Regina Henschel 2022-10-11 14:46:37 +02:00 committed by Miklos Vajna
parent 9e0dcfbaf0
commit e4515c1305
7 changed files with 158 additions and 1 deletions

View file

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

View file

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

View file

@ -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: */

View file

@ -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: */

View file

@ -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: */

View file

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