1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <oox/drawingml/shape.hxx>
21 #include <drawingml/customshapeproperties.hxx>
22 #include <oox/drawingml/theme.hxx>
23 #include <drawingml/fillproperties.hxx>
24 #include <drawingml/graphicproperties.hxx>
25 #include <drawingml/lineproperties.hxx>
26 #include <drawingml/presetgeometrynames.hxx>
27 #include <drawingml/shape3dproperties.hxx>
28 #include "effectproperties.hxx"
29 #include <oox/drawingml/shapepropertymap.hxx>
30 #include <drawingml/textbody.hxx>
31 #include <drawingml/textparagraph.hxx>
32 #include <drawingml/ThemeOverrideFragmentHandler.hxx>
33 #include <drawingml/table/tableproperties.hxx>
34 #include <oox/drawingml/chart/chartconverter.hxx>
35 #include <drawingml/chart/chartspacefragment.hxx>
36 #include <drawingml/chart/chartspacemodel.hxx>
37 #include <o3tl/safeint.hxx>
38 #include <o3tl/unit_conversion.hxx>
39 #include <oox/ppt/pptimport.hxx>
40 #include <oox/vml/vmldrawing.hxx>
41 #include <oox/vml/vmlshape.hxx>
42 #include <oox/vml/vmlshapecontainer.hxx>
43 #include <oox/core/xmlfilterbase.hxx>
44 #include <oox/helper/graphichelper.hxx>
45 #include <oox/helper/propertyset.hxx>
46 #include <oox/helper/modelobjecthelper.hxx>
47 #include <oox/mathml/importutils.hxx>
48 #include <oox/mathml/import.hxx>
49 #include <oox/token/properties.hxx>
50 #include "diagram/datamodel.hxx"
51 
52 #include <comphelper/classids.hxx>
53 #include <comphelper/propertysequence.hxx>
54 #include <comphelper/propertyvalue.hxx>
55 #include <comphelper/sequence.hxx>
56 #include <tools/diagnose_ex.h>
57 #include <tools/gen.hxx>
58 #include <tools/globname.hxx>
59 #include <tools/mapunit.hxx>
60 #include <tools/UnitConversion.hxx>
61 #include <editeng/unoprnms.hxx>
62 #include <com/sun/star/awt/Size.hpp>
63 #include <com/sun/star/awt/XBitmap.hpp>
64 #include <com/sun/star/awt/FontWeight.hpp>
65 #include <com/sun/star/graphic/XGraphic.hpp>
66 #include <com/sun/star/container/XNamed.hpp>
67 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
68 #include <com/sun/star/xml/dom/XDocument.hpp>
69 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
70 #include <com/sun/star/drawing/FillStyle.hpp>
71 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
72 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
73 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
74 #include <com/sun/star/drawing/XShapes.hpp>
75 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
76 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
77 #include <com/sun/star/embed/XEmbeddedObject.hpp>
78 #include <com/sun/star/text/XText.hpp>
79 #include <com/sun/star/table/BorderLine2.hpp>
80 #include <com/sun/star/table/ShadowFormat.hpp>
81 #include <com/sun/star/chart2/XChartDocument.hpp>
82 #include <com/sun/star/style/ParagraphAdjust.hpp>
83 #include <com/sun/star/io/XOutputStream.hpp>
84 
85 #include <basegfx/point/b2dpoint.hxx>
86 #include <basegfx/polygon/b2dpolygon.hxx>
87 #include <basegfx/matrix/b2dhommatrix.hxx>
88 #include <basegfx/matrix/b2dhommatrixtools.hxx>
89 #include <com/sun/star/document/XActionLockable.hpp>
90 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
91 #include <com/sun/star/text/GraphicCrop.hpp>
92 #include <svx/svdtrans.hxx>
93 #include <tools/stream.hxx>
94 #include <unotools/streamwrap.hxx>
95 #include <unotools/fltrcfg.hxx>
96 #include <vcl/graph.hxx>
97 #include <vcl/graphicfilter.hxx>
98 #include <vcl/svapp.hxx>
99 #include <vcl/wmfexternal.hxx>
100 #include <sal/log.hxx>
101 #include <svx/unoapi.hxx>
102 #include <svx/unoshape.hxx>
103 #include <svx/sdtaitm.hxx>
104 
105 using namespace ::oox::core;
106 using namespace ::com::sun::star;
107 using namespace ::com::sun::star::uno;
108 using namespace ::com::sun::star::beans;
109 using namespace ::com::sun::star::frame;
110 using namespace ::com::sun::star::text;
111 using namespace ::com::sun::star::drawing;
112 using namespace ::com::sun::star::style;
113 
114 namespace oox::drawingml {
115 
Shape(const char * pServiceName,bool bDefaultHeight)116 Shape::Shape( const char* pServiceName, bool bDefaultHeight )
117 : mpLinePropertiesPtr( std::make_shared<LineProperties>() )
118 , mpShapeRefLinePropPtr( std::make_shared<LineProperties>() )
119 , mpFillPropertiesPtr( std::make_shared<FillProperties>() )
120 , mpShapeRefFillPropPtr( std::make_shared<FillProperties>() )
121 , mpGraphicPropertiesPtr( std::make_shared<GraphicProperties>() )
122 , mpCustomShapePropertiesPtr( std::make_shared<CustomShapeProperties>() )
123 , mp3DPropertiesPtr( std::make_shared<Shape3DProperties>() )
124 , mpEffectPropertiesPtr( std::make_shared<EffectProperties>() )
125 , mpShapeRefEffectPropPtr( std::make_shared<EffectProperties>() )
126 , mpMasterTextListStyle( std::make_shared<TextListStyle>() )
127 , mnSubType( 0 )
128 , meFrameType( FRAMETYPE_GENERIC )
129 , mnRotation( 0 )
130 , mnDiagramRotation( 0 )
131 , mbFlipH( false )
132 , mbFlipV( false )
133 , mbHidden( false )
134 , mbHiddenMasterShape( false )
135 , mbLocked( false )
136 , mbLockedCanvas( false )
137 , mbWps( false )
138 , mbTextBox( false )
139 , mbHasLinkedTxbx( false )
140 , maDiagramDoms( 0 )
141 {
142     if ( pServiceName )
143         msServiceName = OUString::createFromAscii( pServiceName );
144     setDefaults(bDefaultHeight);
145 }
146 
Shape(const ShapePtr & pSourceShape)147 Shape::Shape( const ShapePtr& pSourceShape )
148 : maChildren()
149 , mpTextBody(pSourceShape->mpTextBody)
150 , mpLinePropertiesPtr( pSourceShape->mpLinePropertiesPtr )
151 , mpShapeRefLinePropPtr( pSourceShape->mpShapeRefLinePropPtr )
152 , mpFillPropertiesPtr( pSourceShape->mpFillPropertiesPtr )
153 , mpShapeRefFillPropPtr( pSourceShape->mpShapeRefFillPropPtr )
154 , mpGraphicPropertiesPtr( pSourceShape->mpGraphicPropertiesPtr )
155 , mpCustomShapePropertiesPtr( pSourceShape->mpCustomShapePropertiesPtr )
156 , mpTablePropertiesPtr( pSourceShape->mpTablePropertiesPtr )
157 , mp3DPropertiesPtr( pSourceShape->mp3DPropertiesPtr )
158 , mpEffectPropertiesPtr (pSourceShape->mpEffectPropertiesPtr)
159 , mpShapeRefEffectPropPtr(pSourceShape->mpShapeRefEffectPropPtr)
160 , maShapeProperties( pSourceShape->maShapeProperties )
161 , mpMasterTextListStyle( pSourceShape->mpMasterTextListStyle )
162 , mxShape()
163 , msServiceName( pSourceShape->msServiceName )
164 , msName( pSourceShape->msName )
165 , msInternalName( pSourceShape->msInternalName )
166 , msId( pSourceShape->msId )
167 , mnSubType( pSourceShape->mnSubType )
168 , moSubTypeIndex( pSourceShape->moSubTypeIndex )
169 , maShapeStyleRefs( pSourceShape->maShapeStyleRefs )
170 , maSize( pSourceShape->maSize )
171 , maPosition( pSourceShape->maPosition )
172 , meFrameType( pSourceShape->meFrameType )
173 , mnRotation( pSourceShape->mnRotation )
174 , mnDiagramRotation( pSourceShape->mnDiagramRotation )
175 , mbFlipH( pSourceShape->mbFlipH )
176 , mbFlipV( pSourceShape->mbFlipV )
177 , mbHidden( pSourceShape->mbHidden )
178 , mbHiddenMasterShape( pSourceShape->mbHiddenMasterShape )
179 , mbLocked( pSourceShape->mbLocked )
180 , mbLockedCanvas( pSourceShape->mbLockedCanvas )
181 , mbWps( pSourceShape->mbWps )
182 , mbTextBox( pSourceShape->mbTextBox )
183 , maLinkedTxbxAttr()
184 , mbHasLinkedTxbx(false)
185 , maDiagramDoms( pSourceShape->maDiagramDoms )
186 , mnZOrder(pSourceShape->mnZOrder)
187 , mnZOrderOff(pSourceShape->mnZOrderOff)
188 , mnDataNodeType(pSourceShape->mnDataNodeType)
189 , mfAspectRatio(pSourceShape->mfAspectRatio)
190 , mbUseBgFill(pSourceShape->mbUseBgFill)
191 , maDiagramFontHeights(pSourceShape->maDiagramFontHeights)
192 {}
193 
~Shape()194 Shape::~Shape()
195 {
196 }
197 
getTableProperties()198 table::TablePropertiesPtr const & Shape::getTableProperties()
199 {
200     if ( !mpTablePropertiesPtr )
201         mpTablePropertiesPtr = std::make_shared<table::TableProperties>();
202     return mpTablePropertiesPtr;
203 }
204 
setDefaults(bool bHeight)205 void Shape::setDefaults(bool bHeight)
206 {
207     maDefaultShapeProperties.setProperty(PROP_TextAutoGrowHeight, false);
208     maDefaultShapeProperties.setProperty(PROP_TextWordWrap, true);
209     maDefaultShapeProperties.setProperty(PROP_TextLeftDistance, static_cast< sal_Int32 >( 250 ));
210     maDefaultShapeProperties.setProperty(PROP_TextUpperDistance, static_cast< sal_Int32 >( 125 ));
211     maDefaultShapeProperties.setProperty(PROP_TextRightDistance, static_cast< sal_Int32 >( 250 ));
212     maDefaultShapeProperties.setProperty(PROP_TextLowerDistance, static_cast< sal_Int32 >( 125 ));
213     if (bHeight)
214         maDefaultShapeProperties.setProperty(PROP_CharHeight, static_cast< float >( 18.0 ));
215     maDefaultShapeProperties.setProperty(PROP_TextVerticalAdjust, TextVerticalAdjust_TOP);
216     maDefaultShapeProperties.setProperty(PROP_ParaAdjust,
217                                          static_cast<sal_Int16>(ParagraphAdjust_LEFT));
218 }
219 
setOleObjectType()220 ::oox::vml::OleObjectInfo& Shape::setOleObjectType()
221 {
222     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setOleObjectType - multiple frame types" );
223     meFrameType = FRAMETYPE_OLEOBJECT;
224     mxOleObjectInfo = std::make_shared<::oox::vml::OleObjectInfo>( true );
225     return *mxOleObjectInfo;
226 }
227 
setChartType(bool bEmbedShapes)228 ChartShapeInfo& Shape::setChartType( bool bEmbedShapes )
229 {
230     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setChartType - multiple frame types" );
231     meFrameType = FRAMETYPE_CHART;
232     if (mbWps)
233         msServiceName = "com.sun.star.drawing.temporaryForXMLImportOLE2Shape";
234     else
235         msServiceName = "com.sun.star.drawing.OLE2Shape";
236     mxChartShapeInfo = std::make_shared<ChartShapeInfo>( bEmbedShapes );
237     return *mxChartShapeInfo;
238 }
239 
setDiagramType()240 void Shape::setDiagramType()
241 {
242     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setDiagramType - multiple frame types" );
243     meFrameType = FRAMETYPE_DIAGRAM;
244     msServiceName = "com.sun.star.drawing.GroupShape";
245     mnSubType = 0;
246 }
247 
setTableType()248 void Shape::setTableType()
249 {
250     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setTableType - multiple frame types" );
251     meFrameType = FRAMETYPE_TABLE;
252     msServiceName = "com.sun.star.drawing.TableShape";
253     mnSubType = 0;
254 }
255 
setServiceName(const char * pServiceName)256 void Shape::setServiceName( const char* pServiceName )
257 {
258     if ( pServiceName )
259         msServiceName = OUString::createFromAscii( pServiceName );
260 }
261 
getShapeStyleRef(sal_Int32 nRefType) const262 const ShapeStyleRef* Shape::getShapeStyleRef( sal_Int32 nRefType ) const
263 {
264     ShapeStyleRefMap::const_iterator aIt = maShapeStyleRefs.find( nRefType );
265     return (aIt == maShapeStyleRefs.end()) ? nullptr : &aIt->second;
266 }
267 
addShape(::oox::core::XmlFilterBase & rFilterBase,const Theme * pTheme,const Reference<XShapes> & rxShapes,const basegfx::B2DHomMatrix & aTransformation,FillProperties & rShapeOrParentShapeFillProps,ShapeIdMap * pShapeMap,oox::drawingml::ShapePtr pParentGroupShape)268 void Shape::addShape(
269         ::oox::core::XmlFilterBase& rFilterBase,
270         const Theme* pTheme,
271         const Reference< XShapes >& rxShapes,
272         const basegfx::B2DHomMatrix& aTransformation,
273         FillProperties& rShapeOrParentShapeFillProps,
274         ShapeIdMap* pShapeMap,
275         oox::drawingml::ShapePtr pParentGroupShape)
276 {
277     SAL_INFO("oox.drawingml", "Shape::addShape: id='" << msId << "'");
278 
279     try
280     {
281         OUString sServiceName( msServiceName );
282         if( !sServiceName.isEmpty() )
283         {
284             basegfx::B2DHomMatrix aMatrix( aTransformation );
285             Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, false, false, aMatrix, rShapeOrParentShapeFillProps, pParentGroupShape) );
286 
287             if( pShapeMap && !msId.isEmpty() )
288             {
289                 (*pShapeMap)[ msId ] = shared_from_this();
290             }
291 
292             // if this is a group shape, we have to add also each child shape
293             Reference< XShapes > xShapes( xShape, UNO_QUERY );
294             if ( xShapes.is() )
295                 addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aMatrix );
296 
297             if( meFrameType == FRAMETYPE_DIAGRAM )
298             {
299                 keepDiagramCompatibilityInfo();
300 
301                 // Check if this is the PPTX import, so far converting SmartArt to a non-editable
302                 // metafile is only imlemented for DOCX.
303                 bool bPowerPoint = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilterBase) != nullptr;
304 
305                 if (!SvtFilterOptions::Get().IsSmartArt2Shape() && !bPowerPoint)
306                     convertSmartArtToMetafile( rFilterBase );
307             }
308 
309             NamedShapePairs* pNamedShapePairs = rFilterBase.getDiagramFontHeights();
310             if (xShape.is() && pNamedShapePairs)
311             {
312                 auto itPairs = pNamedShapePairs->find(getInternalName());
313                 if (itPairs != pNamedShapePairs->end())
314                 {
315                     auto it = itPairs->second.find(shared_from_this());
316                     if (it != itPairs->second.end())
317                     {
318                         // Our drawingml::Shape is in the list of an internal name, remember the now
319                         // inserted XShape.
320                         it->second = xShape;
321                     }
322                 }
323             }
324         }
325     }
326     catch( const Exception& )
327     {
328         TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::addShape" );
329     }
330 }
331 
setLockedCanvas(bool bLockedCanvas)332 void Shape::setLockedCanvas(bool bLockedCanvas)
333 {
334     mbLockedCanvas = bLockedCanvas;
335 }
336 
setWps(bool bWps)337 void Shape::setWps(bool bWps)
338 {
339     mbWps = bWps;
340 }
341 
setTextBox(bool bTextBox)342 void Shape::setTextBox(bool bTextBox)
343 {
344     mbTextBox = bTextBox;
345 }
346 
applyShapeReference(const Shape & rReferencedShape,bool bUseText)347 void Shape::applyShapeReference( const Shape& rReferencedShape, bool bUseText )
348 {
349     SAL_INFO("oox.drawingml", "Shape::applyShapeReference: apply '" << rReferencedShape.msId << "' to '" << msId << "'");
350 
351     if ( rReferencedShape.mpTextBody && bUseText )
352         mpTextBody = std::make_shared<TextBody>( *rReferencedShape.mpTextBody );
353     else
354         mpTextBody.reset();
355     maShapeProperties = rReferencedShape.maShapeProperties;
356     mpShapeRefLinePropPtr = std::make_shared<LineProperties>( rReferencedShape.getActualLineProperties(nullptr) );
357     mpShapeRefFillPropPtr = std::make_shared<FillProperties>( rReferencedShape.getActualFillProperties(nullptr, nullptr) );
358     mpCustomShapePropertiesPtr = std::make_shared<CustomShapeProperties>( *rReferencedShape.mpCustomShapePropertiesPtr );
359     mpTablePropertiesPtr = rReferencedShape.mpTablePropertiesPtr ? std::make_shared<table::TableProperties>( *rReferencedShape.mpTablePropertiesPtr ) : nullptr;
360     mpShapeRefEffectPropPtr = std::make_shared<EffectProperties>( rReferencedShape.getActualEffectProperties(nullptr) );
361     mpMasterTextListStyle = std::make_shared<TextListStyle>( *rReferencedShape.mpMasterTextListStyle );
362     maSize = rReferencedShape.maSize;
363     maPosition = rReferencedShape.maPosition;
364     mnRotation = rReferencedShape.mnRotation;
365     mbFlipH = rReferencedShape.mbFlipH;
366     mbFlipV = rReferencedShape.mbFlipV;
367     mbHidden = rReferencedShape.mbHidden;
368     mbLocked = rReferencedShape.mbLocked;
369 }
370 
371 namespace {
372 
373 struct ActionLockGuard
374 {
ActionLockGuardoox::drawingml::__anonaedc5fb80111::ActionLockGuard375     explicit ActionLockGuard(Reference<drawing::XShape> const& xShape)
376         : m_xLockable(xShape, UNO_QUERY)
377     {
378         if (m_xLockable.is()) {
379             m_xLockable->addActionLock();
380         }
381     }
~ActionLockGuardoox::drawingml::__anonaedc5fb80111::ActionLockGuard382     ~ActionLockGuard()
383     {
384         if (m_xLockable.is()) {
385             m_xLockable->removeActionLock();
386         }
387     }
388 private:
389     Reference<document::XActionLockable> m_xLockable;
390 };
391 
392 }
393 
394 // for group shapes, the following method is also adding each child
addChildren(XmlFilterBase & rFilterBase,Shape & rMaster,const Theme * pTheme,const Reference<XShapes> & rxShapes,ShapeIdMap * pShapeMap,const basegfx::B2DHomMatrix & aTransformation)395 void Shape::addChildren(
396         XmlFilterBase& rFilterBase,
397         Shape& rMaster,
398         const Theme* pTheme,
399         const Reference< XShapes >& rxShapes,
400         ShapeIdMap* pShapeMap,
401         const basegfx::B2DHomMatrix& aTransformation )
402 {
403     for (auto const& child : rMaster.maChildren)
404     {
405         child->setMasterTextListStyle( mpMasterTextListStyle );
406         child->addShape( rFilterBase, pTheme, rxShapes, aTransformation, getFillProperties(), pShapeMap, rMaster.shared_from_this());
407     }
408 }
409 
lcl_resetPropertyValue(std::vector<beans::PropertyValue> & rPropVec,const OUString & rName)410 static void lcl_resetPropertyValue( std::vector<beans::PropertyValue>& rPropVec, const OUString& rName )
411 {
412     auto aIterator = std::find_if( rPropVec.begin(), rPropVec.end(),
413         [rName]( const beans::PropertyValue& rValue ) { return rValue.Name == rName; } );
414 
415     if (aIterator != rPropVec.end())
416         rPropVec.erase( aIterator );
417 }
418 
lcl_setPropertyValue(std::vector<beans::PropertyValue> & rPropVec,const OUString & rName,const beans::PropertyValue & rPropertyValue)419 static void lcl_setPropertyValue( std::vector<beans::PropertyValue>& rPropVec,
420                            const OUString& rName,
421                            const beans::PropertyValue& rPropertyValue )
422 {
423     lcl_resetPropertyValue( rPropVec, rName );
424 
425     rPropVec.push_back( rPropertyValue );
426 }
427 
lcl_convertAdjust(ParagraphAdjust eAdjust)428 static SdrTextHorzAdjust lcl_convertAdjust( ParagraphAdjust eAdjust )
429 {
430     if (eAdjust == ParagraphAdjust_LEFT)
431         return SDRTEXTHORZADJUST_LEFT;
432     else if (eAdjust == ParagraphAdjust_RIGHT)
433         return SDRTEXTHORZADJUST_RIGHT;
434     else if (eAdjust == ParagraphAdjust_CENTER)
435         return SDRTEXTHORZADJUST_CENTER;
436     return SDRTEXTHORZADJUST_LEFT;
437 }
438 
lcl_createPresetShape(const uno::Reference<drawing::XShape> & xShape,const OUString & rClass,const OUString & rPresetType,const CustomShapePropertiesPtr & pCustomShapePropertiesPtr,const TextBodyPtr & pTextBody,const GraphicHelper & rGraphicHelper)439 static void lcl_createPresetShape(const uno::Reference<drawing::XShape>& xShape,
440                                          const OUString& rClass, const OUString& rPresetType,
441                                          const CustomShapePropertiesPtr& pCustomShapePropertiesPtr,
442                                          const TextBodyPtr& pTextBody,
443                                          const GraphicHelper& rGraphicHelper)
444 {
445     if (!xShape.is() || !pCustomShapePropertiesPtr || !pTextBody)
446         return;
447 
448     uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter( xShape,
449                                                                        uno::UNO_QUERY );
450 
451     if (!xDefaulter.is() || rClass.isEmpty())
452         return;
453 
454     Reference<XPropertySet> xSet( xShape, UNO_QUERY );
455     if (!xSet.is())
456         return;
457 
458     // The DrawingML shapes from the presetTextWarpDefinitions are mapped to the definitions
459     // in svx/../EnhancedCustomShapeGeometry.cxx, which are used for WordArt shapes from
460     // binary MS Office. Therefore all adjustment values need to be adapted.
461     auto aAdjGdList = pCustomShapePropertiesPtr->getAdjustmentGuideList();
462     Sequence<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustment(
463         !aAdjGdList.empty() ? aAdjGdList.size() : 1 );
464 
465     int nIndex = 0;
466     for (const auto& aEntry : aAdjGdList)
467     {
468         double fValue = aEntry.maFormula.toDouble();
469         // then: polar-handle, else: XY-handle
470         // There exist only 8 polar-handles at all in presetTextWarp.
471         if ((rClass == "fontwork-arch-down-curve")
472             || (rClass == "fontwork-arch-down-pour" && aEntry.maName == "adj1")
473             || (rClass == "fontwork-arch-up-curve")
474             || (rClass == "fontwork-arch-up-pour" && aEntry.maName == "adj1")
475             || (rClass == "fontwork-open-circle-curve")
476             || (rClass == "fontwork-open-circle-pour" && aEntry.maName == "adj1")
477             || (rClass == "fontwork-circle-curve")
478             || (rClass == "fontwork-circle-pour" && aEntry.maName == "adj1"))
479         {
480             // DrawingML has 1/60000 degree unit, but WordArt simple degree. Range [0..360[
481             // or range ]-180..180] doesn't matter, because only cos(angle) and
482             // sin(angle) are used.
483             fValue = NormAngle360(fValue / 60000.0);
484         }
485         else
486         {
487             // DrawingML writes adjustment guides as relative value with 100% = 100000,
488             // but WordArt definitions use values absolute in viewBox 0 0 21600 21600,
489             // so scale with 21600/100000 = 0.216, with two exceptions:
490             // X-handles of waves describe increase/decrease relative to horizontal center.
491             // The gdRefR of pour-shapes is not relative to viewBox but to radius.
492             if ((rClass == "mso-spt158" && aEntry.maName == "adj2") // textDoubleWave1
493                 || (rClass == "fontwork-wave" && aEntry.maName == "adj2") // textWave1
494                 || (rClass == "mso-spt157" && aEntry.maName == "adj2") // textWave2
495                 || (rClass == "mso-spt159" && aEntry.maName == "adj2")) // textWave4
496             {
497                 fValue = (fValue + 50000.0) * 0.216;
498             }
499             else if ( (rClass == "fontwork-arch-down-pour" && aEntry.maName == "adj2")
500                     || (rClass == "fontwork-arch-up-pour" && aEntry.maName == "adj2")
501                     || (rClass == "fontwork-open-circle-pour" && aEntry.maName == "adj2")
502                     || (rClass == "fontwork-circle-pour" && aEntry.maName == "adj2"))
503                 {
504                     fValue *= 0.108;
505                 }
506             else
507             {
508                 fValue *= 0.216;
509             }
510         }
511 
512         aAdjustment[nIndex].Value <<= fValue;
513         aAdjustment[nIndex++].State = css::beans::PropertyState_DIRECT_VALUE;
514     }
515 
516     // Set properties
517     xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::makeAny( false ) );
518     xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWWIDTH, uno::makeAny( false ) );
519     xSet->setPropertyValue( UNO_NAME_FILLSTYLE, uno::makeAny( drawing::FillStyle_SOLID ) );
520 
521     // ToDo: Old binary WordArt does not allow different styles for different paragraphs, so it
522     // was not necessary to examine all paragraphs. Solution for DrawingML is needed.
523     // Currently different alignment of paragraphs are lost, for example.
524     const TextParagraphVector& rParagraphs = pTextBody->getParagraphs();
525     if (!rParagraphs.empty() && !rParagraphs[0]->getRuns().empty())
526     {
527         std::shared_ptr<TextParagraph> pParagraph = rParagraphs[0];
528         std::shared_ptr<TextRun> pRun = pParagraph->getRuns()[0];
529         TextCharacterProperties& pProperties = pRun->getTextCharacterProperties();
530 
531         if (pProperties.moBold.has() && pProperties.moBold.get())
532         {
533             xSet->setPropertyValue( UNO_NAME_CHAR_WEIGHT, uno::makeAny( css::awt::FontWeight::BOLD ) );
534         }
535         if (pProperties.moItalic.has() && pProperties.moItalic.get())
536         {
537             xSet->setPropertyValue( UNO_NAME_CHAR_POSTURE, uno::makeAny( css::awt::FontSlant::FontSlant_ITALIC ) );
538         }
539         if (pProperties.moHeight.has())
540         {
541             sal_Int32 nHeight = pProperties.moHeight.get() / 100;
542             xSet->setPropertyValue( UNO_NAME_CHAR_HEIGHT, uno::makeAny( nHeight ) );
543         }
544         if (pProperties.maFillProperties.maFillColor.isUsed())
545         {
546             const sal_Int32 aFillColor = static_cast<sal_Int32>(
547                 pProperties.maFillProperties.maFillColor.getColor( rGraphicHelper ).GetRGBColor() );
548             xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::makeAny( aFillColor ) );
549         }
550         else
551         {
552             // Set default color
553             xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::makeAny( COL_BLACK ) );
554         }
555         {
556             ParagraphAdjust eAdjust = ParagraphAdjust_LEFT;
557             if (pParagraph->getProperties().getParaAdjust())
558                 eAdjust = *pParagraph->getProperties().getParaAdjust();
559             xSet->setPropertyValue( "ParaAdjust", uno::makeAny( eAdjust ) );
560             SdrObject* pShape = SdrObject::getSdrObjectFromXShape( xShape );
561             assert(pShape);
562             SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust( eAdjust );
563             pShape->SetMergedItem( SdrTextHorzAdjustItem( eHorzAdjust ) );
564         }
565     }
566 
567     // Apply vertical adjustment for text on arc
568     // ToDo: The property is currently not evaluated.
569     SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
570     assert(pShape);
571     if (rClass == "fontwork-arch-up-curve" || rClass == "fontwork-circle-curve")
572         pShape->SetMergedItem( SdrTextVertAdjustItem( SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM ) );
573     else if (rClass == "fontwork-arch-down-curve")
574         pShape->SetMergedItem( SdrTextVertAdjustItem( SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP ) );
575 
576     // Apply preset shape
577     xDefaulter->createCustomShapeDefaults( rClass );
578 
579     auto aGeomPropSeq = xSet->getPropertyValue( "CustomShapeGeometry" )
580                             .get<uno::Sequence<beans::PropertyValue>>();
581     auto aGeomPropVec
582         = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>(
583             aGeomPropSeq );
584 
585     // Reset old properties
586     static const OUStringLiteral sTextPath( u"TextPath" );
587     static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
588     static const OUStringLiteral sPresetTextWarp( u"PresetTextWarp" );
589 
590     lcl_resetPropertyValue( aGeomPropVec, "CoordinateSize" );
591     lcl_resetPropertyValue( aGeomPropVec, "Equations" );
592     lcl_resetPropertyValue( aGeomPropVec, "Path" );
593     lcl_resetPropertyValue( aGeomPropVec, sAdjustmentValues);
594 
595     bool bFromWordArt(false);
596     pTextBody->getTextProperties().maPropertyMap.getProperty(PROP_FromWordArt) >>= bFromWordArt;
597 
598     bool bScaleX(false);
599     if (!bFromWordArt
600         && (rPresetType == "textArchDown" || rPresetType == "textArchUp"
601             || rPresetType == "textCircle" || rPresetType == "textButton"))
602     {
603         bScaleX = true;
604     }
605 
606     // Apply geometry properties
607     uno::Sequence<beans::PropertyValue> aPropertyValues(
608         comphelper::InitPropertySequence(
609             { { sTextPath, uno::makeAny( true ) },
610                 { "TextPathMode",
611                 uno::Any( drawing::EnhancedCustomShapeTextPathMode_PATH ) },
612                 { "ScaleX", uno::Any(bScaleX) } } ) );
613 
614     lcl_setPropertyValue( aGeomPropVec, sTextPath,
615         comphelper::makePropertyValue( sTextPath, aPropertyValues ) );
616 
617     lcl_setPropertyValue( aGeomPropVec, sPresetTextWarp,
618         comphelper::makePropertyValue( sPresetTextWarp, rPresetType ) );
619 
620     if (!aAdjGdList.empty())
621     {
622         lcl_setPropertyValue( aGeomPropVec, sAdjustmentValues,
623             comphelper::makePropertyValue( sAdjustmentValues, aAdjustment ) );
624     }
625 
626     xSet->setPropertyValue(
627         "CustomShapeGeometry",
628         uno::makeAny(comphelper::containerToSequence(aGeomPropVec)));
629 }
630 
631 // Some helper methods for createAndInsert
632 namespace
633 {
634 // mirrors aTransformation at its center axis
635 // only valid if neither rotation or shear included
lcl_mirrorAtCenter(basegfx::B2DHomMatrix & aTransformation,bool bFlipH,bool bFlipV)636 void lcl_mirrorAtCenter(basegfx::B2DHomMatrix& aTransformation, bool bFlipH, bool bFlipV)
637 {
638     if (!bFlipH && !bFlipV)
639         return;
640     basegfx::B2DPoint aCenter(0.5, 0.5);
641     aCenter *= aTransformation;
642     aTransformation.translate(-aCenter);
643     aTransformation.scale(bFlipH ? -1.0 : 1.0, bFlipV ? -1.0 : 1.0);
644     aTransformation.translate(aCenter);
645     return;
646 }
647 
648 // only valid if neither rotation or shear included
lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix & aTransformation)649 void lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix& aTransformation)
650 {
651     // The values are directly set at the matrix without any matrix multiplication.
652     // That way it is valid for lines too. Those have zero width or height.
653     const double fSx(aTransformation.get(0, 0));
654     const double fSy(aTransformation.get(1, 1));
655     const double fTx(aTransformation.get(0, 2));
656     const double fTy(aTransformation.get(1, 2));
657     aTransformation.set(0, 0, fSy);
658     aTransformation.set(1, 1, fSx);
659     aTransformation.set(0, 2, fTx + 0.5 * (fSx - fSy));
660     aTransformation.set(1, 2, fTy + 0.5 * (fSy - fSx));
661     return;
662 }
663 
lcl_RotateAtCenter(basegfx::B2DHomMatrix & aTransformation,const sal_Int32 & rMSORotationAngle)664 void lcl_RotateAtCenter(basegfx::B2DHomMatrix& aTransformation, const sal_Int32& rMSORotationAngle)
665 {
666     if (rMSORotationAngle == 0)
667         return;
668     double fRad = basegfx::deg2rad(rMSORotationAngle / 60000.0);
669     basegfx::B2DPoint aCenter(0.5, 0.5);
670     aCenter *= aTransformation;
671     aTransformation.translate(-aCenter);
672     aTransformation.rotate(fRad);
673     aTransformation.translate(aCenter);
674     return;
675 }
676 }
677 
createAndInsert(::oox::core::XmlFilterBase & rFilterBase,const OUString & rServiceName,const Theme * pTheme,const css::uno::Reference<css::drawing::XShapes> & rxShapes,bool bClearText,bool bDoNotInsertEmptyTextBody,basegfx::B2DHomMatrix & aParentTransformation,FillProperties & rShapeOrParentShapeFillProps,oox::drawingml::ShapePtr pParentGroupShape)678 Reference< XShape > const & Shape::createAndInsert(
679         ::oox::core::XmlFilterBase& rFilterBase,
680         const OUString& rServiceName,
681         const Theme* pTheme,
682         const css::uno::Reference< css::drawing::XShapes >& rxShapes,
683         bool bClearText,
684         bool bDoNotInsertEmptyTextBody,
685         basegfx::B2DHomMatrix& aParentTransformation,
686         FillProperties& rShapeOrParentShapeFillProps,
687         oox::drawingml::ShapePtr pParentGroupShape)
688 {
689     bool bIsEmbMedia = false;
690     SAL_INFO("oox.drawingml", "Shape::createAndInsert: id='" << msId << "' service='" << rServiceName << "'");
691 
692     formulaimport::XmlStreamBuilder * pMathXml(nullptr);
693     if (mpTextBody)
694     {
695         for (auto const& it : mpTextBody->getParagraphs())
696         {
697             if (it->HasMathXml())
698             {
699                 if (!mpTextBody->isEmpty() || pMathXml != nullptr)
700                 {
701                     SAL_WARN("oox.drawingml", "losing a Math object...");
702                 }
703                 else
704                 {
705                     pMathXml = &it->GetMathXml();
706                 }
707             }
708         }
709     }
710 
711     // tdf#90403 PowerPoint ignores a:ext cx and cy values of p:xfrm, and uses real table width and height
712     if ( mpTablePropertiesPtr && rServiceName == "com.sun.star.drawing.TableShape" )
713     {
714         maSize.Width = 0;
715         for (auto const& elem : mpTablePropertiesPtr->getTableGrid())
716         {
717             maSize.Width = o3tl::saturating_add(maSize.Width, static_cast<sal_Int32>(elem));
718         }
719         maSize.Height = 0;
720         for (auto const& elem : mpTablePropertiesPtr->getTableRows())
721         {
722             maSize.Height = o3tl::saturating_add(maSize.Height, elem.getHeight());
723         }
724     }
725 
726     awt::Rectangle aShapeRectHmm(
727         o3tl::convert(maPosition.X, o3tl::Length::emu, o3tl::Length::mm100),
728         o3tl::convert(maPosition.Y, o3tl::Length::emu, o3tl::Length::mm100),
729         o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100),
730         o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100));
731 
732     OUString aServiceName;
733     if (pMathXml)
734     {
735         // convert this shape to OLE
736         aServiceName = "com.sun.star.drawing.OLE2Shape";
737         msServiceName = aServiceName;
738         meFrameType = FRAMETYPE_GENERIC; // not OLEOBJECT, no stream in package
739         mnSubType = 0;
740     }
741     else if (rServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
742         mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->m_sMediaPackageURL.isEmpty())
743     {
744         aServiceName = finalizeServiceName( rFilterBase, "com.sun.star.presentation.MediaShape", aShapeRectHmm );
745         bIsEmbMedia = true;
746     }
747     else
748     {
749         aServiceName = finalizeServiceName( rFilterBase, rServiceName, aShapeRectHmm );
750     }
751     // Use custom shape instead of GraphicObjectShape if the image is cropped to
752     // shape. Except rectangle, which does not require further cropping
753     bool bIsCroppedGraphic = (aServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
754                               (mpCustomShapePropertiesPtr->getShapePresetType() >= 0 || mpCustomShapePropertiesPtr->getPath2DList().size() > 0) &&
755                               mpCustomShapePropertiesPtr->getShapePresetType() != XML_Rect &&
756                               mpCustomShapePropertiesPtr->getShapePresetType() != XML_rect);
757     // ToDo: Why is ConnectorShape here treated as custom shape, but below with start and end point?
758     bool bIsCustomShape = ( aServiceName == "com.sun.star.drawing.CustomShape" ||
759                             aServiceName == "com.sun.star.drawing.ConnectorShape" ||
760                             bIsCroppedGraphic);
761     if(bIsCroppedGraphic)
762     {
763         aServiceName = "com.sun.star.drawing.CustomShape";
764         mpGraphicPropertiesPtr->mbIsCustomShape = true;
765     }
766     bool bUseRotationTransform = ( !mbWps ||
767             aServiceName == "com.sun.star.drawing.LineShape" ||
768             aServiceName == "com.sun.star.drawing.GroupShape" ||
769             mbFlipH ||
770             mbFlipV );
771 
772     basegfx::B2DHomMatrix aTransformation; // will be cumulative transformation of this object
773 
774     // Special for SmartArt import. Rotate diagram's shape around object's center before sizing.
775     if (bUseRotationTransform && mnDiagramRotation != 0)
776     {
777         aTransformation.translate(-0.5, -0.5);
778         aTransformation.rotate(basegfx::deg2rad(mnDiagramRotation / 60000.0));
779         aTransformation.translate(0.5, 0.5);
780     }
781 
782     // Build object matrix from shape size and position; corresponds to MSO ext and off
783     // Only LineShape and ConnectorShape may have zero width or height.
784     if (aServiceName == "com.sun.star.drawing.LineShape"
785         || aServiceName == "com.sun.star.drawing.ConnectorShape")
786         aTransformation.scale(maSize.Width, maSize.Height);
787     else
788     {
789         aTransformation.scale(maSize.Width ? maSize.Width : 1.0,
790                               maSize.Height ? maSize.Height : 1.0);
791     }
792 
793     // Evaluate object flip. Other shapes than custom shapes have no attribute for flip but use
794     // negative scale. Flip in MSO is at object center.
795     if (!bIsCustomShape && (mbFlipH || mbFlipV))
796         lcl_mirrorAtCenter(aTransformation, mbFlipH, mbFlipV);
797 
798     // Evaluate parent flip.
799     // A CustomShape has mirror not as negative scale, but as attributes.
800     basegfx::B2DVector aParentScale(1.0, 1.0);
801     basegfx::B2DVector aParentTranslate(0.0, 0.0);
802     double fParentRotate(0.0);
803     double fParentShearX(0.0);
804     if (pParentGroupShape)
805     {
806         aParentTransformation.decompose(aParentScale, aParentTranslate, fParentRotate, fParentShearX);
807         if (bIsCustomShape)
808         {
809             lcl_mirrorAtCenter(aTransformation, aParentScale.getX() < 0, aParentScale.getY() < 0);
810             if(aParentScale.getX() < 0)
811                 mbFlipH = !mbFlipH;
812             if(aParentScale.getY() < 0)
813                 mbFlipV = !mbFlipV;
814         }
815     }
816 
817     if (maPosition.X != 0 || maPosition.Y != 0)
818     {
819         // if global position is used, add it to transformation
820         if (mbWps && pParentGroupShape == nullptr)
821             aTransformation.translate(
822                 o3tl::convert(maPosition.X, o3tl::Length::mm100, o3tl::Length::emu),
823                 o3tl::convert(maPosition.Y, o3tl::Length::mm100, o3tl::Length::emu));
824         else
825             aTransformation.translate(maPosition.X, maPosition.Y);
826     }
827 
828     // Apply further parent transformations. First scale object then rotate. Other way round would
829     // introduce shearing.
830 
831     // The attributes chExt and chOff of the group in oox file contain the values on which the size
832     // and position of the child is based on. If they differ from the actual size of the group as
833     // given in its ext and off attributes, the child has to be transformed according the new values.
834     if (pParentGroupShape)
835     {
836         // ToDo: A diagram in a group might need special handling because it cannot flip and only
837         // resize uniformly. But currently it is imported with zero size, see tdf#139575. That needs
838         // to be fixed beforehand.
839 
840         // Scaling is done from left/top edges of the group. So these need to become coordinate axes.
841         aTransformation.translate(-pParentGroupShape->maChPosition.X,
842                                   -pParentGroupShape->maChPosition.Y);
843 
844         // oox allows zero or missing attribute chExt. In that case the scaling factor is 1.
845         // Transform2DContext::onCreateContext has set maChSize to maSize for groups in oox file in
846         // such cases. For own made groups (e.g. diagrams) that is missing.
847         // The factors cumulate on the way through the parent groups, so we do not use maSize of the
848         // direct parent group but the cumulated value from aParentScale.
849         double fFactorX = 1.0;
850         double fFactorY = 1.0;
851         if (pParentGroupShape->maChSize.Width != 0)
852             fFactorX = aParentScale.getX() / pParentGroupShape->maChSize.Width;
853         if (pParentGroupShape->maChSize.Height != 0)
854             fFactorY = aParentScale.getY() / pParentGroupShape->maChSize.Height;
855         if (fFactorX != 1 || fFactorY != 1)
856         {
857             // It depends on the object rotation angle whether scaling is applied to switched
858             // width and height. MSO acts strange in that case (as of May 2021).
859             const sal_Int32 nDeg(mnRotation / 60000);
860             const bool bNeedsMSOWidhtHeightToggle
861                 = (nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315);
862             if (bNeedsMSOWidhtHeightToggle)
863                 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
864 
865             aTransformation.scale(fFactorX, fFactorY);
866 
867             if (bNeedsMSOWidhtHeightToggle)
868             {
869                 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
870                 // In case of flip the special case needs an additional 180deg rotation.
871                 if ((aParentScale.getX() < 0) != (aParentScale.getY() < 0))
872                     lcl_RotateAtCenter(aTransformation, 10800000);
873             }
874         }
875     }
876 
877     // Apply object rotation at current object center
878     // The flip contained in aParentScale will affect orientation of object rotation angle.
879     sal_Int16 nOrientation = ((aParentScale.getX() < 0) != (aParentScale.getY() < 0)) ? -1 : 1;
880     // ToDo: Not sure about the restrictions given by bUseRotationTransform.
881     if (bUseRotationTransform && mnRotation != 0)
882         lcl_RotateAtCenter(aTransformation, nOrientation * mnRotation);
883 
884     if (fParentRotate != 0.0)
885         aTransformation.rotate(fParentRotate);
886     if (!aParentTranslate.equalZero())
887         aTransformation.translate(aParentTranslate);
888 
889     aParentTransformation = aTransformation;
890 
891     constexpr double fEmuToMm100 = o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::mm100);
892     aTransformation.scale(fEmuToMm100, fEmuToMm100);
893 
894     // OOXML flips shapes before rotating them, so the rotation needs to be inverted
895     if( bIsCustomShape && mbFlipH != mbFlipV )
896     {
897         basegfx::B2DVector aScale, aTranslate;
898         double fRotate, fShearX;
899         aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
900 
901         if(fRotate != 0)
902         {
903             basegfx::B2DPoint aCenter(0.5, 0.5);
904             aCenter *= aTransformation;
905             aTransformation.translate( -aCenter.getX(), -aCenter.getY() );
906             aTransformation.rotate( fRotate * -2.0 );
907             aTransformation.translate( aCenter.getX(), aCenter.getY() );
908         }
909     }
910 
911     // special for lineshape
912     if ( aServiceName == "com.sun.star.drawing.LineShape" )
913     {
914         ::basegfx::B2DPolygon aPoly;
915         aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
916         aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
917         aPoly.transform( aTransformation );
918 
919         // now creating the corresponding PolyPolygon
920         sal_Int32 i, nNumPoints = aPoly.count();
921         uno::Sequence< awt::Point > aPointSequence( nNumPoints );
922         awt::Point* pPoints = aPointSequence.getArray();
923         uno::Reference<lang::XServiceInfo> xModelInfo(rFilterBase.getModel(), uno::UNO_QUERY);
924         for( i = 0; i < nNumPoints; ++i )
925         {
926             basegfx::B2DPoint aPoint( aPoly.getB2DPoint( i ) );
927 
928             // Guard against zero width or height.
929             if (i)
930             {
931                 const basegfx::B2DPoint& rPreviousPoint = aPoly.getB2DPoint(i - 1);
932                 if (aPoint.getX() - rPreviousPoint.getX() == 0)
933                     aPoint.setX(aPoint.getX() + 1);
934                 if (aPoint.getY() - rPreviousPoint.getY() == 0)
935                     aPoint.setY(aPoint.getY() + 1);
936             }
937 
938             pPoints[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()), static_cast<sal_Int32>(aPoint.getY()));
939         }
940         uno::Sequence< uno::Sequence< awt::Point > > aPolyPolySequence( 1 );
941         aPolyPolySequence.getArray()[ 0 ] = aPointSequence;
942 
943         maShapeProperties.setProperty(PROP_PolyPolygon, aPolyPolySequence);
944     }
945     else if ( aServiceName == "com.sun.star.drawing.ConnectorShape" )
946     {
947         ::basegfx::B2DPolygon aPoly;
948         aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
949         aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
950         aPoly.transform( aTransformation );
951 
952         basegfx::B2DPoint aStartPosition( aPoly.getB2DPoint( 0 ) );
953         basegfx::B2DPoint aEndPosition( aPoly.getB2DPoint( 1 ) );
954         awt::Point aAWTStartPosition( static_cast< sal_Int32 >( aStartPosition.getX() ), static_cast< sal_Int32 >( aStartPosition.getY() ) );
955         awt::Point aAWTEndPosition( static_cast< sal_Int32 >( aEndPosition.getX() ), static_cast< sal_Int32 >( aEndPosition.getY() ) );
956 
957         maShapeProperties.setProperty(PROP_StartPosition, aAWTStartPosition);
958         maShapeProperties.setProperty(PROP_EndPosition, aAWTEndPosition);
959     }
960     else
961     {
962         // now set transformation for this object
963         HomogenMatrix3 aMatrix;
964 
965         aMatrix.Line1.Column1 = aTransformation.get(0,0);
966         aMatrix.Line1.Column2 = aTransformation.get(0,1);
967         aMatrix.Line1.Column3 = aTransformation.get(0,2);
968 
969         aMatrix.Line2.Column1 = aTransformation.get(1,0);
970         aMatrix.Line2.Column2 = aTransformation.get(1,1);
971         aMatrix.Line2.Column3 = aTransformation.get(1,2);
972 
973         aMatrix.Line3.Column1 = aTransformation.get(2,0);
974         aMatrix.Line3.Column2 = aTransformation.get(2,1);
975         aMatrix.Line3.Column3 = aTransformation.get(2,2);
976 
977         maShapeProperties.setProperty(PROP_Transformation, aMatrix);
978     }
979 
980     Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
981     if ( !mxShape.is() )
982     {
983         mxShape.set( xServiceFact->createInstance( aServiceName ), UNO_QUERY_THROW );
984         if (aServiceName == "com.sun.star.drawing.GroupShape")
985         {
986             // TODO why is this necessary? A newly created group shape should have an empty
987             // grab-bag.
988             uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
989             beans::PropertyValues aVals;
990             xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aVals));
991         }
992     }
993 
994     Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
995     if (xSet.is())
996     {
997         if( !msName.isEmpty() )
998         {
999             Reference< container::XNamed > xNamed( mxShape, UNO_QUERY );
1000             if( xNamed.is() )
1001                 xNamed->setName( msName );
1002         }
1003         if( !msDescription.isEmpty() )
1004         {
1005             xSet->setPropertyValue( "Description", Any( msDescription ) );
1006         }
1007         if (aServiceName != "com.sun.star.text.TextFrame")
1008             rxShapes->add( mxShape );
1009 
1010         if ( mbHidden || mbHiddenMasterShape )
1011         {
1012             SAL_INFO("oox.drawingml", "Shape::createAndInsert: invisible shape with id='" << msId << "'");
1013             xSet->setPropertyValue( "Visible", Any( false ) );
1014             // In Excel hidden means not printed, let's use visibility for now until that's handled separately
1015             xSet->setPropertyValue( "Printable", Any( false ) );
1016         }
1017 
1018         if (mbLocked)
1019         {
1020             xSet->setPropertyValue("MoveProtect", Any(true));
1021             xSet->setPropertyValue("SizeProtect", Any(true));
1022         }
1023 
1024         ActionLockGuard const alg(mxShape);
1025 
1026         // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape
1027         if ( bClearText )
1028         {
1029             uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY );
1030             if ( xText.is() )
1031             {
1032                 xText->setString( "" );
1033             }
1034         }
1035 
1036         if (pMathXml)
1037         {
1038             // the "EmbeddedObject" property is read-only, so we have to create
1039             // the shape first, and it can be read only after the shape is
1040             // inserted into the document, so delay the actual import until here
1041             SvGlobalName name(SO3_SM_CLASSID);
1042             xSet->setPropertyValue("CLSID", uno::makeAny(name.GetHexName()));
1043             uno::Reference<embed::XEmbeddedObject> const xObj(
1044                 xSet->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY);
1045             if (xObj.is())
1046             {
1047                 uno::Reference<uno::XInterface> const xMathModel(xObj->getComponent());
1048                 oox::FormulaImportBase *const pMagic(
1049                         dynamic_cast<oox::FormulaImportBase*>(xMathModel.get()));
1050                 assert(pMagic);
1051                 pMagic->readFormulaOoxml(*pMathXml);
1052             }
1053         }
1054 
1055         const GraphicHelper& rGraphicHelper = rFilterBase.getGraphicHelper();
1056 
1057         ::Color nLinePhClr(ColorTransparency, 0xffffffff);
1058         ::Color nFillPhClr(ColorTransparency, 0xffffffff);
1059         // TODO: use ph color when applying effect properties
1060         //sal_Int32 nEffectPhClr = -1;
1061 
1062         // dmapper needs the original rotation angle for calculating square wrap. This angle is not
1063         // available as property there, so store it in InteropGrabBag.
1064         putPropertyToGrabBag("mso-rotation-angle", Any(mnRotation));
1065 
1066         if( pTheme )
1067         {
1068             if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
1069             {
1070                 LineProperties aLineProperties;
1071                 aLineProperties.maLineFill.moFillType = XML_noFill;
1072                 if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
1073                     aLineProperties.assignUsed( *pLineProps );
1074                 nLinePhClr = pLineRef->maPhClr.getColor( rGraphicHelper );
1075 
1076                 // Store style-related properties to InteropGrabBag to be able to export them back
1077                 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1078                 {
1079                     {"SchemeClr", uno::makeAny(pLineRef->maPhClr.getSchemeName())},
1080                     {"Idx", uno::makeAny(pLineRef->mnThemedIdx)},
1081                     {"Color", uno::makeAny(nLinePhClr)},
1082                     {"LineStyle", uno::makeAny(aLineProperties.getLineStyle())},
1083                     {"LineCap", uno::makeAny(aLineProperties.getLineCap())},
1084                     {"LineJoint", uno::makeAny(aLineProperties.getLineJoint())},
1085                     {"LineWidth", uno::makeAny(aLineProperties.getLineWidth())},
1086                     {"Transformations", uno::makeAny(pLineRef->maPhClr.getTransformations())}
1087                 });
1088                 putPropertyToGrabBag( "StyleLnRef", Any( aProperties ) );
1089             }
1090             if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
1091             {
1092                 if (!mbUseBgFill)
1093                 {
1094                     nFillPhClr = pFillRef->maPhClr.getColor(rGraphicHelper);
1095                 }
1096 
1097                 OUString sColorScheme = pFillRef->maPhClr.getSchemeName();
1098                 if( !sColorScheme.isEmpty() )
1099                 {
1100                     uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1101                     {
1102                         {"SchemeClr", uno::makeAny(sColorScheme)},
1103                         {"Idx", uno::makeAny(pFillRef->mnThemedIdx)},
1104                         {"Color", uno::makeAny(nFillPhClr)},
1105                         {"Transformations", uno::makeAny(pFillRef->maPhClr.getTransformations())}
1106                     });
1107 
1108                     putPropertyToGrabBag( "StyleFillRef", Any( aProperties ) );
1109                 }
1110             }
1111             if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
1112             {
1113                 // TODO: use ph color when applying effect properties
1114                 // nEffectPhClr = pEffectRef->maPhClr.getColor( rGraphicHelper );
1115 
1116                 // Store style-related properties to InteropGrabBag to be able to export them back
1117                 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1118                 {
1119                     {"SchemeClr", uno::makeAny(pEffectRef->maPhClr.getSchemeName())},
1120                     {"Idx", uno::makeAny(pEffectRef->mnThemedIdx)},
1121                     {"Transformations", uno::makeAny(pEffectRef->maPhClr.getTransformations())}
1122                 });
1123                 putPropertyToGrabBag( "StyleEffectRef", Any( aProperties ) );
1124             }
1125         }
1126         ShapePropertyMap aShapeProps( rFilterBase.getModelObjectHelper() );
1127 
1128         // add properties from textbody to shape properties
1129         if( mpTextBody )
1130         {
1131             mpTextBody->getTextProperties().pushRotationAdjustments();
1132             aShapeProps.assignUsed( mpTextBody->getTextProperties().maPropertyMap );
1133             // Push char properties as well - specifically useful when this is a placeholder
1134             if( mpMasterTextListStyle &&  mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.has() )
1135                 aShapeProps.setProperty(PROP_CharHeight, GetFontHeight( mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.get() ));
1136         }
1137 
1138         // applying properties
1139         aShapeProps.assignUsed( getShapeProperties() );
1140         aShapeProps.assignUsed( maDefaultShapeProperties );
1141         if(mnRotation != 0 && bIsCustomShape)
1142             aShapeProps.setProperty( PROP_RotateAngle, sal_Int32( NormAngle36000( Degree100(mnRotation / -600) ) ));
1143         if( bIsEmbMedia ||
1144             bIsCustomShape ||
1145             aServiceName == "com.sun.star.drawing.GraphicObjectShape" ||
1146             aServiceName == "com.sun.star.drawing.OLE2Shape")
1147         {
1148             mpGraphicPropertiesPtr->pushToPropMap( aShapeProps, rGraphicHelper, mbFlipH, mbFlipV );
1149         }
1150         if ( mpTablePropertiesPtr && aServiceName == "com.sun.star.drawing.TableShape" )
1151             mpTablePropertiesPtr->pushToPropSet( rFilterBase, xSet, mpMasterTextListStyle );
1152 
1153         FillProperties aFillProperties = getActualFillProperties(pTheme, &rShapeOrParentShapeFillProps);
1154         if (getFillProperties().moFillType.has() && getFillProperties().moFillType.get() == XML_grpFill)
1155             getFillProperties().assignUsed(aFillProperties);
1156         if(!bIsCroppedGraphic)
1157             aFillProperties.pushToPropMap( aShapeProps, rGraphicHelper, mnRotation, nFillPhClr, mbFlipH, mbFlipV, bIsCustomShape );
1158         LineProperties aLineProperties = getActualLineProperties(pTheme);
1159         aLineProperties.pushToPropMap( aShapeProps, rGraphicHelper, nLinePhClr );
1160         EffectProperties aEffectProperties = getActualEffectProperties(pTheme);
1161         // TODO: use ph color when applying effect properties
1162         aEffectProperties.pushToPropMap( aShapeProps, rGraphicHelper );
1163 
1164         // applying autogrowheight property before setting shape size, because
1165         // the shape size might be changed if currently autogrowheight is true
1166         // we must also check that the PropertySet supports the property.
1167         Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1168         const OUString& rPropName = PropertyMap::getPropertyName( PROP_TextAutoGrowHeight );
1169         if( xSetInfo.is() && xSetInfo->hasPropertyByName( rPropName ) )
1170             if( aShapeProps.hasProperty( PROP_TextAutoGrowHeight ) )
1171                 xSet->setPropertyValue( rPropName, Any( false ) );
1172 
1173         // do not set properties at a group shape (this causes
1174         // assertions from svx) ...
1175         if( aServiceName != "com.sun.star.drawing.GroupShape" )
1176         {
1177             if (aServiceName == "com.sun.star.text.TextFrame")
1178             {
1179                 if (mpCustomShapePropertiesPtr && mpCustomShapePropertiesPtr->getShapeTypeOverride())
1180                 {
1181                     uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1182                     uno::Sequence<beans::PropertyValue> aGrabBag;
1183                     propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
1184                     sal_Int32 length = aGrabBag.getLength();
1185                     aGrabBag.realloc( length+1);
1186                     aGrabBag[length].Name = "mso-orig-shape-type";
1187                     uno::Sequence< sal_Int8 > const & aNameSeq =
1188                         mpCustomShapePropertiesPtr->getShapePresetTypeName();
1189                     OUString sShapePresetTypeName(reinterpret_cast< const char* >(
1190                         aNameSeq.getConstArray()), aNameSeq.getLength(), RTL_TEXTENCODING_UTF8);
1191                     aGrabBag[length].Value <<= sShapePresetTypeName;
1192                     propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag));
1193                 }
1194                 //If the text box has links then save the link information so that
1195                 //it can be accessed in DomainMapper_Impl.cxx while chaining the text frames.
1196                 if (isLinkedTxbx())
1197                 {
1198                     uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1199                     uno::Sequence<beans::PropertyValue> aGrabBag;
1200                     propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
1201                     sal_Int32 length = aGrabBag.getLength();
1202                     aGrabBag.realloc( length + 3 );
1203                     aGrabBag[length].Name = "TxbxHasLink";
1204                     aGrabBag[length].Value <<= isLinkedTxbx();
1205                     aGrabBag[length + 1 ].Name = "Txbx-Id";
1206                     aGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1207                     aGrabBag[length + 2 ].Name = "Txbx-Seq";
1208                     aGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1209                     propertySet->setPropertyValue("FrameInteropGrabBag",uno::makeAny(aGrabBag));
1210                 }
1211 
1212                 // TextFrames have BackColor, not FillColor
1213                 if (aShapeProps.hasProperty(PROP_FillColor))
1214                 {
1215                     aShapeProps.setAnyProperty(PROP_BackColor, aShapeProps.getProperty(PROP_FillColor));
1216                     aShapeProps.erase(PROP_FillColor);
1217                 }
1218                 // TextFrames have BackColorTransparency, not FillTransparence
1219                 if (aShapeProps.hasProperty(PROP_FillTransparence))
1220                 {
1221                     aShapeProps.setAnyProperty(PROP_BackColorTransparency, aShapeProps.getProperty(PROP_FillTransparence));
1222                     aShapeProps.erase(PROP_FillTransparence);
1223                 }
1224                 // TextFrames have BackGraphic, not FillBitmap
1225                 if (aShapeProps.hasProperty(PROP_FillBitmap))
1226                 {
1227                     aShapeProps.setAnyProperty(PROP_BackGraphic, aShapeProps.getProperty(PROP_FillBitmap));
1228                     aShapeProps.erase(PROP_FillBitmap);
1229                 }
1230                 if (aShapeProps.hasProperty(PROP_FillBitmapName))
1231                 {
1232                     uno::Any aAny = aShapeProps.getProperty(PROP_FillBitmapName);
1233                     OUString aFillBitmapName = aAny.get<OUString>();
1234                     uno::Reference<awt::XBitmap> xBitmap = rFilterBase.getModelObjectHelper().getFillBitmap(aFillBitmapName);
1235                     uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
1236                     aShapeProps.setProperty(PROP_BackGraphic, xGraphic);
1237                     // aShapeProps.erase(PROP_FillBitmapName);  // Maybe, leave the name as well
1238                 }
1239                 // And no LineColor property; individual borders can have colors
1240                 if (aShapeProps.hasProperty(PROP_LineColor))
1241                 {
1242                     uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1243                     static const sal_Int32 aBorders[] =
1244                     {
1245                         PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
1246                     };
1247                     for (sal_Int32 nBorder : aBorders)
1248                     {
1249                         css::table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<css::table::BorderLine2>();
1250                         aBorderLine.Color = aShapeProps.getProperty(PROP_LineColor).get<sal_Int32>();
1251                         if (aLineProperties.moLineWidth.has())
1252                             aBorderLine.LineWidth = convertEmuToHmm(aLineProperties.moLineWidth.get());
1253                         aShapeProps.setProperty(nBorder, aBorderLine);
1254                     }
1255                     aShapeProps.erase(PROP_LineColor);
1256                 }
1257                 if(mnRotation)
1258                 {
1259                     uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1260                     static const OUStringLiteral aGrabBagPropName = u"FrameInteropGrabBag";
1261                     uno::Sequence<beans::PropertyValue> aGrabBag;
1262                     xPropertySet->getPropertyValue(aGrabBagPropName) >>= aGrabBag;
1263                     beans::PropertyValue aPair;
1264                     aPair.Name = "mso-rotation-angle";
1265                     aPair.Value <<= mnRotation;
1266                     if (aGrabBag.hasElements())
1267                     {
1268                         sal_Int32 nLength = aGrabBag.getLength();
1269                         aGrabBag.realloc(nLength + 1);
1270                         aGrabBag[nLength] = aPair;
1271                     }
1272                     else
1273                     {
1274                         aGrabBag.realloc(1);
1275                         aGrabBag[0] = aPair;
1276                     }
1277                     xPropertySet->setPropertyValue(aGrabBagPropName, uno::makeAny(aGrabBag));
1278                 }
1279                 // TextFrames have ShadowFormat, not individual shadow properties.
1280                 std::optional<sal_Int32> oShadowDistance;
1281                 if (aShapeProps.hasProperty(PROP_ShadowXDistance))
1282                 {
1283                     oShadowDistance = aShapeProps.getProperty(PROP_ShadowXDistance).get<sal_Int32>();
1284                     aShapeProps.erase(PROP_ShadowXDistance);
1285                 }
1286                 if (aShapeProps.hasProperty(PROP_ShadowYDistance))
1287                 {
1288                     // There is a single 'dist' attribute, so no need to count the avg of x and y.
1289                     aShapeProps.erase(PROP_ShadowYDistance);
1290                 }
1291                 std::optional<sal_Int32> oShadowColor;
1292                 if (aShapeProps.hasProperty(PROP_ShadowColor))
1293                 {
1294                     oShadowColor = aShapeProps.getProperty(PROP_ShadowColor).get<sal_Int32>();
1295                     aShapeProps.erase(PROP_ShadowColor);
1296                 }
1297                 if (aShapeProps.hasProperty(PROP_Shadow))
1298                     aShapeProps.erase(PROP_Shadow);
1299 
1300                 if (oShadowDistance || oShadowColor || aEffectProperties.maShadow.moShadowDir.has())
1301                 {
1302                     css::table::ShadowFormat aFormat;
1303                     if (oShadowColor)
1304                         aFormat.Color = *oShadowColor;
1305                     if (aEffectProperties.maShadow.moShadowDir.has())
1306                     {
1307                         css::table::ShadowLocation nLocation = css::table::ShadowLocation_NONE;
1308                         switch (aEffectProperties.maShadow.moShadowDir.get())
1309                         {
1310                         case 13500000:
1311                             nLocation = css::table::ShadowLocation_TOP_LEFT;
1312                             break;
1313                         case 18900000:
1314                             nLocation = css::table::ShadowLocation_TOP_RIGHT;
1315                             break;
1316                         case 8100000:
1317                             nLocation = css::table::ShadowLocation_BOTTOM_LEFT;
1318                             break;
1319                         case 2700000:
1320                             nLocation = css::table::ShadowLocation_BOTTOM_RIGHT;
1321                             break;
1322                         }
1323                         aFormat.Location = nLocation;
1324                     }
1325                     aFormat.ShadowWidth = *oShadowDistance;
1326                     aShapeProps.setProperty(PROP_ShadowFormat, aFormat);
1327                 }
1328 
1329             }
1330             else if (mbTextBox)
1331             {
1332                 aShapeProps.setProperty(PROP_TextBox, true);
1333             }
1334 
1335             if (aServiceName != "com.sun.star.text.TextFrame" && isLinkedTxbx())
1336             {
1337                 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1338                 uno::Sequence<beans::PropertyValue> aGrabBag;
1339                 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1340                 sal_Int32 length = aGrabBag.getLength();
1341                 aGrabBag.realloc( length + 3 );
1342                 aGrabBag[length].Name = "TxbxHasLink";
1343                 aGrabBag[length].Value <<= isLinkedTxbx();
1344                 aGrabBag[length + 1 ].Name = "Txbx-Id";
1345                 aGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1346                 aGrabBag[length + 2 ].Name = "Txbx-Seq";
1347                 aGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1348                 propertySet->setPropertyValue("InteropGrabBag",uno::makeAny(aGrabBag));
1349             }
1350 
1351             // If the shape is a picture placeholder.
1352             if (aServiceName == "com.sun.star.presentation.GraphicObjectShape" && !bClearText)
1353             {
1354                 // Placeholder text should be in center of the shape.
1355                 aShapeProps.setProperty(PROP_TextContourFrame, false);
1356 
1357                 /* Placeholder icon should be at the center of the parent shape.
1358                  * We use negative graphic crop property because of that we don't
1359                  * have padding support.
1360                  */
1361                 uno::Reference<beans::XPropertySet> xGraphic(xSet->getPropertyValue("Graphic"), uno::UNO_QUERY);
1362                 if (xGraphic.is())
1363                 {
1364                     awt::Size aBitmapSize;
1365                     xGraphic->getPropertyValue("Size100thMM") >>= aBitmapSize;
1366                     sal_Int32 nXMargin = (aShapeRectHmm.Width - aBitmapSize.Width) / 2;
1367                     sal_Int32 nYMargin = (aShapeRectHmm.Height - aBitmapSize.Height) / 2;
1368                     if (nXMargin > 0 && nYMargin > 0)
1369                     {
1370                         text::GraphicCrop aGraphicCrop;
1371                         aGraphicCrop.Top = nYMargin * -1;
1372                         aGraphicCrop.Bottom = nYMargin * -1;
1373                         aGraphicCrop.Left = nXMargin * -1;
1374                         aGraphicCrop.Right = nXMargin * -1;
1375                         aShapeProps.setProperty(PROP_GraphicCrop, aGraphicCrop);
1376                     }
1377                 }
1378             }
1379 
1380             PropertySet( xSet ).setProperties( aShapeProps );
1381             if (mbLockedCanvas)
1382             {
1383                 putPropertyToGrabBag( "LockedCanvas", Any( true ) );
1384                 if (aServiceName == "com.sun.star.drawing.LineShape")
1385                 {
1386                     // It seems the position and size for lines inside a locked canvas is absolute.
1387                     mxShape->setPosition(awt::Point(aShapeRectHmm.X, aShapeRectHmm.Y));
1388                     mxShape->setSize(awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
1389                 }
1390             }
1391 
1392             // Store original fill and line colors of the shape and the theme color name to InteropGrabBag
1393             std::vector<beans::PropertyValue> aProperties;
1394             aProperties.push_back(comphelper::makePropertyValue("EmuLineWidth", aLineProperties.moLineWidth.get(0)));
1395             aProperties.push_back(comphelper::makePropertyValue("OriginalSolidFillClr", aShapeProps.getProperty(PROP_FillColor)));
1396             aProperties.push_back(comphelper::makePropertyValue("OriginalLnSolidFillClr", aShapeProps.getProperty(PROP_LineColor)));
1397             OUString sColorFillScheme = aFillProperties.maFillColor.getSchemeName();
1398             if( !aFillProperties.maFillColor.isPlaceHolder() && !sColorFillScheme.isEmpty() )
1399             {
1400                 aProperties.push_back(comphelper::makePropertyValue("SpPrSolidFillSchemeClr", sColorFillScheme));
1401                 aProperties.push_back(comphelper::makePropertyValue("SpPrSolidFillSchemeClrTransformations", aFillProperties.maFillColor.getTransformations()));
1402             }
1403             OUString sLnColorFillScheme = aLineProperties.maLineFill.maFillColor.getSchemeName();
1404             if( !aLineProperties.maLineFill.maFillColor.isPlaceHolder() && !sLnColorFillScheme.isEmpty() )
1405             {
1406                 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillSchemeClr", sLnColorFillScheme));
1407                 auto aResolvedSchemeClr = aLineProperties.maLineFill.maFillColor;
1408                 aResolvedSchemeClr.clearTransformations();
1409                 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillResolvedSchemeClr", aResolvedSchemeClr.getColor(rGraphicHelper, nFillPhClr)));
1410                 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillSchemeClrTransformations", aLineProperties.maLineFill.maFillColor.getTransformations()));
1411             }
1412             putPropertiesToGrabBag(comphelper::containerToSequence(aProperties));
1413 
1414             // Store original gradient fill of the shape to InteropGrabBag
1415             // LibreOffice doesn't support all the kinds of gradient so we save its complete definition
1416             if( aShapeProps.hasProperty( PROP_FillGradient ) )
1417             {
1418                 std::vector<beans::PropertyValue> aGradientStops;
1419                 size_t i = 0;
1420                 for( const auto& [rPos, rColor] : aFillProperties.maGradientProps.maGradientStops )
1421                 { // for each stop in the gradient definition:
1422 
1423                     // save position
1424                     std::vector<beans::PropertyValue> aGradientStop;
1425                     aGradientStop.push_back(comphelper::makePropertyValue("Pos", rPos));
1426 
1427                     OUString sStopColorScheme = rColor.getSchemeName();
1428                     if( sStopColorScheme.isEmpty() )
1429                     {
1430                         // save RGB color
1431                         aGradientStop.push_back(comphelper::makePropertyValue("RgbClr", rColor.getColor(rGraphicHelper, nFillPhClr)));
1432                         // in the case of a RGB color, transformations are already applied to
1433                         // the color with the exception of alpha transformations. We only need
1434                         // to keep the transparency value to calculate the alpha value later.
1435                         if( rColor.hasTransparency() )
1436                             aGradientStop.push_back(comphelper::makePropertyValue("Transparency", rColor.getTransparency()));
1437                     }
1438                     else
1439                     {
1440                         // save color with scheme name
1441                         aGradientStop.push_back(comphelper::makePropertyValue("SchemeClr", sStopColorScheme));
1442                         // save all color transformations
1443                         aGradientStop.push_back(comphelper::makePropertyValue("Transformations", rColor.getTransformations()));
1444                     }
1445 
1446                     aGradientStops.push_back(comphelper::makePropertyValue(OUString::number(i), comphelper::containerToSequence(aGradientStop)));
1447                     ++i;
1448                 }
1449                 // If getFillProperties.moFillType is unused that means gradient is defined by a theme
1450                 // which is already saved into StyleFillRef property, so no need to save the explicit values too
1451                 if( getFillProperties().moFillType.has() )
1452                     putPropertyToGrabBag( "GradFillDefinition", uno::Any(comphelper::containerToSequence(aGradientStops)));
1453                 putPropertyToGrabBag( "OriginalGradFill", aShapeProps.getProperty(PROP_FillGradient) );
1454             }
1455 
1456             // store unsupported effect attributes in the grab bag
1457             if (!aEffectProperties.m_Effects.empty())
1458             {
1459                 std::vector<beans::PropertyValue> aEffects;
1460                 sal_uInt32 i = 0;
1461                 for (auto const& it : aEffectProperties.m_Effects)
1462                 {
1463                     PropertyValue aEffect = it->getEffect();
1464                     if( !aEffect.Name.isEmpty() )
1465                     {
1466                         std::vector<beans::PropertyValue> aEffectsGrabBag;
1467                         aEffectsGrabBag.push_back(comphelper::makePropertyValue("Attribs", aEffect.Value));
1468 
1469                         Color& aColor( it->moColor );
1470                         OUString sColorScheme = aColor.getSchemeName();
1471                         if( sColorScheme.isEmpty() )
1472                         {
1473                             // RGB color and transparency value
1474                             aEffectsGrabBag.push_back(comphelper::makePropertyValue("RgbClr", aColor.getColor(rGraphicHelper, nFillPhClr)));
1475                             aEffectsGrabBag.push_back(comphelper::makePropertyValue("RgbClrTransparency", aColor.getTransparency()));
1476                         }
1477                         else
1478                         {
1479                             // scheme color with name and transformations
1480                             aEffectsGrabBag.push_back(comphelper::makePropertyValue("SchemeClr", sColorScheme));
1481                             aEffectsGrabBag.push_back(comphelper::makePropertyValue("SchemeClrTransformations", aColor.getTransformations()));
1482                         }
1483                         aEffects.push_back(comphelper::makePropertyValue(aEffect.Name, comphelper::containerToSequence(aEffectsGrabBag)));
1484                         ++i;
1485                     }
1486                 }
1487                 putPropertyToGrabBag("EffectProperties", uno::Any(comphelper::containerToSequence(aEffects)));
1488             }
1489 
1490             // add 3D effects if any
1491             Sequence< PropertyValue > aCamera3DEffects = get3DProperties().getCameraAttributes();
1492             Sequence< PropertyValue > aLightRig3DEffects = get3DProperties().getLightRigAttributes();
1493             Sequence< PropertyValue > aShape3DEffects = get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1494             if( aCamera3DEffects.hasElements() || aLightRig3DEffects.hasElements() || aShape3DEffects.hasElements() )
1495             {
1496                 uno::Sequence<beans::PropertyValue> a3DEffectsGrabBag = comphelper::InitPropertySequence(
1497                 {
1498                     {"Camera", uno::makeAny(aCamera3DEffects)},
1499                     {"LightRig", uno::makeAny(aLightRig3DEffects)},
1500                     {"Shape3D", uno::makeAny(aShape3DEffects)}
1501                 });
1502                 putPropertyToGrabBag( "3DEffectProperties", Any( a3DEffectsGrabBag ) );
1503             }
1504 
1505             if( bIsCustomShape && getTextBody())
1506             {
1507 
1508                 Sequence< PropertyValue > aTextCamera3DEffects = getTextBody()->get3DProperties().getCameraAttributes();
1509                 Sequence< PropertyValue > aTextLightRig3DEffects = getTextBody()->get3DProperties().getLightRigAttributes();
1510                 Sequence< PropertyValue > aTextShape3DEffects = getTextBody()->get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1511                 if( aTextCamera3DEffects.hasElements() || aTextLightRig3DEffects.hasElements() || aTextShape3DEffects.hasElements() )
1512                 {
1513                     uno::Sequence<beans::PropertyValue> aText3DEffectsGrabBag = comphelper::InitPropertySequence(
1514                     {
1515                         {"Camera", uno::makeAny(aTextCamera3DEffects)},
1516                         {"LightRig", uno::makeAny(aTextLightRig3DEffects)},
1517                         {"Shape3D", uno::makeAny(aTextShape3DEffects)}
1518                     });
1519                     putPropertyToGrabBag( "Text3DEffectProperties", Any( aText3DEffectsGrabBag ) );
1520                 }
1521             }
1522 
1523             // store bitmap artistic effects in the grab bag
1524             if( !mpGraphicPropertiesPtr->maBlipProps.maEffect.isEmpty() )
1525                 putPropertyToGrabBag( "ArtisticEffectProperties",
1526                                       Any( mpGraphicPropertiesPtr->maBlipProps.maEffect.getEffect() ) );
1527         }
1528 
1529         else if( mbLockedCanvas )
1530         {
1531             //If we have aServiceName as "com.sun.star.drawing.GroupShape" and lockedCanvas
1532             putPropertyToGrabBag( "LockedCanvas", Any( true ) );
1533         }
1534 
1535         // These can have a custom geometry, so position should be set here,
1536         // after creation but before custom shape handling, using the position
1537         // we got from the caller.
1538         if (mbWps && aServiceName == "com.sun.star.drawing.LineShape")
1539             mxShape->setPosition(maPosition);
1540 
1541         if( bIsCustomShape )
1542         {
1543             if ( mbFlipH )
1544                 mpCustomShapePropertiesPtr->setMirroredX( true );
1545             if ( mbFlipV )
1546                 mpCustomShapePropertiesPtr->setMirroredY( true );
1547             if( getTextBody() )
1548             {
1549                 sal_Int32 nTextCameraZRotation = static_cast< sal_Int32 >( getTextBody()->get3DProperties().maCameraRotation.mnRevolution.get() );
1550                 mpCustomShapePropertiesPtr->setTextCameraZRotateAngle( nTextCameraZRotation / 60000 );
1551 
1552                 sal_Int32 nTextRotateAngle = static_cast< sal_Int32 >( getTextBody()->getTextProperties().moRotation.get( 0 ) );
1553 
1554                 nTextRotateAngle -= mnDiagramRotation;
1555                 /* OOX measures text rotation clockwise in 1/60000th degrees,
1556                    relative to the containing shape. setTextRotateAngle wants degrees anticlockwise. */
1557                 nTextRotateAngle = -1 * nTextRotateAngle / 60000;
1558 
1559                 if (getTextBody()->getTextProperties().moUpright)
1560                 {
1561                     // When upright is set, we want the text without any rotation.
1562                     // But if we set 0 here, the text is still rotated if the
1563                     // shape containing it is rotated.
1564                     // Hence, we rotate the text into the opposite direction of
1565                     // the rotation of the shape, by as much as the shape was rotated.
1566                     mpCustomShapePropertiesPtr->setTextRotateAngle((mnRotation / 60000) + nTextRotateAngle);
1567                     // Also put the initial angles away in a GrabBag.
1568                     putPropertyToGrabBag("Upright", Any(true));
1569                     putPropertyToGrabBag("nShapeRotationAtImport", Any(mnRotation / 60000));
1570                     putPropertyToGrabBag("nTextRotationAtImport", Any(nTextRotateAngle));
1571                 }
1572                 else
1573                 {
1574                     mpCustomShapePropertiesPtr->setTextRotateAngle(nTextRotateAngle);
1575                 }
1576 
1577                 auto sHorzOverflow = getTextBody()->getTextProperties().msHorzOverflow;
1578                 if (!sHorzOverflow.isEmpty())
1579                     putPropertyToGrabBag("horzOverflow", uno::makeAny(getTextBody()->getTextProperties().msHorzOverflow));
1580                 auto nVertOverflow = getTextBody()->getTextProperties().msVertOverflow;
1581                 if (!nVertOverflow.isEmpty())
1582                     putPropertyToGrabBag("vertOverflow", uno::makeAny(getTextBody()->getTextProperties().msVertOverflow));
1583             }
1584 
1585             // Note that the script oox/source/drawingml/customshapes/generatePresetsData.pl looks
1586             // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs
1587             SAL_INFO("oox.cscode", "==cscode== shape name: '" << msName << "'");
1588             SAL_INFO("oox.csdata", "==csdata== shape name: '" << msName << "'");
1589             mpCustomShapePropertiesPtr->pushToPropSet( xSet, mxShape, maSize );
1590 
1591             if (mpTextBody)
1592             {
1593                 bool bIsPresetShape = !mpTextBody->getTextProperties().msPrst.isEmpty();
1594                 if (bIsPresetShape)
1595                 {
1596                     OUString sClass;
1597                     const OUString sPresetType = mpTextBody->getTextProperties().msPrst;
1598                     sClass = PresetGeometryTypeNames::GetFontworkType( sPresetType );
1599 
1600                     lcl_createPresetShape( mxShape, sClass, sPresetType, mpCustomShapePropertiesPtr, mpTextBody, rGraphicHelper );
1601                 }
1602             }
1603         }
1604         else if( getTextBody() )
1605             getTextBody()->getTextProperties().pushVertSimulation();
1606 
1607         // tdf#133037: a bit hackish: force Shape to rotate in the opposite direction the camera would rotate
1608         const sal_Int32 nCameraRotation = get3DProperties().maCameraRotation.mnRevolution.get(0);
1609 
1610         PropertySet aPropertySet(mxShape);
1611         if ( !bUseRotationTransform && (mnRotation != 0 || nCameraRotation != 0) )
1612         {
1613             // use the same logic for rotation from VML exporter (SimpleShape::implConvertAndInsert at vmlshape.cxx)
1614             Degree100 nAngle = NormAngle36000( Degree100((mnRotation - nCameraRotation) / -600) );
1615             aPropertySet.setAnyProperty( PROP_RotateAngle, makeAny( sal_Int32( nAngle.get() ) ) );
1616             aPropertySet.setAnyProperty( PROP_HoriOrientPosition, makeAny( maPosition.X ) );
1617             aPropertySet.setAnyProperty( PROP_VertOrientPosition, makeAny( maPosition.Y ) );
1618         }
1619 
1620         // in some cases, we don't have any text body.
1621         if( getTextBody() && ( !bDoNotInsertEmptyTextBody || !mpTextBody->isEmpty() ) )
1622         {
1623             Reference < XText > xText( mxShape, UNO_QUERY );
1624             if ( xText.is() )   // not every shape is supporting an XText interface (e.g. GroupShape)
1625             {
1626                 TextCharacterProperties aCharStyleProperties;
1627                 if( const ShapeStyleRef* pFontRef = getShapeStyleRef( XML_fontRef ) )
1628                 {
1629                     if( pFontRef->mnThemedIdx != 0 )
1630                     {
1631                         if( pTheme )
1632                             if( const TextCharacterProperties* pCharProps = pTheme->getFontStyle( pFontRef->mnThemedIdx ) )
1633                                 aCharStyleProperties.assignUsed( *pCharProps );
1634                         SAL_INFO("oox.drawingml", "Shape::createAndInsert: use font color");
1635                         if ( pFontRef->maPhClr.isUsed() )
1636                         {
1637                             aCharStyleProperties.maFillProperties.maFillColor = pFontRef->maPhClr;
1638                             aCharStyleProperties.maFillProperties.moFillType.set(XML_solidFill);
1639                         }
1640                     }
1641                 }
1642                 xText->setString("");
1643                 Reference < XTextCursor > xAt = xText->createTextCursor();
1644                 getTextBody()->insertAt( rFilterBase, xText, xAt, aCharStyleProperties, mpMasterTextListStyle );
1645 
1646                 const TextParagraphVector& rParagraphs = getTextBody()->getParagraphs();
1647                 if (!rParagraphs.empty())
1648                 {
1649                     const std::shared_ptr<TextParagraph>& pParagraph = rParagraphs[0];
1650                     if (pParagraph->getProperties().getParaAdjust())
1651                     {
1652                         style::ParagraphAdjust eAdjust = *pParagraph->getProperties().getParaAdjust();
1653                         if (eAdjust == style::ParagraphAdjust_CENTER)
1654                         {
1655                             // If the first paragraph is centered, then set the para adjustment of
1656                             // the shape itself to centered as well.
1657                             aPropertySet.setAnyProperty(PROP_ParaAdjust, uno::makeAny(eAdjust));
1658                         }
1659                     }
1660                 }
1661             }
1662         }
1663         else if (mbTextBox)
1664         {
1665             // No drawingML text, but WPS text is expected: save the theme
1666             // character color on the shape, then.
1667             if(const ShapeStyleRef* pFontRef = getShapeStyleRef(XML_fontRef))
1668             {
1669                 ::Color nCharColor = pFontRef->maPhClr.getColor(rGraphicHelper);
1670                 aPropertySet.setAnyProperty(PROP_CharColor, uno::makeAny(nCharColor));
1671             }
1672         }
1673 
1674         // Set glow effect properties
1675         if ( aEffectProperties.maGlow.moGlowRad.has() )
1676         {
1677             uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1678             propertySet->setPropertyValue("GlowEffectRadius", makeAny(convertEmuToHmm(aEffectProperties.maGlow.moGlowRad.get())));
1679             propertySet->setPropertyValue("GlowEffectColor", makeAny(aEffectProperties.maGlow.moGlowColor.getColor(rGraphicHelper)));
1680             propertySet->setPropertyValue("GlowEffectTransparency", makeAny(aEffectProperties.maGlow.moGlowColor.getTransparency()));
1681         }
1682 
1683         // Set soft edge effect properties
1684         if (aEffectProperties.maSoftEdge.moRad.has())
1685         {
1686             uno::Reference<beans::XPropertySet> propertySet(mxShape, uno::UNO_QUERY);
1687             propertySet->setPropertyValue(
1688                 "SoftEdgeRadius", makeAny(convertEmuToHmm(aEffectProperties.maSoftEdge.moRad.get())));
1689         }
1690     }
1691 
1692     if( mxShape.is() )
1693         finalizeXShape( rFilterBase, rxShapes );
1694 
1695     return mxShape;
1696 }
1697 
keepDiagramDrawing(XmlFilterBase & rFilterBase,const OUString & rFragmentPath)1698 void Shape::keepDiagramDrawing(XmlFilterBase& rFilterBase, const OUString& rFragmentPath)
1699 {
1700     uno::Sequence<uno::Any> diagramDrawing(2);
1701     // drawingValue[0] => dom, drawingValue[1] => Sequence of associated relationships
1702 
1703     sal_Int32 length = maDiagramDoms.getLength();
1704     maDiagramDoms.realloc(length + 1);
1705 
1706     diagramDrawing[0] <<= rFilterBase.importFragment(rFragmentPath);
1707     diagramDrawing[1] <<= resolveRelationshipsOfTypeFromOfficeDoc(rFilterBase, rFragmentPath, u"image");
1708 
1709     beans::PropertyValue* pValue = maDiagramDoms.getArray();
1710     pValue[length].Name = "OOXDrawing";
1711     pValue[length].Value <<= diagramDrawing;
1712 }
1713 
keepDiagramCompatibilityInfo()1714 void Shape::keepDiagramCompatibilityInfo()
1715 {
1716     try
1717     {
1718         if( !maDiagramDoms.hasElements() )
1719             return;
1720 
1721         Reference < XPropertySet > xSet( mxShape, UNO_QUERY_THROW );
1722         Reference < XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1723         if ( !xSetInfo.is() )
1724             return;
1725 
1726         if (mpDiagramData)
1727         {
1728             if (SdrObject* pObj = GetSdrObjectFromXShape(mxShape))
1729                 pObj->SetDiagramData(mpDiagramData);
1730         }
1731 
1732         const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1733         if( !xSetInfo->hasPropertyByName( aGrabBagPropName ) )
1734             return;
1735 
1736         Sequence < PropertyValue > aGrabBag;
1737         xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
1738 
1739         // We keep the previous items, if present
1740         if ( aGrabBag.hasElements() )
1741             xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, maDiagramDoms) ) );
1742         else
1743             xSet->setPropertyValue( aGrabBagPropName, Any( maDiagramDoms ) );
1744     }
1745     catch( const Exception& )
1746     {
1747         TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::keepDiagramCompatibilityInfo" );
1748     }
1749 }
1750 
syncDiagramFontHeights()1751 void Shape::syncDiagramFontHeights()
1752 {
1753     // Each name represents a group of shapes, for which the font height should have the same
1754     // scaling.
1755     for (const auto& rNameAndPairs : maDiagramFontHeights)
1756     {
1757         // Find out the minimum scale within this group.
1758         const ShapePairs& rShapePairs = rNameAndPairs.second;
1759         sal_Int16 nMinScale = 100;
1760         for (const auto& rShapePair : rShapePairs)
1761         {
1762             uno::Reference<beans::XPropertySet> xPropertySet(rShapePair.second, uno::UNO_QUERY);
1763             if (xPropertySet.is())
1764             {
1765                 sal_Int16 nTextFitToSizeScale = 0;
1766                 xPropertySet->getPropertyValue("TextFitToSizeScale") >>= nTextFitToSizeScale;
1767                 if (nTextFitToSizeScale > 0 && nTextFitToSizeScale < nMinScale)
1768                 {
1769                     nMinScale = nTextFitToSizeScale;
1770                 }
1771             }
1772         }
1773 
1774         // Set that minimum scale for all members of the group.
1775         if (nMinScale < 100)
1776         {
1777             for (const auto& rShapePair : rShapePairs)
1778             {
1779                 uno::Reference<beans::XPropertySet> xPropertySet(rShapePair.second, uno::UNO_QUERY);
1780                 if (xPropertySet.is())
1781                 {
1782                     xPropertySet->setPropertyValue("TextFitToSizeScale", uno::makeAny(nMinScale));
1783                 }
1784             }
1785         }
1786     }
1787 }
1788 
convertSmartArtToMetafile(XmlFilterBase const & rFilterBase)1789 void Shape::convertSmartArtToMetafile(XmlFilterBase const & rFilterBase)
1790 {
1791     try
1792     {
1793         Reference<XPropertySet> xSet(mxShape, UNO_QUERY_THROW);
1794 
1795         xSet->setPropertyValue("MoveProtect", Any(true));
1796         xSet->setPropertyValue("SizeProtect", Any(true));
1797 
1798         // Replace existing shapes with a new Graphic Object rendered
1799         // from them
1800         Reference<XShape> xShape(renderDiagramToGraphic(rFilterBase));
1801         Reference<XShapes> xShapes(mxShape, UNO_QUERY_THROW);
1802         while (xShapes->hasElements())
1803             xShapes->remove(Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW));
1804         xShapes->add(xShape);
1805     }
1806     catch (const Exception&)
1807     {
1808         TOOLS_WARN_EXCEPTION("oox.drawingml", "Shape::convertSmartArtToMetafile");
1809     }
1810 }
1811 
renderDiagramToGraphic(XmlFilterBase const & rFilterBase)1812 Reference < XShape > Shape::renderDiagramToGraphic( XmlFilterBase const & rFilterBase )
1813 {
1814     Reference< XShape > xShape;
1815 
1816     try
1817     {
1818         if( !maDiagramDoms.hasElements() )
1819             return xShape;
1820 
1821         // Stream in which to place the rendered shape
1822         SvMemoryStream aTempStream;
1823         Reference < io::XStream > xStream( new utl::OStreamWrapper( aTempStream ) );
1824         Reference < io::XOutputStream > xOutputStream( xStream->getOutputStream() );
1825 
1826         // Size of the rendering
1827         awt::Size aActualSize = mxShape->getSize();
1828         Size aResolution(Application::GetDefaultDevice()->LogicToPixel(Size(100, 100), MapMode(MapUnit::MapCM)));
1829         double fPixelsPer100thmm = static_cast < double > ( aResolution.Width() ) / 100000.0;
1830         awt::Size aSize( static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Width ) + 0.5 ),
1831                          static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Height ) + 0.5 ) );
1832 
1833         Sequence< PropertyValue > aFilterData( 4 );
1834         aFilterData[ 0 ].Name = "PixelWidth";
1835         aFilterData[ 0 ].Value <<= aSize.Width;
1836         aFilterData[ 1 ].Name = "PixelHeight";
1837         aFilterData[ 1 ].Value <<= aSize.Height;
1838         aFilterData[ 2 ].Name = "LogicalWidth";
1839         aFilterData[ 2 ].Value <<= aActualSize.Width;
1840         aFilterData[ 3 ].Name = "LogicalHeight";
1841         aFilterData[ 3 ].Value <<= aActualSize.Height;
1842 
1843         Sequence < PropertyValue > aDescriptor( 3 );
1844         aDescriptor[ 0 ].Name = "OutputStream";
1845         aDescriptor[ 0 ].Value <<= xOutputStream;
1846         aDescriptor[ 1 ].Name = "FilterName";
1847         aDescriptor[ 1 ].Value <<= OUString("SVM"); // Rendering format
1848         aDescriptor[ 2 ].Name = "FilterData";
1849         aDescriptor[ 2 ].Value <<= aFilterData;
1850 
1851         Reference < lang::XComponent > xSourceDoc( mxShape, UNO_QUERY_THROW );
1852         Reference < XGraphicExportFilter > xGraphicExporter = GraphicExportFilter::create( rFilterBase.getComponentContext() );
1853         xGraphicExporter->setSourceDocument( xSourceDoc );
1854         xGraphicExporter->filter( aDescriptor );
1855 
1856         aTempStream.Seek( STREAM_SEEK_TO_BEGIN );
1857 
1858         Graphic aGraphic;
1859         GraphicFilter aFilter( false );
1860         if ( aFilter.ImportGraphic( aGraphic, "", aTempStream, GRFILTER_FORMAT_NOTFOUND, nullptr, GraphicFilterImportFlags::NONE, static_cast < Sequence < PropertyValue >* > ( nullptr ) ) != ERRCODE_NONE )
1861         {
1862             SAL_WARN( "oox.drawingml", "Shape::renderDiagramToGraphic: Unable to import rendered stream into graphic object" );
1863             return xShape;
1864         }
1865 
1866         Reference < graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() );
1867         Reference < lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
1868         xShape.set( xServiceFact->createInstance( "com.sun.star.drawing.GraphicObjectShape" ), UNO_QUERY_THROW );
1869         Reference < XPropertySet > xPropSet( xShape, UNO_QUERY_THROW );
1870         xPropSet->setPropertyValue(  "Graphic", Any( xGraphic ) );
1871         xPropSet->setPropertyValue(  "MoveProtect", Any( true ) );
1872         xPropSet->setPropertyValue(  "SizeProtect", Any( true ) );
1873         xPropSet->setPropertyValue(  "Name", Any( OUString( "RenderedShapes" ) ) );
1874     }
1875     catch( const Exception& )
1876     {
1877         TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::renderDiagramToGraphic" );
1878     }
1879 
1880     return xShape;
1881 }
1882 
setTextBody(const TextBodyPtr & pTextBody)1883 void Shape::setTextBody(const TextBodyPtr & pTextBody)
1884 {
1885     mpTextBody = pTextBody;
1886 }
1887 
setMasterTextListStyle(const TextListStylePtr & pMasterTextListStyle)1888 void Shape::setMasterTextListStyle( const TextListStylePtr& pMasterTextListStyle )
1889 {
1890     SAL_INFO("oox.drawingml", "Shape::setMasterTextListStyle: Set master text list style to shape id='" << msId << "'");
1891 
1892     mpMasterTextListStyle = pMasterTextListStyle;
1893 }
1894 
finalizeServiceName(XmlFilterBase & rFilter,const OUString & rServiceName,const awt::Rectangle & rShapeRect)1895 OUString Shape::finalizeServiceName( XmlFilterBase& rFilter, const OUString& rServiceName, const awt::Rectangle& rShapeRect )
1896 {
1897     OUString aServiceName = rServiceName;
1898     switch( meFrameType )
1899     {
1900         case FRAMETYPE_OLEOBJECT:
1901         {
1902             awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1903             if( rFilter.getOleObjectHelper().importOleObject( maShapeProperties, *mxOleObjectInfo, aOleSize ) )
1904                 aServiceName = "com.sun.star.drawing.OLE2Shape";
1905 
1906             // get the path to the representation graphic
1907             OUString aGraphicPath;
1908             if( !mxOleObjectInfo->maShapeId.isEmpty() )
1909                 if( ::oox::vml::Drawing* pVmlDrawing = rFilter.getVmlDrawing() )
1910                     if( const ::oox::vml::ShapeBase* pVmlShape = pVmlDrawing->getShapes().getShapeById( mxOleObjectInfo->maShapeId ) )
1911                         aGraphicPath = pVmlShape->getGraphicPath();
1912 
1913             // import and store the graphic
1914             if( !aGraphicPath.isEmpty() )
1915             {
1916                 // Transfer shape's width and height to graphicsfilter (can be used by WMF/EMF)
1917                 WmfExternal aExtHeader;
1918                 aExtHeader.mapMode = 8; // MM_ANISOTROPIC
1919                 aExtHeader.xExt = rShapeRect.Width;
1920                 aExtHeader.yExt = rShapeRect.Height;
1921 
1922                 Reference< graphic::XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath, &aExtHeader );
1923                 if( xGraphic.is() )
1924                     maShapeProperties.setProperty(PROP_Graphic, xGraphic);
1925             }
1926         }
1927         break;
1928 
1929         default:;
1930     }
1931     return aServiceName;
1932 }
1933 
finalizeXShape(XmlFilterBase & rFilter,const Reference<XShapes> & rxShapes)1934 void Shape::finalizeXShape( XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes )
1935 {
1936     switch( meFrameType )
1937     {
1938         case FRAMETYPE_CHART:
1939         {
1940             OSL_ENSURE( !mxChartShapeInfo->maFragmentPath.isEmpty(), "Shape::finalizeXShape - missing chart fragment" );
1941             if( mxShape.is() && !mxChartShapeInfo->maFragmentPath.isEmpty() ) try
1942             {
1943                 // set the chart2 OLE class ID at the OLE shape
1944                 PropertySet aShapeProp( mxShape );
1945                 aShapeProp.setProperty( PROP_CLSID, OUString( "12dcae26-281f-416f-a234-c3086127382e" ) );
1946 
1947                 // get the XModel interface of the embedded object from the OLE shape
1948                 Reference< frame::XModel > xDocModel;
1949                 aShapeProp.getProperty( xDocModel, PROP_Model );
1950                 Reference< chart2::XChartDocument > xChartDoc( xDocModel, UNO_QUERY_THROW );
1951 
1952                 // load the chart data from the XML fragment
1953                 bool bMSO2007Doc = rFilter.isMSO2007Document();
1954                 chart::ChartSpaceModel aModel(bMSO2007Doc);
1955                 rtl::Reference<chart::ChartSpaceFragment> pChartSpaceFragment = new chart::ChartSpaceFragment(
1956                         rFilter, mxChartShapeInfo->maFragmentPath, aModel );
1957                 const OUString aThemeOverrideFragmentPath( pChartSpaceFragment->
1958                         getFragmentPathFromFirstTypeFromOfficeDoc(u"themeOverride") );
1959                 rFilter.importFragment( pChartSpaceFragment );
1960                 ::oox::ppt::PowerPointImport *pPowerPointImport =
1961                     dynamic_cast< ::oox::ppt::PowerPointImport* >(&rFilter);
1962 
1963                 // The original theme.
1964                 ThemePtr pTheme;
1965 
1966                 if (!aThemeOverrideFragmentPath.isEmpty() && pPowerPointImport)
1967                 {
1968                     // Handle theme override.
1969                     uno::Reference< xml::sax::XFastSAXSerializable > xDoc(
1970                             rFilter.importFragment(aThemeOverrideFragmentPath), uno::UNO_QUERY_THROW);
1971                     pTheme = pPowerPointImport->getActualSlidePersist()->getTheme();
1972                     auto pThemeOverride = std::make_shared<Theme>(*pTheme);
1973                     rFilter.importFragment(
1974                         new ThemeOverrideFragmentHandler(rFilter, aThemeOverrideFragmentPath,
1975                                                          *pThemeOverride),
1976                         xDoc);
1977                     pPowerPointImport->getActualSlidePersist()->setTheme(pThemeOverride);
1978                 }
1979 
1980                 // convert imported chart model to chart document
1981                 Reference< drawing::XShapes > xExternalPage;
1982                 if( !mxChartShapeInfo->mbEmbedShapes )
1983                     xExternalPage = rxShapes;
1984                 if( rFilter.getChartConverter() )
1985                 {
1986                     rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
1987                     if( !xChartDoc->hasInternalDataProvider() )
1988                     {
1989                         Reference< chart2::data::XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
1990                         Reference< chart2::data::XDataSource > xData = xDataRec->getUsedData();
1991                         if( !xData->getDataSequences().hasElements() || !xData->getDataSequences()[0]->getValues().is() ||
1992                                 !xData->getDataSequences()[0]->getValues()->getData().hasElements() )
1993                         {
1994                             rFilter.useInternalChartDataTable( true );
1995                             rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
1996                             rFilter.useInternalChartDataTable( false );
1997                         }
1998                     }
1999 
2000                 }
2001 
2002                 if (!aThemeOverrideFragmentPath.isEmpty() && pPowerPointImport)
2003                 {
2004                     // Restore the original theme.
2005                     pPowerPointImport->getActualSlidePersist()->setTheme(pTheme);
2006                 }
2007             }
2008             catch( Exception& )
2009             {
2010             }
2011         }
2012         break;
2013 
2014         default:;
2015     }
2016 }
2017 
putPropertyToGrabBag(const OUString & sPropertyName,const Any & aPropertyValue)2018 void Shape::putPropertyToGrabBag( const OUString& sPropertyName, const Any& aPropertyValue )
2019 {
2020     PropertyValue aNewProperty;
2021     aNewProperty.Name = sPropertyName;
2022     aNewProperty.Value = aPropertyValue;
2023     putPropertyToGrabBag( aNewProperty );
2024 }
2025 
putPropertyToGrabBag(const PropertyValue & pProperty)2026 void Shape::putPropertyToGrabBag( const PropertyValue& pProperty )
2027 {
2028     Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2029     Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2030     const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2031     if( mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName ) )
2032     {
2033         Sequence< PropertyValue > aGrabBag;
2034         xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2035 
2036         sal_Int32 length = aGrabBag.getLength();
2037         aGrabBag.realloc( length + 1 );
2038         aGrabBag[length] = pProperty;
2039 
2040         xSet->setPropertyValue( aGrabBagPropName, Any( aGrabBag ) );
2041     }
2042 }
2043 
putPropertiesToGrabBag(const Sequence<PropertyValue> & aProperties)2044 void Shape::putPropertiesToGrabBag( const Sequence< PropertyValue >& aProperties )
2045 {
2046     Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2047     Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2048     const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2049     if( !(mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName )) )
2050         return;
2051 
2052     // get existing grab bag
2053     Sequence< PropertyValue > aGrabBag;
2054     xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2055 
2056     std::vector<PropertyValue> aVec;
2057     aVec.reserve(aProperties.getLength());
2058 
2059     // put the new items
2060     std::transform(aProperties.begin(), aProperties.end(), std::back_inserter(aVec),
2061         [](const PropertyValue& rProp) {
2062             PropertyValue aProp;
2063             aProp.Name = rProp.Name;
2064             aProp.Value = rProp.Value;
2065             return aProp;
2066         });
2067 
2068     // put it back to the shape
2069     xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, aVec) ) );
2070 }
2071 
getActualFillProperties(const Theme * pTheme,const FillProperties * pParentShapeFillProps) const2072 FillProperties Shape::getActualFillProperties(const Theme* pTheme, const FillProperties* pParentShapeFillProps) const
2073 {
2074     FillProperties aFillProperties;
2075     aFillProperties.moFillType = XML_noFill;
2076 
2077     // Reference shape properties
2078     aFillProperties.assignUsed( *mpShapeRefFillPropPtr );
2079 
2080     // Theme
2081     if( pTheme != nullptr )
2082     {
2083         if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
2084         {
2085             if( const FillProperties* pFillProps = pTheme->getFillStyle( pFillRef->mnThemedIdx ) )
2086                 aFillProperties.assignUsed( *pFillProps );
2087         }
2088     }
2089 
2090     // Properties specified directly for this shape
2091     aFillProperties.assignUsed(getFillProperties());
2092 
2093     // Parent shape's properties
2094     if ( pParentShapeFillProps != nullptr)
2095         if( getFillProperties().moFillType.has() && getFillProperties().moFillType.get() == XML_grpFill )
2096             aFillProperties.assignUsed( *pParentShapeFillProps );
2097 
2098     return aFillProperties;
2099 }
2100 
getActualLineProperties(const Theme * pTheme) const2101 LineProperties Shape::getActualLineProperties(const Theme* pTheme) const
2102 {
2103     LineProperties aLineProperties;
2104     aLineProperties.maLineFill.moFillType = XML_noFill;
2105 
2106     // Reference shape properties
2107     aLineProperties.assignUsed( *mpShapeRefLinePropPtr );
2108 
2109     // Theme
2110     if( pTheme != nullptr )
2111     {
2112         if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
2113         {
2114             if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
2115                 aLineProperties.assignUsed( *pLineProps );
2116         }
2117     }
2118 
2119     // Properties specified directly for this shape
2120     aLineProperties.assignUsed( getLineProperties() );
2121 
2122     return aLineProperties;
2123 }
2124 
getActualEffectProperties(const Theme * pTheme) const2125 EffectProperties Shape::getActualEffectProperties(const Theme* pTheme) const
2126 {
2127     EffectProperties aEffectProperties;
2128 
2129     // Reference shape properties
2130     aEffectProperties.assignUsed( *mpShapeRefEffectPropPtr );
2131 
2132     // Theme
2133     if( pTheme != nullptr )
2134     {
2135         if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
2136         {
2137             if( const EffectProperties* pEffectProps = pTheme->getEffectStyle( pEffectRef->mnThemedIdx ) )
2138                 aEffectProperties.assignUsed( *pEffectProps );
2139         }
2140     }
2141 
2142     // Properties specified directly for this shape
2143     aEffectProperties.assignUsed ( getEffectProperties() );
2144 
2145     return aEffectProperties;
2146 }
2147 
resolveRelationshipsOfTypeFromOfficeDoc(core::XmlFilterBase & rFilter,const OUString & sFragment,std::u16string_view sType)2148 uno::Sequence< uno::Sequence< uno::Any > >  Shape::resolveRelationshipsOfTypeFromOfficeDoc(core::XmlFilterBase& rFilter, const OUString& sFragment, std::u16string_view sType )
2149 {
2150     uno::Sequence< uno::Sequence< uno::Any > > xRelListTemp;
2151     sal_Int32 counter = 0;
2152 
2153     core::RelationsRef xRels = rFilter.importRelations( sFragment );
2154     if ( xRels )
2155     {
2156         core::RelationsRef xImageRels = xRels->getRelationsFromTypeFromOfficeDoc( sType );
2157         if ( xImageRels )
2158         {
2159             xRelListTemp.realloc( xImageRels->size() );
2160             for (auto const& imageRel : *xImageRels)
2161             {
2162                 uno::Sequence< uno::Any > diagramRelTuple (3);
2163                 // [0] => RID, [1] => InputStream [2] => extension
2164                 OUString sRelId = imageRel.second.maId;
2165 
2166                 diagramRelTuple[0] <<= sRelId;
2167                 OUString sTarget = xImageRels->getFragmentPathFromRelId( sRelId );
2168 
2169                 uno::Reference< io::XInputStream > xImageInputStrm( rFilter.openInputStream( sTarget ), uno::UNO_SET_THROW );
2170                 StreamDataSequence dataSeq;
2171                 if ( rFilter.importBinaryData( dataSeq, sTarget ) )
2172                 {
2173                     diagramRelTuple[1] <<= dataSeq;
2174                 }
2175 
2176                 diagramRelTuple[2] <<= sTarget.copy( sTarget.lastIndexOf(".") );
2177 
2178                 xRelListTemp[counter] = diagramRelTuple;
2179                 ++counter;
2180             }
2181             xRelListTemp.realloc(counter);
2182 
2183         }
2184     }
2185     return xRelListTemp;
2186 }
2187 
cloneFillProperties()2188 void Shape::cloneFillProperties()
2189 {
2190     auto pFillProperties = std::make_shared<FillProperties>();
2191     pFillProperties->assignUsed(*mpFillPropertiesPtr);
2192     mpFillPropertiesPtr = pFillProperties;
2193 }
2194 }
2195 
2196 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2197