summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/oox/drawingml/drawingmltypes.hxx7
-rw-r--r--include/oox/drawingml/shape.hxx10
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.cxx133
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.hxx27
-rw-r--r--oox/source/drawingml/diagram/layoutatomvisitors.cxx7
-rw-r--r--oox/source/drawingml/diagram/layoutnodecontext.cxx1
-rw-r--r--oox/source/drawingml/shape.cxx7
-rw-r--r--sd/qa/unit/data/pptx/smartart-picture-strip.pptxbin0 -> 52395 bytes
-rw-r--r--sd/qa/unit/import-tests-smartart.cxx85
9 files changed, 250 insertions, 27 deletions
diff --git a/include/oox/drawingml/drawingmltypes.hxx b/include/oox/drawingml/drawingmltypes.hxx
index c4f05fcdd84e..2abe05767d6a 100644
--- a/include/oox/drawingml/drawingmltypes.hxx
+++ b/include/oox/drawingml/drawingmltypes.hxx
@@ -190,6 +190,13 @@ inline float convertEmuToPoints( sal_Int64 nValue )
return static_cast<float>(nValue) / EMU_PER_PT;
}
+/** Converts the passed double value from points to mm. */
+inline double convertPointToMms(double fValue)
+{
+ constexpr double fFactor = static_cast<double>(EMU_PER_PT) / (EMU_PER_HMM * 100);
+ return fValue * fFactor;
+}
+
/** A structure for a point with 64-bit integer components. */
struct EmuPoint
{
diff --git a/include/oox/drawingml/shape.hxx b/include/oox/drawingml/shape.hxx
index 4a571213a090..40a80ae113dc 100644
--- a/include/oox/drawingml/shape.hxx
+++ b/include/oox/drawingml/shape.hxx
@@ -226,6 +226,13 @@ public:
sal_Int32 getDataNodeType() const { return mnDataNodeType; }
+ void setAspectRatio(double fAspectRatio) { mfAspectRatio = fAspectRatio; }
+
+ double getAspectRatio() const { return mfAspectRatio; }
+
+ /// Changes reference semantics to value semantics for fill properties.
+ void cloneFillProperties();
+
protected:
css::uno::Reference< css::drawing::XShape > const &
@@ -348,6 +355,9 @@ private:
/// Type of data node for an in-diagram shape.
sal_Int32 mnDataNodeType = 0;
+
+ /// Aspect ratio for an in-diagram shape.
+ double mfAspectRatio = 0;
};
} }
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index 09edf0022259..247b99d0baad 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -65,6 +65,24 @@ bool isFontUnit(sal_Int32 nUnit)
return nUnit == oox::XML_primFontSz || nUnit == oox::XML_secFontSz;
}
+/// Determines which UNO property should be set for a given constraint type.
+sal_Int32 getPropertyFromConstraint(sal_Int32 nConstraint)
+{
+ switch (nConstraint)
+ {
+ case oox::XML_lMarg:
+ return oox::PROP_TextLeftDistance;
+ case oox::XML_rMarg:
+ return oox::PROP_TextRightDistance;
+ case oox::XML_tMarg:
+ return oox::PROP_TextUpperDistance;
+ case oox::XML_bMarg:
+ return oox::PROP_TextLowerDistance;
+ }
+
+ return 0;
+}
+
/// Determines the connector shape type from a linear alg.
sal_Int32 getConnectorType(const oox::drawingml::LayoutNode* pNode)
{
@@ -246,7 +264,7 @@ void LayoutAtom::dump(int level)
pAtom->dump(level + 1);
}
-ForEachAtom::ForEachAtom(const LayoutNode& rLayoutNode, const Reference< XFastAttributeList >& xAttributes) :
+ForEachAtom::ForEachAtom(LayoutNode& rLayoutNode, const Reference< XFastAttributeList >& xAttributes) :
LayoutAtom(rLayoutNode)
{
maIter.loadFromXAttr(xAttributes);
@@ -273,7 +291,7 @@ const std::vector<LayoutAtomPtr>& ChooseAtom::getChildren() const
return maEmptyChildren;
}
-ConditionAtom::ConditionAtom(const LayoutNode& rLayoutNode, bool isElse, const Reference< XFastAttributeList >& xAttributes) :
+ConditionAtom::ConditionAtom(LayoutNode& rLayoutNode, bool isElse, const Reference< XFastAttributeList >& xAttributes) :
LayoutAtom(rLayoutNode),
mIsElse(isElse)
{
@@ -447,6 +465,21 @@ void ConstraintAtom::accept( LayoutAtomVisitor& rVisitor )
void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints,
bool bRequireForName) const
{
+ // Whitelist for cases where empty forName is handled.
+ if (bRequireForName)
+ {
+ switch (maConstraint.mnType)
+ {
+ case XML_sp:
+ case XML_lMarg:
+ case XML_rMarg:
+ case XML_tMarg:
+ case XML_bMarg:
+ bRequireForName = false;
+ break;
+ }
+ }
+
if (bRequireForName && maConstraint.msForName.isEmpty())
return;
@@ -464,7 +497,7 @@ void AlgAtom::accept( LayoutAtomVisitor& rVisitor )
}
void AlgAtom::layoutShape( const ShapePtr& rShape,
- const std::vector<Constraint>& rOwnConstraints ) const
+ const std::vector<Constraint>& rOwnConstraints )
{
// Algorithm result may depend on the parent constraints as well.
std::vector<Constraint> aMergedConstraints;
@@ -860,6 +893,18 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0)
break;
+ // Parse constraints, only self spacing from height as a start.
+ double fSpaceFromConstraint = 0;
+ for (const auto& rConstr : rConstraints)
+ {
+ if (rConstr.mnRefType == XML_h)
+ {
+ if (rConstr.mnType == XML_sp && rConstr.msForName.isEmpty())
+ fSpaceFromConstraint = rConstr.mfFactor;
+ }
+ }
+ bool bSpaceFromConstraints = fSpaceFromConstraint != 0;
+
const sal_Int32 nDir = maMap.count(XML_grDir) ? maMap.find(XML_grDir)->second : XML_tL;
sal_Int32 nIncX = 1;
sal_Int32 nIncY = 1;
@@ -871,38 +916,67 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
case XML_bR: nIncX = -1; nIncY = -1; break;
}
- // TODO: get values from constraints
sal_Int32 nCount = rShape->getChildren().size();
- double fSpace = 0.3;
+ // Defaults in case not provided by constraints.
+ double fSpace = bSpaceFromConstraints ? fSpaceFromConstraint : 0.3;
double fAspectRatio = 0.54; // diagram should not spill outside, earlier it was 0.6
sal_Int32 nCol = 1;
sal_Int32 nRow = 1;
- for ( ; nRow<nCount; nRow++)
+ double fChildAspectRatio = rShape->getChildren()[0]->getAspectRatio();
+ if (nCount <= fChildAspectRatio)
+ // Child aspect ratio request (width/height) is N, and we have at most N shapes.
+ // This means we don't need multiple columns.
+ nRow = nCount;
+ else
{
- nCol = (nCount+nRow-1) / nRow;
- const double fShapeHeight = rShape->getSize().Height;
- const double fShapeWidth = rShape->getSize().Width;
- if ((fShapeHeight / nCol) / (fShapeWidth / nRow) >= fAspectRatio)
- break;
+ for ( ; nRow<nCount; nRow++)
+ {
+ nCol = (nCount+nRow-1) / nRow;
+ const double fShapeHeight = rShape->getSize().Height;
+ const double fShapeWidth = rShape->getSize().Width;
+ if ((fShapeHeight / nCol) / (fShapeWidth / nRow) >= fAspectRatio)
+ break;
+ }
}
SAL_INFO("oox.drawingml", "Snake layout grid: " << nCol << "x" << nRow);
sal_Int32 nWidth = rShape->getSize().Width / (nCol + (nCol-1)*fSpace);
- const awt::Size aChildSize(nWidth, nWidth * fAspectRatio);
+ awt::Size aChildSize(nWidth, nWidth * fAspectRatio);
+ if (nCol == 1 && nRow > 1)
+ {
+ // We have a single column, so count the height based on the parent height, not
+ // based on width.
+ // Space occurs inside children; also double amount of space is needed outside (on
+ // both sides), if the factor comes from a constraint.
+ sal_Int32 nNumSpaces = -1;
+ if (bSpaceFromConstraints)
+ nNumSpaces += 4;
+ sal_Int32 nHeight
+ = rShape->getSize().Height / (nRow + (nRow + nNumSpaces) * fSpace);
+
+ if (fChildAspectRatio > 1)
+ {
+ // Shrink width if the aspect ratio requires it.
+ nWidth = std::min(rShape->getSize().Width,
+ static_cast<sal_Int32>(nHeight * fChildAspectRatio));
+ aChildSize = awt::Size(nWidth, nHeight);
+ }
+ }
awt::Point aCurrPos(0, 0);
if (nIncX == -1)
aCurrPos.X = rShape->getSize().Width - aChildSize.Width;
if (nIncY == -1)
aCurrPos.Y = rShape->getSize().Height - aChildSize.Height;
+ else if (bSpaceFromConstraints)
+ // Initial vertical offset to have upper spacing (outside, so double amount).
+ aCurrPos.Y = aChildSize.Height * fSpace * 2;
sal_Int32 nStartX = aCurrPos.X;
sal_Int32 nColIdx = 0,index = 0;
- sal_Int32 num = rShape->getChildren().size();
-
const sal_Int32 aContDir = maMap.count(XML_contDir) ? maMap.find(XML_contDir)->second : XML_sameDir;
switch(aContDir)
@@ -922,7 +996,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
if(++nColIdx == nCol) // condition for next row
{
// if last row, then position children according to number of shapes.
- if((index+1)%nCol!=0 && (index+1)>=3 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol)
+ if((index+1)%nCol!=0 && (index+1)>=3 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol)
// position first child of last row
aCurrPos.X = nStartX + (nIncX * (aChildSize.Width + fSpace*aChildSize.Width))/2;
else
@@ -961,10 +1035,10 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
if(++nColIdx == nCol) // condition for next row
{
// if last row, then position children according to number of shapes.
- if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol && ((index/nCol)+1)%2==0)
+ if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol && ((index/nCol)+1)%2==0)
// position first child of last row
aCurrPos.X -= aChildSize.Width*3/2;
- else if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol && ((index/nCol)+1)%2!=0)
+ else if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol && ((index/nCol)+1)%2!=0)
aCurrPos.X = nStartX + (nIncX * (aChildSize.Width + fSpace*aChildSize.Width))/2;
else if(((index/nCol)+1)%2!=0)
aCurrPos.X = nStartX;
@@ -997,6 +1071,29 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
case XML_tx:
{
// adjust text alignment
+
+ // Parse constraints, only self margins as a start.
+ for (const auto& rConstr : rConstraints)
+ {
+ if (rConstr.mnRefType == XML_w)
+ {
+ if (!rConstr.msForName.isEmpty())
+ continue;
+
+ sal_Int32 nProperty = getPropertyFromConstraint(rConstr.mnType);
+ if (!nProperty)
+ continue;
+
+ // PowerPoint takes size as points, but gives margin as MMs.
+ double fFactor = convertPointToMms(rConstr.mfFactor);
+
+ // DrawingML works in EMUs, UNO API works in MM100s.
+ sal_Int32 nValue = rShape->getSize().Width * fFactor / EMU_PER_HMM;
+
+ rShape->getShapeProperties().setProperty(nProperty, nValue);
+ }
+ }
+
// TODO: adjust text size to fit shape
TextBodyPtr pTextBody = rShape->getTextBody();
if (!pTextBody ||
@@ -1220,6 +1317,8 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode
" processing shape type "
<< rShape->getCustomShapeProperties()->getShapePresetType()
<< " for layout node named \"" << msName << "\"");
+ if (pPresNode->mpShape)
+ rShape->getFillProperties().assignUsed(pPresNode->mpShape->getFillProperties());
}
// TODO(Q1): apply styling & coloring - take presentation
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
index 75149a5cbecd..9b184f917f17 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx
@@ -91,10 +91,10 @@ typedef std::shared_ptr< LayoutAtom > LayoutAtomPtr;
class LayoutAtom
{
public:
- LayoutAtom(const LayoutNode& rLayoutNode) : mrLayoutNode(rLayoutNode) {}
+ LayoutAtom(LayoutNode& rLayoutNode) : mrLayoutNode(rLayoutNode) {}
virtual ~LayoutAtom() { }
- const LayoutNode& getLayoutNode() const
+ LayoutNode& getLayoutNode()
{ return mrLayoutNode; }
/** visitor acceptance
@@ -127,7 +127,7 @@ public:
void dump(int level = 0);
protected:
- const LayoutNode& mrLayoutNode;
+ LayoutNode& mrLayoutNode;
std::vector< LayoutAtomPtr > mpChildNodes;
std::weak_ptr<LayoutAtom> mpParent;
OUString msName;
@@ -137,7 +137,7 @@ class ConstraintAtom
: public LayoutAtom
{
public:
- ConstraintAtom(const LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode) {}
+ ConstraintAtom(LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode) {}
virtual void accept( LayoutAtomVisitor& ) override;
Constraint& getConstraint()
{ return maConstraint; }
@@ -150,7 +150,7 @@ class AlgAtom
: public LayoutAtom
{
public:
- AlgAtom(const LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode), mnType(0), maMap() {}
+ AlgAtom(LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode), mnType(0), maMap() {}
typedef std::map<sal_Int32,sal_Int32> ParamMap;
@@ -161,7 +161,7 @@ public:
void addParam( sal_Int32 nType, sal_Int32 nVal )
{ maMap[nType]=nVal; }
void layoutShape( const ShapePtr& rShape,
- const std::vector<Constraint>& rConstraints ) const;
+ const std::vector<Constraint>& rConstraints );
/// Gives access to <dgm:alg type="..."/>.
sal_Int32 getType() const { return mnType; }
@@ -171,6 +171,8 @@ public:
void setAspectRatio(double fAspectRatio) { mfAspectRatio = fAspectRatio; }
+ double getAspectRatio() const { return mfAspectRatio; }
+
private:
sal_Int32 mnType;
ParamMap maMap;
@@ -184,7 +186,7 @@ class ForEachAtom
: public LayoutAtom
{
public:
- explicit ForEachAtom(const LayoutNode& rLayoutNode, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes);
+ explicit ForEachAtom(LayoutNode& rLayoutNode, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes);
IteratorAttr & iterator()
{ return maIter; }
@@ -200,7 +202,7 @@ class ConditionAtom
: public LayoutAtom
{
public:
- explicit ConditionAtom(const LayoutNode& rLayoutNode, bool isElse, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes);
+ explicit ConditionAtom(LayoutNode& rLayoutNode, bool isElse, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttributes);
virtual void accept( LayoutAtomVisitor& ) override;
bool getDecision() const;
private:
@@ -220,7 +222,7 @@ class ChooseAtom
: public LayoutAtom
{
public:
- ChooseAtom(const LayoutNode& rLayoutNode)
+ ChooseAtom(LayoutNode& rLayoutNode)
: LayoutAtom(rLayoutNode)
#if defined __clang__ && __clang_major__ == 3 && __clang_minor__ == 8
, maEmptyChildren()
@@ -264,6 +266,10 @@ public:
const LayoutNode* getParentLayoutNode() const;
+ void setAlgAtom(AlgAtomPtr pAlgAtom) { mpAlgAtom = pAlgAtom; }
+
+ AlgAtomPtr getAlgAtom() const { return mpAlgAtom.lock(); }
+
private:
const Diagram& mrDgm;
VarMap mVariables;
@@ -272,6 +278,7 @@ private:
ShapePtr mpExistingShape;
std::vector<ShapePtr> mpNodeShapes;
sal_Int32 mnChildOrder;
+ std::weak_ptr<AlgAtom> mpAlgAtom;
};
typedef std::shared_ptr< LayoutNode > LayoutNodePtr;
@@ -280,7 +287,7 @@ class ShapeAtom
: public LayoutAtom
{
public:
- ShapeAtom(const LayoutNode& rLayoutNode, const ShapePtr& pShape) : LayoutAtom(rLayoutNode), mpShapeTemplate(pShape) {}
+ ShapeAtom(LayoutNode& rLayoutNode, const ShapePtr& pShape) : LayoutAtom(rLayoutNode), mpShapeTemplate(pShape) {}
virtual void accept( LayoutAtomVisitor& ) override;
const ShapePtr& getShapeTemplate() const
{ return mpShapeTemplate; }
diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
index e2d6c4681b5c..4e69e8c8725b 100644
--- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx
+++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx
@@ -131,6 +131,8 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom)
if (rAtom.setupShape(pShape, pNewNode))
{
pShape->setInternalName(rAtom.getName());
+ if (AlgAtomPtr pAlgAtom = rAtom.getAlgAtom())
+ pShape->setAspectRatio(pAlgAtom->getAspectRatio());
rAtom.addNodeShape(pShape);
}
}
@@ -151,6 +153,8 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom)
if (rAtom.setupShape(pShape, pNewNode))
{
pShape->setInternalName(rAtom.getName());
+ if (AlgAtomPtr pAlgAtom = rAtom.getAlgAtom())
+ pShape->setAspectRatio(pAlgAtom->getAspectRatio());
pCurrParent->addChild(pShape);
pCurrParent = pShape;
rAtom.addNodeShape(pShape);
@@ -270,6 +274,9 @@ void ShapeTemplateVisitor::visit(ShapeAtom& rAtom)
// TODO(F3): cloned shape shares all properties by reference,
// don't change them!
mpShape.reset(new Shape(pCurrShape));
+ // Fill properties have to be changed as sometimes only the presentation node contains the blip
+ // fill, unshare those.
+ mpShape->cloneFillProperties();
}
void ShapeLayoutingVisitor::defaultVisit(LayoutAtom const & rAtom)
diff --git a/oox/source/drawingml/diagram/layoutnodecontext.cxx b/oox/source/drawingml/diagram/layoutnodecontext.cxx
index 24264135478b..646ab5ecd3da 100644
--- a/oox/source/drawingml/diagram/layoutnodecontext.cxx
+++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx
@@ -230,6 +230,7 @@ LayoutNodeContext::onCreateContext( ::sal_Int32 aElement,
// CT_Algorithm
AlgAtomPtr pAtom( new AlgAtom(mpNode->getLayoutNode()) );
LayoutAtom::connect(mpNode, pAtom);
+ mpNode->getLayoutNode().setAlgAtom(pAtom);
return new AlgorithmContext( *this, rAttribs, pAtom );
}
case DGM_TOKEN( choose ):
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index 55d154642960..4c552194b08a 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -178,6 +178,7 @@ Shape::Shape( const ShapePtr& pSourceShape )
, mnZOrder(pSourceShape->mnZOrder)
, mnZOrderOff(pSourceShape->mnZOrderOff)
, mnDataNodeType(pSourceShape->mnDataNodeType)
+, mfAspectRatio(pSourceShape->mfAspectRatio)
{}
Shape::~Shape()
@@ -1806,6 +1807,12 @@ uno::Sequence< uno::Sequence< uno::Any > > Shape::resolveRelationshipsOfTypeFro
return xRelListTemp;
}
+void Shape::cloneFillProperties()
+{
+ auto pFillProperties = std::make_shared<FillProperties>();
+ pFillProperties->assignUsed(*mpFillPropertiesPtr);
+ mpFillPropertiesPtr = pFillProperties;
+}
} }
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/qa/unit/data/pptx/smartart-picture-strip.pptx b/sd/qa/unit/data/pptx/smartart-picture-strip.pptx
new file mode 100644
index 000000000000..bfb8d4f2c1bd
--- /dev/null
+++ b/sd/qa/unit/data/pptx/smartart-picture-strip.pptx
Binary files differ
diff --git a/sd/qa/unit/import-tests-smartart.cxx b/sd/qa/unit/import-tests-smartart.cxx
index 29f998ce6f43..b1ced877c00d 100644
--- a/sd/qa/unit/import-tests-smartart.cxx
+++ b/sd/qa/unit/import-tests-smartart.cxx
@@ -15,6 +15,7 @@
#include <com/sun/star/text/XText.hpp>
#include <comphelper/sequenceashashmap.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
using namespace ::com::sun::star;
@@ -52,6 +53,7 @@ public:
void testContinuousBlockProcess();
void testOrgChart();
void testCycleMatrix();
+ void testPictureStrip();
CPPUNIT_TEST_SUITE(SdImportTestSmartArt);
@@ -69,6 +71,7 @@ public:
CPPUNIT_TEST(testContinuousBlockProcess);
CPPUNIT_TEST(testOrgChart);
CPPUNIT_TEST(testCycleMatrix);
+ CPPUNIT_TEST(testPictureStrip);
CPPUNIT_TEST_SUITE_END();
};
@@ -640,6 +643,88 @@ void SdImportTestSmartArt::testCycleMatrix()
xDocShRef->DoClose();
}
+void SdImportTestSmartArt::testPictureStrip()
+{
+ sd::DrawDocShellRef xDocShRef = loadURL(
+ m_directories.getURLFromSrc("/sd/qa/unit/data/pptx/smartart-picture-strip.pptx"), PPTX);
+ uno::Reference<drawing::XShape> xGroup(getShapeFromPage(0, 0, xDocShRef), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xGroup.is());
+
+ uno::Reference<beans::XPropertySet> xFirstImage(getChildShape(getChildShape(xGroup, 0), 1),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xFirstImage.is());
+ drawing::FillStyle eFillStyle = drawing::FillStyle_NONE;
+ xFirstImage->getPropertyValue("FillStyle") >>= eFillStyle;
+ // Without the accompanying fix in place, this test would have failed: fill style was solid, not
+ // bitmap.
+ CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP, eFillStyle);
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+ xFirstImage->getPropertyValue("FillBitmap") >>= xGraphic;
+ Graphic aFirstGraphic(xGraphic);
+
+ uno::Reference<beans::XPropertySet> xSecondImage(getChildShape(getChildShape(xGroup, 1), 1),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xSecondImage.is());
+ eFillStyle = drawing::FillStyle_NONE;
+ xSecondImage->getPropertyValue("FillStyle") >>= eFillStyle;
+ CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_BITMAP, eFillStyle);
+
+ xSecondImage->getPropertyValue("FillBitmap") >>= xGraphic;
+ Graphic aSecondGraphic(xGraphic);
+ // Without the accompanying fix in place, this test would have failed: both xFirstImage and
+ // xSecondImage had the bitmap fill from the second shape.
+ CPPUNIT_ASSERT(aFirstGraphic.GetChecksum() != aSecondGraphic.GetChecksum());
+
+ // Test that the 3 images are in a single column, in 3 rows.
+ uno::Reference<drawing::XShape> xFirstImageShape(xFirstImage, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xFirstImage.is());
+ uno::Reference<drawing::XShape> xSecondImageShape(xSecondImage, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xSecondImage.is());
+ uno::Reference<drawing::XShape> xThirdImageShape(getChildShape(getChildShape(xGroup, 2), 1),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xThirdImageShape.is());
+ // Without the accompanying fix in place, this test would have failed: the first and the second
+ // image were in the same row.
+ CPPUNIT_ASSERT_EQUAL(xFirstImageShape->getPosition().X, xSecondImageShape->getPosition().X);
+ CPPUNIT_ASSERT_EQUAL(xSecondImageShape->getPosition().X, xThirdImageShape->getPosition().X);
+ CPPUNIT_ASSERT_GREATER(xFirstImageShape->getPosition().Y, xSecondImageShape->getPosition().Y);
+ CPPUNIT_ASSERT_GREATER(xSecondImageShape->getPosition().Y, xThirdImageShape->getPosition().Y);
+
+ // Make sure that the title shape doesn't overlap with the diagram.
+ // Note that real "no overlap" is asserted here, though in fact what we want is a less strict
+ // condition: that no text part of the title shape and the diagram overlaps.
+ uno::Reference<drawing::XShape> xTitle(getShapeFromPage(1, 0, xDocShRef), uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xTitle.is());
+ // Without the accompanying fix in place, this test would have failed with 'Expected greater
+ // than: 2873; Actual : 2320', i.e. the title shape and the diagram overlapped.
+ CPPUNIT_ASSERT_GREATER(xTitle->getPosition().Y + xTitle->getSize().Height,
+ xGroup->getPosition().Y);
+
+ // Make sure that left margin is 60% of width (if you count width in points and margin in mms).
+ uno::Reference<beans::XPropertySet> xFirstText(getChildShape(getChildShape(xGroup, 0), 0),
+ uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xFirstText.is());
+ sal_Int32 nTextLeftDistance = 0;
+ xFirstText->getPropertyValue("TextLeftDistance") >>= nTextLeftDistance;
+ uno::Reference<drawing::XShape> xFirstTextShape(xFirstText, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xFirstTextShape.is());
+ sal_Int32 nWidth = xFirstTextShape->getSize().Width;
+ double fFactor = oox::drawingml::convertPointToMms(0.6);
+ // Without the accompanying fix in place, this test would have failed with 'Expected: 3440,
+ // Actual : 263', i.e. the left margin was too small.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(nWidth * fFactor), nTextLeftDistance);
+
+ // Make sure that aspect ratio is not ignored, i.e. width is not larger than height 3 times.
+ uno::Reference<drawing::XShape> xFirstPair = getChildShape(xGroup, 0);
+ awt::Size aFirstPairSize = xFirstPair->getSize();
+ // Without the accompanying fix in place, this test would have failed: bad width was 16932, good
+ // width is 12540, but let's accept 12541 as well.
+ CPPUNIT_ASSERT_LESSEQUAL(aFirstPairSize.Height * 3 + 1, aFirstPairSize.Width);
+
+ xDocShRef->DoClose();
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(SdImportTestSmartArt);
CPPUNIT_PLUGIN_IMPLEMENT();