xref: /core/oox/source/drawingml/shape.cxx (revision 41c59a730ffce72202083b8ce3438c10ba18f1d1)
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 <config_wasm_strip.h>
21 
22 #include <oox/drawingml/shape.hxx>
23 #include <drawingml/customshapeproperties.hxx>
24 #include <oox/drawingml/theme.hxx>
25 #include <drawingml/fillproperties.hxx>
26 #include <drawingml/fontworkhelpers.hxx>
27 #include <drawingml/graphicproperties.hxx>
28 #include <drawingml/lineproperties.hxx>
29 #include <drawingml/presetgeometrynames.hxx>
30 #include <drawingml/shape3dproperties.hxx>
31 #include <drawingml/scene3dhelper.hxx>
32 #include <oox/drawingml/effectproperties.hxx>
33 #include <oox/drawingml/shapepropertymap.hxx>
34 #include <drawingml/textbody.hxx>
35 #include <drawingml/textparagraph.hxx>
36 #include <drawingml/ThemeOverrideFragmentHandler.hxx>
37 #include <drawingml/table/tableproperties.hxx>
38 #include <oox/drawingml/chart/chartconverter.hxx>
39 #include <drawingml/chart/chartspacefragment.hxx>
40 #include <drawingml/chart/chartspacemodel.hxx>
41 #include <o3tl/safeint.hxx>
42 #include <o3tl/unit_conversion.hxx>
43 #include <oox/ppt/pptimport.hxx>
44 #include <oox/vml/vmldrawing.hxx>
45 #include <oox/vml/vmlshape.hxx>
46 #include <oox/vml/vmlshapecontainer.hxx>
47 #include <oox/core/xmlfilterbase.hxx>
48 #include <oox/helper/graphichelper.hxx>
49 #include <oox/helper/propertyset.hxx>
50 #include <oox/helper/modelobjecthelper.hxx>
51 #include <oox/mathml/imexport.hxx>
52 #include <oox/mathml/importutils.hxx>
53 #include <oox/token/properties.hxx>
54 #include "diagram/datamodel.hxx"
55 #include "diagram/diagramhelper.hxx"
56 
57 #include <comphelper/classids.hxx>
58 #include <comphelper/propertysequence.hxx>
59 #include <comphelper/propertyvalue.hxx>
60 #include <comphelper/sequence.hxx>
61 #include <comphelper/diagnose_ex.hxx>
62 #include <tools/gen.hxx>
63 #include <tools/globname.hxx>
64 #include <tools/mapunit.hxx>
65 #include <editeng/unoprnms.hxx>
66 #include <com/sun/star/awt/FontSlant.hpp>
67 #include <com/sun/star/awt/Size.hpp>
68 #include <com/sun/star/awt/XBitmap.hpp>
69 #include <com/sun/star/awt/FontWeight.hpp>
70 #include <com/sun/star/graphic/XGraphic.hpp>
71 #include <com/sun/star/container/XNamed.hpp>
72 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
73 #include <com/sun/star/xml/dom/XDocument.hpp>
74 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
75 #include <com/sun/star/drawing/FillStyle.hpp>
76 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
77 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
78 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
79 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
80 #include <com/sun/star/drawing/XShapes.hpp>
81 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
82 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
83 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
84 #include <com/sun/star/drawing/ConnectorType.hpp>
85 #include <com/sun/star/embed/XEmbeddedObject.hpp>
86 #include <com/sun/star/text/XText.hpp>
87 #include <com/sun/star/table/BorderLine2.hpp>
88 #include <com/sun/star/table/ShadowFormat.hpp>
89 #include <com/sun/star/chart2/XChartDocument.hpp>
90 #include <com/sun/star/style/ParagraphAdjust.hpp>
91 #include <com/sun/star/io/XOutputStream.hpp>
92 #include <com/sun/star/lang/Locale.hpp>
93 #include <com/sun/star/i18n/ScriptType.hpp>
94 #include <com/sun/star/text/WritingMode2.hpp>
95 
96 #include <basegfx/point/b2dpoint.hxx>
97 #include <basegfx/polygon/b2dpolygon.hxx>
98 #include <basegfx/matrix/b2dhommatrix.hxx>
99 #include <com/sun/star/document/XActionLockable.hpp>
100 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
101 #include <officecfg/Office/Common.hxx>
102 #include <svx/svdobj.hxx>
103 #include <svx/svdotable.hxx>
104 #include <svx/svdtrans.hxx>
105 #include <tools/stream.hxx>
106 #include <unotools/streamwrap.hxx>
107 #include <unotools/mediadescriptor.hxx>
108 #include <vcl/graph.hxx>
109 #include <vcl/graphicfilter.hxx>
110 #include <vcl/svapp.hxx>
111 #include <vcl/wmfexternal.hxx>
112 #include <sal/log.hxx>
113 #include <svx/sdtaitm.hxx>
114 #include <oox/drawingml/diagram/diagram.hxx>
115 #include <docmodel/theme/Theme.hxx>
116 #include <i18nlangtag/languagetag.hxx>
117 #include <i18nlangtag/mslangid.hxx>
118 
119 using namespace ::oox::core;
120 using namespace ::com::sun::star;
121 using namespace ::com::sun::star::uno;
122 using namespace ::com::sun::star::beans;
123 using namespace ::com::sun::star::frame;
124 using namespace ::com::sun::star::text;
125 using namespace ::com::sun::star::drawing;
126 using namespace ::com::sun::star::style;
127 
128 namespace oox::drawingml {
129 
Shape()130 Shape::Shape()
131 : mpLinePropertiesPtr( std::make_shared<LineProperties>() )
132 , mpShapeRefLinePropPtr( std::make_shared<LineProperties>() )
133 , mpFillPropertiesPtr( std::make_shared<FillProperties>() )
134 , mpShapeRefFillPropPtr( std::make_shared<FillProperties>() )
135 , mpGraphicPropertiesPtr( std::make_shared<GraphicProperties>() )
136 , mpCustomShapePropertiesPtr( std::make_shared<CustomShapeProperties>() )
137 , mp3DPropertiesPtr( std::make_shared<Shape3DProperties>() )
138 , mpEffectPropertiesPtr( std::make_shared<EffectProperties>() )
139 , mpShapeRefEffectPropPtr( std::make_shared<EffectProperties>() )
140 , mpMasterTextListStyle( std::make_shared<TextListStyle>() )
141 , mnSubType( 0 )
142 , meFrameType( FRAMETYPE_GENERIC )
143 , mnRotation( 0 )
144 , mnDiagramRotation( 0 )
145 , mbFlipH( false )
146 , mbFlipV( false )
147 , mbHidden( false )
148 , mbHiddenMasterShape( false )
149 , mbLocked( false )
150 , mbWPGChild(false)
151 , mbLockedCanvas( false )
152 , mbWordprocessingCanvas(false)
153 , mbWps( false )
154 , mbTextBox( false )
155 , mbHasLinkedTxbx( false )
156 , mbHasCustomPrompt( false )
157 , maDiagramDoms( 0 )
158 , mpDiagramHelper( nullptr )
159 {
160     setDefaults(/*bDefaultHeight*/true);
161 }
162 
163 
Shape(const OUString & rServiceName,bool bDefaultHeight)164 Shape::Shape( const OUString& rServiceName, bool bDefaultHeight )
165 : mpLinePropertiesPtr( std::make_shared<LineProperties>() )
166 , mpShapeRefLinePropPtr( std::make_shared<LineProperties>() )
167 , mpFillPropertiesPtr( std::make_shared<FillProperties>() )
168 , mpShapeRefFillPropPtr( std::make_shared<FillProperties>() )
169 , mpGraphicPropertiesPtr( std::make_shared<GraphicProperties>() )
170 , mpCustomShapePropertiesPtr( std::make_shared<CustomShapeProperties>() )
171 , mp3DPropertiesPtr( std::make_shared<Shape3DProperties>() )
172 , mpEffectPropertiesPtr( std::make_shared<EffectProperties>() )
173 , mpShapeRefEffectPropPtr( std::make_shared<EffectProperties>() )
174 , mpMasterTextListStyle( std::make_shared<TextListStyle>() )
175 , mnSubType( 0 )
176 , meFrameType( FRAMETYPE_GENERIC )
177 , mnRotation( 0 )
178 , mnDiagramRotation( 0 )
179 , mbFlipH( false )
180 , mbFlipV( false )
181 , mbHidden( false )
182 , mbHiddenMasterShape( false )
183 , mbLocked( false )
184 , mbWPGChild(false)
185 , mbLockedCanvas( false )
186 , mbWordprocessingCanvas(false)
187 , mbWps( false )
188 , mbTextBox( false )
189 , mbHasLinkedTxbx( false )
190 , mbHasCustomPrompt( false )
191 , maDiagramDoms( 0 )
192 , mpDiagramHelper( nullptr )
193 {
194     msServiceName = rServiceName;
195     setDefaults(bDefaultHeight);
196 }
197 
Shape(const ShapePtr & pSourceShape)198 Shape::Shape( const ShapePtr& pSourceShape )
199 : mpTextBody(pSourceShape->mpTextBody)
200 , mpLinePropertiesPtr( pSourceShape->mpLinePropertiesPtr )
201 , mpShapeRefLinePropPtr( pSourceShape->mpShapeRefLinePropPtr )
202 , mpFillPropertiesPtr( pSourceShape->mpFillPropertiesPtr )
203 , mpShapeRefFillPropPtr( pSourceShape->mpShapeRefFillPropPtr )
204 , mpGraphicPropertiesPtr( pSourceShape->mpGraphicPropertiesPtr )
205 , mpCustomShapePropertiesPtr( pSourceShape->mpCustomShapePropertiesPtr )
206 , mpTablePropertiesPtr( pSourceShape->mpTablePropertiesPtr )
207 , mp3DPropertiesPtr( pSourceShape->mp3DPropertiesPtr )
208 , mpEffectPropertiesPtr (pSourceShape->mpEffectPropertiesPtr)
209 , mpShapeRefEffectPropPtr(pSourceShape->mpShapeRefEffectPropPtr)
210 , maShapeProperties( pSourceShape->maShapeProperties )
211 , mpMasterTextListStyle( pSourceShape->mpMasterTextListStyle )
212 , msServiceName( pSourceShape->msServiceName )
213 , msName( pSourceShape->msName )
214 , msInternalName( pSourceShape->msInternalName )
215 , msId( pSourceShape->msId )
216 , mnSubType( pSourceShape->mnSubType )
217 , moSubTypeIndex( pSourceShape->moSubTypeIndex )
218 , maShapeStyleRefs( pSourceShape->maShapeStyleRefs )
219 , maSize( pSourceShape->maSize )
220 , maPosition( pSourceShape->maPosition )
221 , meFrameType( pSourceShape->meFrameType )
222 , mnRotation( pSourceShape->mnRotation )
223 , mnDiagramRotation( pSourceShape->mnDiagramRotation )
224 , mbFlipH( pSourceShape->mbFlipH )
225 , mbFlipV( pSourceShape->mbFlipV )
226 , mbHidden( pSourceShape->mbHidden )
227 , mbHiddenMasterShape( pSourceShape->mbHiddenMasterShape )
228 , mbLocked( pSourceShape->mbLocked )
229 , mbWPGChild( pSourceShape->mbWPGChild )
230 , mbLockedCanvas( pSourceShape->mbLockedCanvas )
231 , mbWordprocessingCanvas(pSourceShape->mbWordprocessingCanvas)
232 , mbWps( pSourceShape->mbWps )
233 , mbTextBox( pSourceShape->mbTextBox )
234 , mbHasLinkedTxbx(false)
235 , mbHasCustomPrompt( pSourceShape->mbHasCustomPrompt )
236 , maDiagramDoms( pSourceShape->maDiagramDoms )
237 , mnZOrder(pSourceShape->mnZOrder)
238 , mnZOrderOff(pSourceShape->mnZOrderOff)
239 , mnDataNodeType(pSourceShape->mnDataNodeType)
240 , mfAspectRatio(pSourceShape->mfAspectRatio)
241 , mpDiagramHelper( nullptr )
242 , msDiagramDataModelID(pSourceShape->msDiagramDataModelID)
243 {}
244 
~Shape()245 Shape::~Shape()
246 {
247     // DiagramHelper should not be set here anymore, see
248     // propagateDiagramHelper below (maybe assert..?)
249     delete mpDiagramHelper;
250 }
251 
prepareDiagramHelper(const std::shared_ptr<Diagram> & rDiagramPtr,const std::shared_ptr<::oox::drawingml::Theme> & rTheme,bool bSelfCreated)252 void Shape::prepareDiagramHelper(
253     const std::shared_ptr< Diagram >& rDiagramPtr,
254     const std::shared_ptr<::oox::drawingml::Theme>& rTheme,
255     bool bSelfCreated)
256 {
257     // Prepare Diagram data collecting for this Shape
258     if( nullptr == mpDiagramHelper && FRAMETYPE_DIAGRAM == meFrameType )
259     {
260         mpDiagramHelper = new AdvancedDiagramHelper(
261             rDiagramPtr,
262             rTheme,
263             getSize(),
264             bSelfCreated);
265     }
266 }
267 
propagateDiagramHelper()268 void Shape::propagateDiagramHelper()
269 {
270     // Propagate collected Diagram data to data holder
271     if (FRAMETYPE_DIAGRAM == meFrameType && nullptr != mpDiagramHelper)
272     {
273         SdrObjGroup* pAnchorObj = dynamic_cast<SdrObjGroup*>(SdrObject::getSdrObjectFromXShape(mxShape));
274 
275         if(pAnchorObj)
276         {
277             mpDiagramHelper->doAnchor(*pAnchorObj, *this);
278             mpDiagramHelper = nullptr;
279         }
280     }
281 
282     // If propagation failed, delete/cleanup here. Since the DiagramHelper
283     // holds a Diagram and that this Shape it is necessary - the destructor
284     // will not be called and will be too late
285     if (nullptr != mpDiagramHelper)
286     {
287         delete mpDiagramHelper;
288         mpDiagramHelper = nullptr;
289     }
290 }
291 
migrateDiagramHelperToNewShape(const ShapePtr & pTarget)292 void Shape::migrateDiagramHelperToNewShape(const ShapePtr& pTarget)
293 {
294     if(!mpDiagramHelper)
295     {
296         return;
297     }
298 
299     if(!pTarget)
300     {
301         // no migrate target, but cleanup helper
302         delete mpDiagramHelper;
303         mpDiagramHelper = nullptr;
304         return;
305     }
306 
307     if(pTarget->mpDiagramHelper)
308     {
309         // this should no happen, but if there is already a helper, clean it up
310         delete pTarget->mpDiagramHelper;
311         pTarget->mpDiagramHelper = nullptr;
312     }
313 
314     // exchange and reset to nullptr
315     pTarget->mpDiagramHelper = mpDiagramHelper;
316     mpDiagramHelper = nullptr;
317 }
318 
getTableProperties()319 table::TablePropertiesPtr const & Shape::getTableProperties()
320 {
321     if ( !mpTablePropertiesPtr )
322         mpTablePropertiesPtr = std::make_shared<table::TableProperties>();
323     return mpTablePropertiesPtr;
324 }
325 
setDefaults(bool bHeight)326 void Shape::setDefaults(bool bHeight)
327 {
328     maDefaultShapeProperties.setProperty(PROP_TextAutoGrowHeight, false);
329     maDefaultShapeProperties.setProperty(PROP_TextWordWrap, true);
330     maDefaultShapeProperties.setProperty(PROP_TextLeftDistance, static_cast< sal_Int32 >( 250 ));
331     maDefaultShapeProperties.setProperty(PROP_TextUpperDistance, static_cast< sal_Int32 >( 125 ));
332     maDefaultShapeProperties.setProperty(PROP_TextRightDistance, static_cast< sal_Int32 >( 250 ));
333     maDefaultShapeProperties.setProperty(PROP_TextLowerDistance, static_cast< sal_Int32 >( 125 ));
334     if (bHeight)
335         maDefaultShapeProperties.setProperty(PROP_CharHeight, static_cast< float >( 18.0 ));
336     maDefaultShapeProperties.setProperty(PROP_TextVerticalAdjust, TextVerticalAdjust_TOP);
337     maDefaultShapeProperties.setProperty(PROP_ParaAdjust,
338                                          static_cast<sal_Int16>(ParagraphAdjust_LEFT));
339 }
340 
setOleObjectType()341 ::oox::vml::OleObjectInfo& Shape::setOleObjectType()
342 {
343     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setOleObjectType - multiple frame types" );
344     meFrameType = FRAMETYPE_OLEOBJECT;
345     mxOleObjectInfo = std::make_shared<::oox::vml::OleObjectInfo>( true );
346     return *mxOleObjectInfo;
347 }
348 
setChartType(bool bEmbedShapes)349 ChartShapeInfo& Shape::setChartType( bool bEmbedShapes )
350 {
351     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setChartType - multiple frame types" );
352     meFrameType = FRAMETYPE_CHART;
353     if (mbWps)
354         msServiceName = u"com.sun.star.drawing.temporaryForXMLImportOLE2Shape"_ustr;
355     else
356         msServiceName = u"com.sun.star.drawing.OLE2Shape"_ustr;
357     mxChartShapeInfo = std::make_shared<ChartShapeInfo>( bEmbedShapes );
358     return *mxChartShapeInfo;
359 }
360 
setDiagramType()361 void Shape::setDiagramType()
362 {
363     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setDiagramType - multiple frame types" );
364     meFrameType = FRAMETYPE_DIAGRAM;
365     msServiceName = u"com.sun.star.drawing.GroupShape"_ustr;
366     mnSubType = 0;
367 }
368 
setTableType()369 void Shape::setTableType()
370 {
371     OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setTableType - multiple frame types" );
372     meFrameType = FRAMETYPE_TABLE;
373     msServiceName = u"com.sun.star.drawing.TableShape"_ustr;
374     mnSubType = 0;
375 }
376 
getShapeStyleRef(sal_Int32 nRefType) const377 const ShapeStyleRef* Shape::getShapeStyleRef( sal_Int32 nRefType ) const
378 {
379     ShapeStyleRefMap::const_iterator aIt = maShapeStyleRefs.find( nRefType );
380     return (aIt == maShapeStyleRefs.end()) ? nullptr : &aIt->second;
381 }
382 
addShape(::oox::core::XmlFilterBase & rFilterBase,const Theme * pTheme,const Reference<XShapes> & rxShapes,const basegfx::B2DHomMatrix & aTransformation,const FillProperties & rShapeOrParentShapeFillProps,ShapeIdMap * pShapeMap,const oox::drawingml::ShapePtr & pParentGroupShape)383 void Shape::addShape(
384         ::oox::core::XmlFilterBase& rFilterBase,
385         const Theme* pTheme,
386         const Reference< XShapes >& rxShapes,
387         const basegfx::B2DHomMatrix& aTransformation,
388         const FillProperties& rShapeOrParentShapeFillProps,
389         ShapeIdMap* pShapeMap,
390         const oox::drawingml::ShapePtr& pParentGroupShape)
391 {
392     SAL_INFO("oox.drawingml", "Shape::addShape: id='" << msId << "'");
393 
394     try
395     {
396         OUString sServiceName( msServiceName );
397         if( !sServiceName.isEmpty() )
398         {
399             basegfx::B2DHomMatrix aMatrix( aTransformation );
400             Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, false, nullptr, aMatrix, rShapeOrParentShapeFillProps, pParentGroupShape) );
401 
402             if( pShapeMap && !msId.isEmpty() )
403             {
404                 (*pShapeMap)[ msId ] = shared_from_this();
405             }
406 
407             // if this is a group shape, we have to add also each child shape
408             Reference< XShapes > xShapes( xShape, UNO_QUERY );
409             if ( xShapes.is() )
410                 addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aMatrix );
411 
412             if (mbWordprocessingCanvas && !mbWPGChild)
413             {
414                 // This is a drawing canvas. In case the canvas has no fill and no stroke, Word does
415                 // not render shadow or glow, even if it is set for the canvas. Thus we disable shadow
416                 // and glow in this case for the ersatz background shape of the drawing canvas.
417                 try
418                 {
419                     oox::drawingml::ShapePtr pBgShape = getChildren().front();
420                     const Reference<css::drawing::XShape>& xBgShape = pBgShape->getXShape();
421                     Reference<XPropertySet> xBgProps(xBgShape, uno::UNO_QUERY);
422                     drawing::FillStyle eFillStyle = drawing::FillStyle_NONE;
423                     xBgProps->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle;
424                     drawing::LineStyle eLineStyle = drawing::LineStyle_NONE;
425                     xBgProps->getPropertyValue(u"LineStyle"_ustr) >>= eLineStyle;
426                     if (eFillStyle == drawing::FillStyle_NONE
427                         && eLineStyle == drawing::LineStyle_NONE)
428                     {
429                         xBgProps->setPropertyValue(UNO_NAME_SHADOW, uno::Any(false));
430                         xBgProps->setPropertyValue(u"GlowEffectRadius"_ustr, uno::Any(sal_Int32(0)));
431                     }
432                 }
433                 catch (const Exception&)
434                 {
435                     TOOLS_WARN_EXCEPTION("oox.drawingml", "Shape::addShape mbWordprocessingCanvas");
436                 }
437             }
438 
439             if (isWPGChild() && xShape)
440             {
441                 // This is a wps shape and it is the child of the WPG, now copy the
442                 // the text body properties to the xshape.
443                 Reference<XPropertySet> xChildWPSProperties(xShape, uno::UNO_QUERY);
444 
445                 if (getTextBody() && xChildWPSProperties)
446                 {
447                     xChildWPSProperties->setPropertyValue(
448                         UNO_NAME_TEXT_VERTADJUST,
449                         uno::Any(getTextBody()->getTextProperties().meVA));
450 
451                     xChildWPSProperties->setPropertyValue(
452                         UNO_NAME_TEXT_LEFTDIST,
453                         uno::Any(getTextBody()->getTextProperties().moInsets[0].has_value()
454                                      ? *getTextBody()->getTextProperties().moInsets[0]
455                                      : 0));
456                     xChildWPSProperties->setPropertyValue(
457                         UNO_NAME_TEXT_UPPERDIST,
458                         uno::Any(getTextBody()->getTextProperties().moInsets[1].has_value()
459                                      ? *getTextBody()->getTextProperties().moInsets[1]
460                                      : 0));
461                     xChildWPSProperties->setPropertyValue(
462                         UNO_NAME_TEXT_RIGHTDIST,
463                         uno::Any(getTextBody()->getTextProperties().moInsets[2].has_value()
464                                      ? *getTextBody()->getTextProperties().moInsets[2]
465                                      : 0));
466                     xChildWPSProperties->setPropertyValue(
467                         UNO_NAME_TEXT_LOWERDIST,
468                         uno::Any(getTextBody()->getTextProperties().moInsets[3].has_value()
469                                      ? *getTextBody()->getTextProperties().moInsets[3]
470                                      : 0));
471                 }
472 
473                 // tdf#145147 Set the Hyperlink property to the child wps shape.
474                 if (getShapeProperties().hasProperty(PROP_URL)) try
475                 {
476                     uno::Any aAny = getShapeProperties().getProperty(PROP_URL);
477                     OUString sUrl = aAny.get<OUString>();
478                     if (!sUrl.isEmpty())
479                         xChildWPSProperties->setPropertyValue(UNO_NAME_HYPERLINK, aAny);
480                 }
481                 catch (const Exception&)
482                 {
483                 }
484             }
485 
486             if( meFrameType == FRAMETYPE_DIAGRAM )
487             {
488                 keepDiagramCompatibilityInfo();
489 
490                 // set DiagramHelper at SdrObjGroup
491                 propagateDiagramHelper();
492 
493                 // Check if this is the PPTX import, so far converting SmartArt to a non-editable
494                 // metafile is only implemented for DOCX.
495                 bool bPowerPoint = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilterBase) != nullptr;
496 
497                 if (!officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::get() && !bPowerPoint)
498                     convertSmartArtToMetafile( rFilterBase );
499             }
500 
501             NamedShapePairs* pNamedShapePairs = rFilterBase.getDiagramFontHeights();
502             if (xShape.is() && pNamedShapePairs)
503             {
504                 auto itPairs = pNamedShapePairs->find(getInternalName());
505                 if (itPairs != pNamedShapePairs->end())
506                 {
507                     auto it = itPairs->second.find(shared_from_this());
508                     if (it != itPairs->second.end())
509                     {
510                         // Our drawingml::Shape is in the list of an internal name, remember the now
511                         // inserted XShape.
512                         it->second = std::move(xShape);
513                     }
514                 }
515             }
516         }
517     }
518     catch( const Exception& )
519     {
520         TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::addShape" );
521     }
522 }
523 
setLockedCanvas(bool bLockedCanvas)524 void Shape::setLockedCanvas(bool bLockedCanvas)
525 {
526     mbLockedCanvas = bLockedCanvas;
527 }
528 
setWordprocessingCanvas(bool bWordprocessingCanvas)529 void Shape::setWordprocessingCanvas(bool bWordprocessingCanvas)
530 {
531     mbWordprocessingCanvas = bWordprocessingCanvas;
532 }
533 
setWPGChild(bool bWPG)534 void Shape::setWPGChild(bool bWPG)
535 {
536     mbWPGChild = bWPG;
537 }
538 
setWps(bool bWps)539 void Shape::setWps(bool bWps)
540 {
541     mbWps = bWps;
542 }
543 
setTextBox(bool bTextBox)544 void Shape::setTextBox(bool bTextBox)
545 {
546     mbTextBox = bTextBox;
547 }
548 
applyShapeReference(const Shape & rReferencedShape,bool bUseText)549 void Shape::applyShapeReference( const Shape& rReferencedShape, bool bUseText )
550 {
551     SAL_INFO("oox.drawingml", "Shape::applyShapeReference: apply '" << rReferencedShape.msId << "' to '" << msId << "'");
552 
553     if ( rReferencedShape.mpTextBody && bUseText )
554         mpTextBody = std::make_shared<TextBody>( *rReferencedShape.mpTextBody );
555     else
556         mpTextBody.reset();
557     maShapeProperties = rReferencedShape.maShapeProperties;
558     mpShapeRefLinePropPtr = std::make_shared<LineProperties>( rReferencedShape.getActualLineProperties(nullptr) );
559     mpShapeRefFillPropPtr = std::make_shared<FillProperties>( rReferencedShape.getActualFillProperties(nullptr, nullptr) );
560     mpCustomShapePropertiesPtr = std::make_shared<CustomShapeProperties>( *rReferencedShape.mpCustomShapePropertiesPtr );
561     mpTablePropertiesPtr = rReferencedShape.mpTablePropertiesPtr ? std::make_shared<table::TableProperties>( *rReferencedShape.mpTablePropertiesPtr ) : nullptr;
562     mpShapeRefEffectPropPtr = std::make_shared<EffectProperties>( rReferencedShape.getActualEffectProperties(nullptr) );
563     mpMasterTextListStyle = std::make_shared<TextListStyle>( *rReferencedShape.mpMasterTextListStyle );
564     maSize = rReferencedShape.maSize;
565     maPosition = rReferencedShape.maPosition;
566     mnRotation = rReferencedShape.mnRotation;
567     mbFlipH = rReferencedShape.mbFlipH;
568     mbFlipV = rReferencedShape.mbFlipV;
569     mbHidden = rReferencedShape.mbHidden;
570     mbLocked = rReferencedShape.mbLocked;
571 }
572 
573 namespace {
574 
575 struct ActionLockGuard
576 {
ActionLockGuardoox::drawingml::__anon3a6e14a00111::ActionLockGuard577     explicit ActionLockGuard(Reference<drawing::XShape> const& xShape)
578         : m_xLockable(xShape, UNO_QUERY)
579     {
580         if (m_xLockable.is()) {
581             m_xLockable->addActionLock();
582         }
583     }
~ActionLockGuardoox::drawingml::__anon3a6e14a00111::ActionLockGuard584     ~ActionLockGuard()
585     {
586         if (m_xLockable.is()) {
587             m_xLockable->removeActionLock();
588         }
589     }
590 private:
591     Reference<document::XActionLockable> m_xLockable;
592 };
593 
594 }
595 
596 // 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)597 void Shape::addChildren(
598         XmlFilterBase& rFilterBase,
599         Shape& rMaster,
600         const Theme* pTheme,
601         const Reference< XShapes >& rxShapes,
602         ShapeIdMap* pShapeMap,
603         const basegfx::B2DHomMatrix& aTransformation )
604 {
605     for (auto const& child : rMaster.maChildren)
606     {
607         child->setMasterTextListStyle( mpMasterTextListStyle );
608         child->addShape( rFilterBase, pTheme, rxShapes, aTransformation, getFillProperties(), pShapeMap, rMaster.shared_from_this());
609     }
610 }
611 
lcl_convertAdjust(ParagraphAdjust eAdjust)612 static SdrTextHorzAdjust lcl_convertAdjust( ParagraphAdjust eAdjust )
613 {
614     if (eAdjust == ParagraphAdjust_LEFT)
615         return SDRTEXTHORZADJUST_LEFT;
616     else if (eAdjust == ParagraphAdjust_RIGHT)
617         return SDRTEXTHORZADJUST_RIGHT;
618     else if (eAdjust == ParagraphAdjust_CENTER)
619         return SDRTEXTHORZADJUST_CENTER;
620     return SDRTEXTHORZADJUST_LEFT;
621 }
622 
lcl_convertTextAdjust(ParagraphAdjust eAdjust)623 static TextHorizontalAdjust lcl_convertTextAdjust(ParagraphAdjust eAdjust)
624 {
625     if (eAdjust == ParagraphAdjust_LEFT)
626         return drawing::TextHorizontalAdjust_LEFT;
627     else if (eAdjust == ParagraphAdjust_RIGHT)
628         return drawing::TextHorizontalAdjust_RIGHT;
629     else
630         return drawing::TextHorizontalAdjust_BLOCK;
631 }
632 
633 // LO does not interpret properties in styles belonging to the text content of a FontWork shape,
634 // but only those in the shape style. This method copies properties from the text content styles to
635 // the shape style.
lcl_copyCharPropsToShape(const uno::Reference<drawing::XShape> & xShape,const TextBodyPtr & pTextBody,const::oox::core::XmlFilterBase & rFilter)636 static void lcl_copyCharPropsToShape(const uno::Reference<drawing::XShape>& xShape,
637                                      const TextBodyPtr& pTextBody,
638                                      const ::oox::core::XmlFilterBase& rFilter)
639 {
640     if (!xShape.is() || !pTextBody)
641         return;
642 
643     Reference<XPropertySet> xSet(xShape, UNO_QUERY);
644     if (!xSet.is())
645         return;
646 
647     // Content stretches or scales to given width and height, thus disable autogrow.
648     xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::Any(false));
649     xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::Any(false));
650 
651     // LibreOffice is not able (as of Nov 2022) to use different styles for the paragraphs or
652     // characters in FontWork, since that was not allowed in old binary WordArt. We use the
653     // properties of the first non empty paragraph for now.
654     const TextParagraphVector& rParagraphs = pTextBody->getParagraphs();
655     auto aParaIt = std::find_if_not(rParagraphs.cbegin(), rParagraphs.cend(),
656                                     [](const std::shared_ptr<TextParagraph> pParagraph) {
657                                         return pParagraph->getRuns().empty();
658                                     });
659     if (aParaIt != rParagraphs.cend())
660     {
661         const std::shared_ptr<TextParagraph>& pParagraph = *aParaIt;
662         const TextRunVector& rRuns = pParagraph->getRuns();
663         auto aRunIt = std::find_if_not(rRuns.cbegin(), rRuns.cend(),
664                                        [](const std::shared_ptr<TextRun> pRun)
665                                        {
666                                            return pRun->getText().isEmpty()
667                                                   || pRun->getText() == " "
668                                                   || pRun->getText().toChar() == 0xA0; // NBSP
669                                        });
670         if (aRunIt != rRuns.cend())
671         {
672             const std::shared_ptr<TextRun>& pRun = *aRunIt;
673             TextCharacterProperties& rCharProps = pRun->getTextCharacterProperties();
674 
675             // set language
676             if (rCharProps.moLang.has_value() && !rCharProps.moLang.value().isEmpty())
677             {
678                 LanguageTag aTag(rCharProps.moLang.value());
679                 const css::lang::Locale& aLocale(aTag.getLocale(false));
680                 switch (MsLangId::getScriptType(aTag.getLanguageType()))
681                 {
682                     case css::i18n::ScriptType::LATIN:
683                         xSet->setPropertyValue(u"CharLocale"_ustr, uno::Any(aLocale));
684                         break;
685                     case css::i18n::ScriptType::ASIAN:
686                         xSet->setPropertyValue(u"CharLocaleAsian"_ustr, uno::Any(aLocale));
687                         break;
688                     case css::i18n::ScriptType::COMPLEX:
689                         xSet->setPropertyValue(u"CharLocaleComplex"_ustr, uno::Any(aLocale));
690                         break;
691                     default:;
692                 }
693             }
694 
695             // Font Weight, Posture, Height
696             if (rCharProps.moBold.has_value() && rCharProps.moBold.value())
697             {
698                 xSet->setPropertyValue(UNO_NAME_CHAR_WEIGHT, uno::Any(css::awt::FontWeight::BOLD));
699             }
700             if (rCharProps.moItalic.has_value() && rCharProps.moItalic.value())
701             {
702                 xSet->setPropertyValue(UNO_NAME_CHAR_POSTURE,
703                                        uno::Any(css::awt::FontSlant::FontSlant_ITALIC));
704             }
705             if (rCharProps.moHeight.has_value())
706             {
707                 sal_Int32 nHeight = rCharProps.moHeight.value() / 100;
708                 xSet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::Any(nHeight));
709             }
710 
711             // Put theme fonts into shape properties
712             OUString sFontName;
713             sal_Int16 nFontPitch = 0;
714             sal_Int16 nFontFamily = 0;
715             bool bRet(false);
716             if (const Theme* pTheme = rFilter.getCurrentTheme())
717             {
718                 // minor Latin
719                 if (const TextFont* pFont = pTheme->resolveFont(u"+mn-lt"))
720                 {
721                     bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
722                     if (bRet)
723                     {
724                         xSet->setPropertyValue(u"CharFontName"_ustr, uno::Any(sFontName));
725                         xSet->setPropertyValue(u"CharFontPitch"_ustr, uno::Any(nFontPitch));
726                         xSet->setPropertyValue(u"CharFontFamily"_ustr, uno::Any(nFontFamily));
727                     }
728                 }
729                 // minor Asian
730                 if (const TextFont* pFont = pTheme->resolveFont(u"+mn-ea"))
731                 {
732                     bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
733                     if (bRet)
734                     {
735                         xSet->setPropertyValue(u"CharFontNameAsian"_ustr, uno::Any(sFontName));
736                         xSet->setPropertyValue(u"CharFontPitchAsian"_ustr, uno::Any(nFontPitch));
737                         xSet->setPropertyValue(u"CharFontFamilyAsian"_ustr, uno::Any(nFontFamily));
738                     }
739                 }
740                 // minor Complex
741                 if (const TextFont* pFont = pTheme->resolveFont(u"+mn-cs"))
742                 {
743                     bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
744                     if (bRet)
745                     {
746                         xSet->setPropertyValue(u"CharFontNameComplex"_ustr, uno::Any(sFontName));
747                         xSet->setPropertyValue(u"CharFontPitchComplex"_ustr, uno::Any(nFontPitch));
748                         xSet->setPropertyValue(u"CharFontFamilyComplex"_ustr, uno::Any(nFontFamily));
749                     }
750                 }
751             }
752 
753             // Replace theme fonts with formatting at run if any. ToDo: Inspect paragraph too?
754             // Latin
755             bRet = rCharProps.maLatinFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
756             if (!bRet)
757                 // In case there is no direct font, try to look it up as a theme reference.
758                 bRet = rCharProps.maLatinThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
759                                                                rFilter);
760 
761             if (bRet)
762             {
763                 xSet->setPropertyValue(u"CharFontName"_ustr, uno::Any(sFontName));
764                 xSet->setPropertyValue(u"CharFontPitch"_ustr, uno::Any(nFontPitch));
765                 xSet->setPropertyValue(u"CharFontFamily"_ustr, uno::Any(nFontFamily));
766             }
767             // Asian
768             bRet = rCharProps.maAsianFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
769             if (!bRet)
770                 // In case there is no direct font, try to look it up as a theme reference.
771                 bRet = rCharProps.maAsianThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
772                                                                rFilter);
773             if (bRet)
774             {
775                 xSet->setPropertyValue(u"CharFontNameAsian"_ustr, uno::Any(sFontName));
776                 xSet->setPropertyValue(u"CharFontPitchAsian"_ustr, uno::Any(nFontPitch));
777                 xSet->setPropertyValue(u"CharFontFamilyAsian"_ustr, uno::Any(nFontFamily));
778             }
779             // Complex
780             bRet
781                 = rCharProps.maComplexFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
782             if (!bRet)
783                 // In case there is no direct font, try to look it up as a theme reference.
784                 bRet = rCharProps.maComplexThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
785                                                                  rFilter);
786             if (bRet)
787             {
788                 xSet->setPropertyValue(u"CharFontNameComplex"_ustr, uno::Any(sFontName));
789                 xSet->setPropertyValue(u"CharFontPitchComplex"_ustr, uno::Any(nFontPitch));
790                 xSet->setPropertyValue(u"CharFontFamilyComplex"_ustr, uno::Any(nFontFamily));
791             }
792 
793             // LO uses shape properties, MS Office character properties. Copy them from char to shape.
794             // Outline
795             if (rCharProps.moTextOutlineProperties.has_value())
796             {
797                 oox::drawingml::ShapePropertyMap aStrokeShapeProps(rFilter.getModelObjectHelper());
798                 rCharProps.moTextOutlineProperties.value().pushToPropMap(
799                     aStrokeShapeProps, rFilter.getGraphicHelper());
800                 for (const auto& rProp : aStrokeShapeProps.makePropertyValueSequence())
801                 {
802                     xSet->setPropertyValue(rProp.Name, rProp.Value);
803                 }
804             }
805             else
806             {
807                 xSet->setPropertyValue(UNO_NAME_LINESTYLE, uno::Any(drawing::LineStyle_NONE));
808             }
809 
810             // Fill
811             // ToDo: Replace flip and rotate constants in parameters with actual values.
812             // tdf#155327 If color is not explicitly set, MS Office uses scheme color 'tx1'.
813             oox::drawingml::ShapePropertyMap aFillShapeProps(rFilter.getModelObjectHelper());
814             if (!rCharProps.maFillProperties.moFillType.has_value())
815                 rCharProps.maFillProperties.moFillType = XML_solidFill;
816             if (!rCharProps.maFillProperties.maFillColor.isUsed())
817                 rCharProps.maFillProperties.maFillColor.setSchemeClr(XML_tx1);
818             rCharProps.maFillProperties.pushToPropMap(aFillShapeProps, rFilter.getGraphicHelper(),
819                                                       /*nShapeRotation*/ 0,
820                                                       /*nPhClr*/ API_RGB_TRANSPARENT,
821                                                       /*aShapeSize*/ css::awt::Size(0, 0),
822                                                       /*nPhClrTheme*/ -1,
823                                                       /*bFlipH*/ false, /*bFlipV*/ false,
824                                                       /*bIsCustomShape*/ true);
825             for (const auto& rProp : aFillShapeProps.makePropertyValueSequence())
826             {
827                 xSet->setPropertyValue(rProp.Name, rProp.Value);
828             }
829 
830             // ToDo: Import WordArt glow and simple shadow effects. They are available in LO.
831         }
832 
833         // LO does not evaluate paragraph alignment in text path mode. Use text area anchor instead.
834         {
835             ParagraphAdjust eAdjust = ParagraphAdjust_LEFT;
836             if (pParagraph->getProperties().getParaAdjust())
837                 eAdjust = *pParagraph->getProperties().getParaAdjust();
838             xSet->setPropertyValue(u"ParaAdjust"_ustr, uno::Any(eAdjust));
839             SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
840             assert(pShape);
841             SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust(eAdjust);
842             pShape->SetMergedItem(SdrTextHorzAdjustItem(eHorzAdjust));
843         }
844     }
845 
846     // Vertical adjustment is only meaningful for OOXML WordArt shapes of 'Follow Path' kinds. We set
847     // it so, that text position is approximately same as in MS Office.
848     const OUString sMSPresetType = pTextBody->getTextProperties().msPrst;
849     const OUString sFontworkType = PresetGeometryTypeNames::GetFontworkType(sMSPresetType);
850     SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
851     assert(pShape);
852     if (sFontworkType == "fontwork-arch-up-curve" || sFontworkType == "fontwork-circle-curve")
853         pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM));
854     else if (sFontworkType == "fontwork-arch-down-curve")
855         pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP));
856     else
857         pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_CENTER));
858 }
859 
860 // Some helper methods for createAndInsert
861 namespace
862 {
863 // mirrors aTransformation at its center axis
864 // only valid if neither rotation or shear included
lcl_mirrorAtCenter(basegfx::B2DHomMatrix & aTransformation,bool bFlipH,bool bFlipV)865 void lcl_mirrorAtCenter(basegfx::B2DHomMatrix& aTransformation, bool bFlipH, bool bFlipV)
866 {
867     if (!bFlipH && !bFlipV)
868         return;
869     basegfx::B2DPoint aCenter(0.5, 0.5);
870     aCenter *= aTransformation;
871     aTransformation.translate(-aCenter);
872     aTransformation.scale(bFlipH ? -1.0 : 1.0, bFlipV ? -1.0 : 1.0);
873     aTransformation.translate(aCenter);
874     return;
875 }
876 
877 // only valid if neither rotation or shear included
lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix & aTransformation)878 void lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix& aTransformation)
879 {
880     // The values are directly set at the matrix without any matrix multiplication.
881     // That way it is valid for lines too. Those have zero width or height.
882     const double fSx(aTransformation.get(0, 0));
883     const double fSy(aTransformation.get(1, 1));
884     const double fTx(aTransformation.get(0, 2));
885     const double fTy(aTransformation.get(1, 2));
886     aTransformation.set(0, 0, fSy);
887     aTransformation.set(1, 1, fSx);
888     aTransformation.set(0, 2, fTx + 0.5 * (fSx - fSy));
889     aTransformation.set(1, 2, fTy + 0.5 * (fSy - fSx));
890     return;
891 }
892 
lcl_RotateAtCenter(basegfx::B2DHomMatrix & aTransformation,sal_Int32 nMSORotationAngle)893 void lcl_RotateAtCenter(basegfx::B2DHomMatrix& aTransformation, sal_Int32 nMSORotationAngle)
894 {
895     if (nMSORotationAngle == 0)
896         return;
897     double fRad = basegfx::deg2rad<60000>(nMSORotationAngle);
898     basegfx::B2DPoint aCenter(0.5, 0.5);
899     aCenter *= aTransformation;
900     aTransformation.translate(-aCenter);
901     aTransformation.rotate(fRad);
902     aTransformation.translate(aCenter);
903     return;
904 }
905 
lcl_MSORotateAngleToAPIAngle(const sal_Int32 nMSORotationAngle)906 Degree100 lcl_MSORotateAngleToAPIAngle(const sal_Int32 nMSORotationAngle)
907 {
908     // Converts a shape rotation angle from MSO to angle for API property RotateAngle
909     // from unit 1/60000 deg to unit 1/100 deg
910     Degree100 nAngle(nMSORotationAngle / 600);
911     // API RotateAngle has opposite direction than nMSORotationAngle, thus 'minus'.
912     return NormAngle36000(-nAngle);
913 }
914 }
915 
createAndInsert(::oox::core::XmlFilterBase & rFilterBase,const OUString & rServiceName,const Theme * pTheme,const css::uno::Reference<css::drawing::XShapes> & rxShapes,bool bClearText,const oox::drawingml::ShapePtr & pPlaceholder,basegfx::B2DHomMatrix & aParentTransformation,const FillProperties & rShapeOrParentShapeFillProps,const oox::drawingml::ShapePtr & pParentGroupShape)916 Reference< XShape > const & Shape::createAndInsert(
917         ::oox::core::XmlFilterBase& rFilterBase,
918         const OUString& rServiceName,
919         const Theme* pTheme,
920         const css::uno::Reference< css::drawing::XShapes >& rxShapes,
921         bool bClearText,
922         const oox::drawingml::ShapePtr& pPlaceholder,
923         basegfx::B2DHomMatrix& aParentTransformation,
924         const FillProperties& rShapeOrParentShapeFillProps,
925         const oox::drawingml::ShapePtr& pParentGroupShape)
926 {
927     bool bIsEmbMedia = false;
928     SAL_INFO("oox.drawingml", "Shape::createAndInsert: id='" << msId << "' service='" << rServiceName << "'");
929 
930     formulaimport::XmlStreamBuilder * pMathXml(nullptr);
931     if (mpTextBody)
932     {
933         for (auto const& it : mpTextBody->getParagraphs())
934         {
935             if (it->HasMathXml())
936             {
937                 if (!mpTextBody->isEmpty() || pMathXml != nullptr)
938                 {
939                     SAL_WARN("oox.drawingml", "losing a Math object...");
940                 }
941                 else
942                 {
943                     pMathXml = &it->GetMathXml();
944                 }
945             }
946         }
947     }
948 
949     // tdf#90403 PowerPoint ignores a:ext cx and cy values of p:xfrm, and uses real table width and height
950     if ( mpTablePropertiesPtr && rServiceName == "com.sun.star.drawing.TableShape" )
951     {
952         maSize.Width = 0;
953         for (auto const& elem : mpTablePropertiesPtr->getTableGrid())
954         {
955             maSize.Width = o3tl::saturating_add(maSize.Width, static_cast<sal_Int32>(elem));
956         }
957         maSize.Height = 0;
958         for (auto const& elem : mpTablePropertiesPtr->getTableRows())
959         {
960             // WARN: If some rows can't fit the content, this is not the final height
961             maSize.Height = o3tl::saturating_add(maSize.Height, elem.getHeight());
962         }
963     }
964 
965     awt::Rectangle aShapeRectHmm(
966         o3tl::convert(maPosition.X, o3tl::Length::emu, o3tl::Length::mm100),
967         o3tl::convert(maPosition.Y, o3tl::Length::emu, o3tl::Length::mm100),
968         o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100),
969         o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100));
970 
971     OUString aServiceName;
972     if (pMathXml)
973     {
974         // convert this shape to OLE
975         aServiceName = u"com.sun.star.drawing.OLE2Shape"_ustr;
976         msServiceName = aServiceName;
977         meFrameType = FRAMETYPE_GENERIC; // not OLEOBJECT, no stream in package
978         mnSubType = 0;
979     }
980     else if (rServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
981         mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->m_sMediaPackageURL.isEmpty())
982     {
983         aServiceName = finalizeServiceName( rFilterBase, u"com.sun.star.presentation.MediaShape"_ustr, aShapeRectHmm );
984         bIsEmbMedia = true;
985     }
986     else
987     {
988         aServiceName = finalizeServiceName( rFilterBase, rServiceName, aShapeRectHmm );
989     }
990     // Use custom shape instead of GraphicObjectShape if the image is cropped to
991     // shape. Except rectangle, which does not require further cropping
992     bool bIsCroppedGraphic = (aServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
993                               !mpCustomShapePropertiesPtr->representsDefaultShape());
994 
995     bool bIsCustomShape = (aServiceName == "com.sun.star.drawing.CustomShape" || bIsCroppedGraphic);
996     bool bIsConnectorShape = (aServiceName == "com.sun.star.drawing.ConnectorShape");
997 
998     // Look for 3D. Its z-rotation and extrusion color become shape properties. We consider a
999     // z-rotation of an image even we currently do not extrude an image to 3D-scene.
1000     bool bBlockExtrusion = !bIsCustomShape && mp3DPropertiesPtr->mnPreset.has_value();
1001     double fShapeRotateInclCamera = 0.0; // unit rad; same orientation as shape property RotateAngle
1002     Color aExtrusionColor;
1003     Scene3DHelper aScene3DHelper;
1004     bool bHas3DEffect = aScene3DHelper.setExtrusionProperties(
1005         mp3DPropertiesPtr, mnRotation, getCustomShapeProperties()->getExtrusionPropertyMap(),
1006         fShapeRotateInclCamera, aExtrusionColor, bBlockExtrusion);
1007     // Currently the other places use unit 1/60000deg and MSO shape rotate orientation.
1008     sal_Int32 nShapeRotateInclCamera = -basegfx::rad2deg<60000>(fShapeRotateInclCamera);
1009     bool bIs3DGraphic = aServiceName == "com.sun.star.drawing.GraphicObjectShape" && bHas3DEffect;
1010     bIsCustomShape |= bIs3DGraphic;
1011 
1012     // The extrusion color does not belong to the extrusion properties but is secondary color in
1013     // the style of the shape, FillColor2 in API. The case that no extrusion color was set is handled
1014     // further down when FillProperties and LineProperties are handled.
1015     if (aExtrusionColor.isUsed())
1016     {
1017         // FillColor2 is not yet transformed to ComplexColor.
1018         ::Color aColor = aExtrusionColor.getColor(rFilterBase.getGraphicHelper());
1019         maShapeProperties.setProperty(PROP_FillColor2, aColor);
1020     }
1021 
1022     if (bHas3DEffect)
1023     {
1024         aScene3DHelper.setLightingProperties(mp3DPropertiesPtr, fShapeRotateInclCamera,
1025                                              getCustomShapeProperties()->getExtrusionPropertyMap());
1026         oox::Scene3DHelper::setMaterialProperties(
1027             mp3DPropertiesPtr, getCustomShapeProperties()->getExtrusionPropertyMap());
1028     }
1029 
1030     if (bIsCroppedGraphic || bIs3DGraphic)
1031     {
1032         aServiceName = "com.sun.star.drawing.CustomShape";
1033         mpGraphicPropertiesPtr->mbIsCustomShape = true;
1034         mpGraphicPropertiesPtr->mbIsExtruded = bIs3DGraphic;
1035     }
1036     bool bUseRotationTransform = ( !mbWps ||
1037             aServiceName == "com.sun.star.drawing.LineShape" ||
1038             aServiceName == "com.sun.star.drawing.GroupShape" ||
1039             mbFlipH ||
1040             mbFlipV );
1041 
1042     basegfx::B2DHomMatrix aTransformation; // will be cumulative transformation of this object
1043 
1044     // Special for SmartArt import. Rotate diagram's shape around object's center before sizing.
1045     if (bUseRotationTransform && mnDiagramRotation != 0)
1046     {
1047         aTransformation.translate(-0.5, -0.5);
1048         aTransformation.rotate(basegfx::deg2rad<60000>(mnDiagramRotation));
1049         aTransformation.translate(0.5, 0.5);
1050     }
1051 
1052     bool bLineShape = aServiceName == "com.sun.star.drawing.LineShape";
1053     bool bTopWriterLine = !pParentGroupShape && mbWps && bLineShape;
1054     // Build object matrix from shape size and position; corresponds to MSO ext and off
1055     // Only LineShape and ConnectorShape may have zero width or height.
1056     if (bLineShape || aServiceName == "com.sun.star.drawing.ConnectorShape")
1057     {
1058         // For toplevel Writer lines, size is included in the point coordinates.
1059         if (!bTopWriterLine)
1060         {
1061             aTransformation.scale(maSize.Width, maSize.Height);
1062         }
1063     }
1064     else
1065     {
1066         aTransformation.scale(maSize.Width ? maSize.Width : 1.0,
1067                               maSize.Height ? maSize.Height : 1.0);
1068     }
1069 
1070     // Evaluate object flip. Other shapes than custom shapes have no attribute for flip but use
1071     // negative scale. Flip in MSO is at object center.
1072     if (!bIsCustomShape && (mbFlipH || mbFlipV))
1073         lcl_mirrorAtCenter(aTransformation, mbFlipH, mbFlipV);
1074 
1075     // Evaluate parent flip.
1076     // A CustomShape has mirror not as negative scale, but as attributes.
1077     basegfx::B2DVector aParentScale(1.0, 1.0);
1078     basegfx::B2DVector aParentTranslate(0.0, 0.0);
1079     double fParentRotate(0.0);
1080     double fParentShearX(0.0);
1081     if (pParentGroupShape)
1082     {
1083         aParentTransformation.decompose(aParentScale, aParentTranslate, fParentRotate, fParentShearX);
1084         if (bIsCustomShape)
1085         {
1086             lcl_mirrorAtCenter(aTransformation, aParentScale.getX() < 0, aParentScale.getY() < 0);
1087             if(aParentScale.getX() < 0)
1088                 mbFlipH = !mbFlipH;
1089             if(aParentScale.getY() < 0)
1090                 mbFlipV = !mbFlipV;
1091         }
1092     }
1093 
1094     if (maPosition.X != 0 || maPosition.Y != 0)
1095     {
1096         // if global position is used, add it to transformation
1097         if (mbWps && pParentGroupShape == nullptr)
1098             aTransformation.translate(
1099                 o3tl::convert(maPosition.X, o3tl::Length::mm100, o3tl::Length::emu),
1100                 o3tl::convert(maPosition.Y, o3tl::Length::mm100, o3tl::Length::emu));
1101         else
1102             aTransformation.translate(maPosition.X, maPosition.Y);
1103     }
1104 
1105     // Apply further parent transformations. First scale object then rotate. Other way round would
1106     // introduce shearing.
1107 
1108     // The attributes chExt and chOff of the group in oox file contain the values on which the size
1109     // and position of the child is based on. If they differ from the actual size of the group as
1110     // given in its ext and off attributes, the child has to be transformed according the new values.
1111     if (pParentGroupShape)
1112     {
1113         // ToDo: A diagram in a group might need special handling because it cannot flip and only
1114         // resize uniformly. But currently it is imported with zero size, see tdf#139575. That needs
1115         // to be fixed beforehand.
1116 
1117         // Scaling is done from left/top edges of the group. So these need to become coordinate axes.
1118         aTransformation.translate(-pParentGroupShape->maChPosition.X,
1119                                   -pParentGroupShape->maChPosition.Y);
1120 
1121         // oox allows zero or missing attribute chExt. In that case the scaling factor is 1.
1122         // Transform2DContext::onCreateContext has set maChSize to maSize for groups in oox file in
1123         // such cases. For own made groups (e.g. diagrams) that is missing.
1124         // The factors cumulate on the way through the parent groups, so we do not use maSize of the
1125         // direct parent group but the cumulated value from aParentScale.
1126         double fFactorX = 1.0;
1127         double fFactorY = 1.0;
1128         if (pParentGroupShape->maChSize.Width != 0)
1129             fFactorX = aParentScale.getX() / pParentGroupShape->maChSize.Width;
1130         if (pParentGroupShape->maChSize.Height != 0)
1131             fFactorY = aParentScale.getY() / pParentGroupShape->maChSize.Height;
1132         if (fFactorX != 1 || fFactorY != 1)
1133         {
1134             // It depends on the object rotation angle whether scaling is applied to switched
1135             // width and height. MSO acts strange in that case (as of May 2021).
1136             const sal_Int32 nDeg(mnRotation / 60000);
1137             const bool bNeedsMSOWidthHeightToggle
1138                 = (nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315);
1139             if (bNeedsMSOWidthHeightToggle)
1140                 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
1141 
1142             aTransformation.scale(fFactorX, fFactorY);
1143 
1144             if (bNeedsMSOWidthHeightToggle)
1145             {
1146                 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
1147                 // In case of flip the special case needs an additional 180deg rotation.
1148                 if ((aParentScale.getX() < 0) != (aParentScale.getY() < 0))
1149                     lcl_RotateAtCenter(aTransformation, 10800000);
1150             }
1151         }
1152     }
1153 
1154     // Apply object rotation at current object center
1155     // The flip contained in aParentScale will affect orientation of object rotation angle.
1156     sal_Int16 nOrientation = ((aParentScale.getX() < 0) != (aParentScale.getY() < 0)) ? -1 : 1;
1157     // ToDo: Not sure about the restrictions given by bUseRotationTransform.
1158     if (bUseRotationTransform && nShapeRotateInclCamera != 0)
1159     {
1160         lcl_RotateAtCenter(aTransformation, nOrientation * nShapeRotateInclCamera);
1161     }
1162 
1163     if (fParentRotate != 0.0)
1164         aTransformation.rotate(fParentRotate);
1165     if (!aParentTranslate.equalZero())
1166         aTransformation.translate(aParentTranslate);
1167 
1168     aParentTransformation = aTransformation;
1169 
1170     constexpr double fEmuToMm100 = o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::mm100);
1171     if (!bTopWriterLine)
1172     {
1173         aTransformation.scale(fEmuToMm100, fEmuToMm100);
1174     }
1175 
1176     // OOXML flips shapes before rotating them, so the rotation needs to be inverted
1177     if( bIsCustomShape && mbFlipH != mbFlipV )
1178     {
1179         basegfx::B2DVector aScale, aTranslate;
1180         double fRotate, fShearX;
1181         aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
1182 
1183         if(fRotate != 0)
1184         {
1185             basegfx::B2DPoint aCenter(0.5, 0.5);
1186             aCenter *= aTransformation;
1187             aTransformation.translate( -aCenter.getX(), -aCenter.getY() );
1188             aTransformation.rotate( fRotate * -2.0 );
1189             aTransformation.translate( aCenter.getX(), aCenter.getY() );
1190         }
1191     }
1192 
1193     // special for lineshape
1194     uno::Sequence< uno::Sequence< awt::Point > > aPolyPolySequence( 1 );
1195     if (bLineShape)
1196     {
1197         ::basegfx::B2DPolygon aPoly;
1198         aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
1199         if (bTopWriterLine)
1200         {
1201             // No transform of individual points, everything apart from size is part of the
1202             // transform matrix.
1203             sal_Int32 nMM100Width = o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100);
1204             sal_Int32 nMM100Height = o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100);
1205             aPoly.insert(1, ::basegfx::B2DPoint(nMM100Width, nMM100Height));
1206         }
1207         else
1208         {
1209             aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
1210             aPoly.transform( aTransformation );
1211         }
1212 
1213         // now creating the corresponding PolyPolygon
1214         sal_Int32 i, nNumPoints = aPoly.count();
1215         uno::Sequence< awt::Point > aPointSequence( nNumPoints );
1216         awt::Point* pPoints = aPointSequence.getArray();
1217         for( i = 0; i < nNumPoints; ++i )
1218         {
1219             basegfx::B2DPoint aPoint( aPoly.getB2DPoint( i ) );
1220 
1221             // Guard against zero width or height.
1222             if (i)
1223             {
1224                 const basegfx::B2DPoint& rPreviousPoint = aPoly.getB2DPoint(i - 1);
1225                 if (aPoint.getX() - rPreviousPoint.getX() == 0)
1226                     aPoint.setX(aPoint.getX() + 1);
1227                 if (aPoint.getY() - rPreviousPoint.getY() == 0)
1228                     aPoint.setY(aPoint.getY() + 1);
1229             }
1230 
1231             pPoints[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()), static_cast<sal_Int32>(aPoint.getY()));
1232         }
1233         aPolyPolySequence.getArray()[ 0 ] = std::move(aPointSequence);
1234 
1235         if (!(bTopWriterLine && !maSize.Width))
1236         {
1237             maShapeProperties.setProperty(PROP_PolyPolygon, aPolyPolySequence);
1238         }
1239     }
1240     HomogenMatrix3 aMatrix;
1241     tools::Rectangle aOrigSize;
1242     if ( aServiceName == "com.sun.star.drawing.ConnectorShape" )
1243     {
1244         ::basegfx::B2DPolygon aPoly;
1245         aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
1246         aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
1247         aPoly.transform( aTransformation );
1248 
1249         basegfx::B2DPoint aStartPosition( aPoly.getB2DPoint( 0 ) );
1250         basegfx::B2DPoint aEndPosition( aPoly.getB2DPoint( 1 ) );
1251         awt::Point aAWTStartPosition( static_cast< sal_Int32 >( aStartPosition.getX() ), static_cast< sal_Int32 >( aStartPosition.getY() ) );
1252         awt::Point aAWTEndPosition( static_cast< sal_Int32 >( aEndPosition.getX() ), static_cast< sal_Int32 >( aEndPosition.getY() ) );
1253 
1254         maShapeProperties.setProperty(PROP_StartPosition, aAWTStartPosition);
1255         maShapeProperties.setProperty(PROP_EndPosition, aAWTEndPosition);
1256     }
1257     else if (!bLineShape || bTopWriterLine)
1258     {
1259         // now set transformation for this object
1260 
1261         aMatrix.Line1.Column1 = aTransformation.get(0,0);
1262         aMatrix.Line1.Column2 = aTransformation.get(0,1);
1263         aMatrix.Line1.Column3 = aTransformation.get(0,2);
1264 
1265         aMatrix.Line2.Column1 = aTransformation.get(1,0);
1266         aMatrix.Line2.Column2 = aTransformation.get(1,1);
1267         aMatrix.Line2.Column3 = aTransformation.get(1,2);
1268 
1269         aMatrix.Line3.Column1 = 0;
1270         aMatrix.Line3.Column2 = 0;
1271         aMatrix.Line3.Column3 = 1;
1272 
1273         if (!(bTopWriterLine && !maSize.Width))
1274         {
1275             maShapeProperties.setProperty(PROP_Transformation, aMatrix);
1276         }
1277     }
1278 
1279     Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
1280     if ( !mxShape.is() )
1281     {
1282         mxShape.set( xServiceFact->createInstance( aServiceName ), UNO_QUERY_THROW );
1283     }
1284 
1285     Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
1286     if (xSet.is())
1287     {
1288         if (bTopWriterLine && !maSize.Width)
1289         {
1290             // Entirely vertical line, set the points and the transform separately to match the ODF
1291             // import.
1292             xSet->setPropertyValue(u"PolyPolygon"_ustr, Any(aPolyPolySequence));
1293             xSet->setPropertyValue(u"Transformation"_ustr, Any(aMatrix));
1294         }
1295 
1296         if( !msName.isEmpty() )
1297         {
1298             Reference< container::XNamed > xNamed( mxShape, UNO_QUERY );
1299             if( xNamed.is() )
1300                 xNamed->setName( msName );
1301         }
1302         if( !msDescription.isEmpty() )
1303         {
1304             xSet->setPropertyValue( u"Description"_ustr, Any( msDescription ) );
1305         }
1306         if (m_isDecorative)
1307         {
1308             xSet->setPropertyValue(u"Decorative"_ustr, Any(m_isDecorative));
1309         }
1310         if (!msMacro.isEmpty())
1311         {
1312             putPropertyToGrabBag(u"mso-sp-macro"_ustr, Any(msMacro));
1313         }
1314         if (!msTextLink.isEmpty())
1315         {
1316             putPropertyToGrabBag(u"mso-sp-textlink"_ustr, Any(msTextLink));
1317         }
1318         if (!mbFLocksText) // set only if "false", otherwise it will use "true" by default
1319         {
1320             putPropertyToGrabBag(u"mso-sp-fLocksText"_ustr, Any(mbFLocksText));
1321         }
1322         if (mbFPublished)
1323         {
1324             putPropertyToGrabBag(u"mso-sp-fPublished"_ustr, Any(mbFPublished));
1325         }
1326         if (!msTitle.isEmpty())
1327         {
1328             xSet->setPropertyValue(u"Title"_ustr, Any(msTitle));
1329         }
1330 
1331         // get tooltip attribute of <hlinkClick>
1332         OUString sTooltip;
1333         getShapeProperties().getProperty(PROP_Representation) >>= sTooltip;
1334         if (!sTooltip.isEmpty())
1335             putPropertyToGrabBag(u"mso-hlinkClick-tooltip"_ustr, Any(sTooltip));
1336 
1337         // Placeholder uses the height set on the slide instead of the height from the master slide,
1338         // if it has the "TextAutoGrowHeight" property
1339         if (getTextBody() && mxShape->getShapeType().startsWith("com.sun.star.presentation."))
1340         {
1341             bool bAutoGrowHeight = getTextBody()
1342                                        ->getTextProperties()
1343                                        .maPropertyMap.getProperty(PROP_TextAutoGrowHeight)
1344                                        .get<bool>();
1345             if (bAutoGrowHeight)
1346             {
1347                 ppt::PowerPointImport* pPPT = dynamic_cast<ppt::PowerPointImport*>(&rFilterBase);
1348                 if (!pPPT->getActualSlidePersist()->isMasterPage())
1349                 {
1350                     sal_Int32 nUpper = 0;
1351                     sal_Int32 nLower = 0;
1352                     sal_Int32 nHeight = maSize.Height / 360;
1353                     if (getTextBody()->getTextProperties().moInsets[1].has_value()
1354                         && getTextBody()->getTextProperties().moInsets[3].has_value())
1355                     {
1356                         nUpper = *getTextBody()->getTextProperties().moInsets[1];
1357                         nLower = *getTextBody()->getTextProperties().moInsets[3];
1358                     }
1359                     else
1360                     {
1361                         maDefaultShapeProperties.getProperty(PROP_TextUpperDistance) >>= nUpper;
1362                         maDefaultShapeProperties.getProperty(PROP_TextLowerDistance) >>= nLower;
1363                     }
1364                     nHeight -= (nUpper + nLower);
1365                     mxShape->setSize(awt::Size(0, nHeight));
1366                 }
1367             }
1368             else // the placeholder uses the height set on the master slide
1369                 mxShape->setSize(awt::Size(0, 0));
1370         }
1371 
1372         if (aServiceName != "com.sun.star.text.TextFrame")
1373             rxShapes->add( mxShape );
1374 
1375         if ( mbHidden || mbHiddenMasterShape )
1376         {
1377             SAL_INFO("oox.drawingml", "Shape::createAndInsert: invisible shape with id='" << msId << "'");
1378             xSet->setPropertyValue( u"Visible"_ustr, Any( false ) );
1379             // In Excel hidden means not printed, let's use visibility for now until that's handled separately
1380             xSet->setPropertyValue( u"Printable"_ustr, Any( false ) );
1381         }
1382 
1383         if (mbLocked)
1384         {
1385             xSet->setPropertyValue(u"MoveProtect"_ustr, Any(true));
1386             xSet->setPropertyValue(u"SizeProtect"_ustr, Any(true));
1387         }
1388 
1389         ActionLockGuard const alg(mxShape);
1390 
1391         // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape
1392         if ( bClearText )
1393         {
1394             uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY );
1395             if ( xText.is() )
1396             {
1397                 xText->setString( u""_ustr );
1398             }
1399         }
1400 
1401         if (pMathXml)
1402         {
1403             // the "EmbeddedObject" property is read-only, so we have to create
1404             // the shape first, and it can be read only after the shape is
1405             // inserted into the document, so delay the actual import until here
1406             SvGlobalName name(SO3_SM_CLASSID);
1407             xSet->setPropertyValue(u"CLSID"_ustr, uno::Any(name.GetHexName()));
1408             uno::Reference<embed::XEmbeddedObject> const xObj(
1409                 xSet->getPropertyValue(u"EmbeddedObject"_ustr), uno::UNO_QUERY);
1410             if (xObj.is())
1411             {
1412                 uno::Reference<uno::XInterface> const xMathModel(xObj->getComponent());
1413                 oox::FormulaImExportBase *const pMagic(
1414                         dynamic_cast<oox::FormulaImExportBase*>(xMathModel.get()));
1415                 assert(pMagic);
1416                 pMagic->readFormulaOoxml(*pMathXml);
1417             }
1418         }
1419 
1420         const GraphicHelper& rGraphicHelper = rFilterBase.getGraphicHelper();
1421 
1422         ::Color nLinePhClr(ColorTransparency, 0xffffffff);
1423         ::Color nFillPhClr(ColorTransparency, 0xffffffff);
1424         sal_Int16 nFillPhClrTheme = -1;
1425         sal_Int16 nLinePhClrTheme = -1;
1426         // TODO: use ph color when applying effect properties
1427         //sal_Int32 nEffectPhClr = -1;
1428 
1429         // dmapper needs the original rotation angle for calculating square wrap. This angle is not
1430         // available as property there, so store it in InteropGrabBag.
1431         putPropertyToGrabBag(u"mso-rotation-angle"_ustr, Any(mnRotation));
1432 
1433         if( pTheme )
1434         {
1435             if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
1436             {
1437                 LineProperties aLineProperties;
1438                 aLineProperties.maLineFill.moFillType = XML_noFill;
1439                 if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
1440                     aLineProperties.assignUsed( *pLineProps );
1441                 nLinePhClr = pLineRef->maPhClr.getColor( rGraphicHelper );
1442                 nLinePhClrTheme = pLineRef->maPhClr.getSchemeColorIndex();
1443 
1444                 // Store style-related properties to InteropGrabBag to be able to export them back
1445                 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1446                 {
1447                     {"SchemeClr", uno::Any(pLineRef->maPhClr.getSchemeColorName())},
1448                     {"Idx", uno::Any(pLineRef->mnThemedIdx)},
1449                     {"Color", uno::Any(nLinePhClr)},
1450                     {"LineStyle", uno::Any(aLineProperties.getLineStyle())},
1451                     {"LineCap", uno::Any(aLineProperties.getLineCap())},
1452                     {"LineJoint", uno::Any(aLineProperties.getLineJoint())},
1453                     {"LineWidth", uno::Any(aLineProperties.getLineWidth())},
1454                     {"Transformations", uno::Any(pLineRef->maPhClr.getTransformations())}
1455                 });
1456                 putPropertyToGrabBag( u"StyleLnRef"_ustr, Any( aProperties ) );
1457             }
1458             if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
1459             {
1460                 if (!getFillProperties().moUseBgFill.value_or(false))
1461                 {
1462                     nFillPhClr = pFillRef->maPhClr.getColor(rGraphicHelper);
1463                     nFillPhClrTheme = pFillRef->maPhClr.getSchemeColorIndex();
1464                 }
1465 
1466                 OUString sColorScheme = pFillRef->maPhClr.getSchemeColorName();
1467                 if( !sColorScheme.isEmpty() )
1468                 {
1469                     uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1470                     {
1471                         {"SchemeClr", uno::Any(sColorScheme)},
1472                         {"Idx", uno::Any(pFillRef->mnThemedIdx)},
1473                         {"Color", uno::Any(nFillPhClr)},
1474                         {"Transformations", uno::Any(pFillRef->maPhClr.getTransformations())}
1475                     });
1476 
1477                     putPropertyToGrabBag( u"StyleFillRef"_ustr, Any( aProperties ) );
1478                 }
1479             }
1480             if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
1481             {
1482                 // TODO: use ph color when applying effect properties
1483                 // nEffectPhClr = pEffectRef->maPhClr.getColor( rGraphicHelper );
1484 
1485                 // Store style-related properties to InteropGrabBag to be able to export them back
1486                 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1487                 {
1488                     {"SchemeClr", uno::Any(pEffectRef->maPhClr.getSchemeColorName())},
1489                     {"Idx", uno::Any(pEffectRef->mnThemedIdx)},
1490                     {"Transformations", uno::Any(pEffectRef->maPhClr.getTransformations())}
1491                 });
1492                 putPropertyToGrabBag( u"StyleEffectRef"_ustr, Any( aProperties ) );
1493             }
1494         }
1495         ShapePropertyMap aShapeProps( rFilterBase.getModelObjectHelper() );
1496 
1497         // add properties from textbody to shape properties
1498         if( mpTextBody )
1499         {
1500             // tdf#67347: In case of Stacked, PP calculates in the vertical direction with the
1501             // horizontal alignment.
1502             // In LO, we simulate it by setting TextVerticalAdjust based on the ParagraphAdjust
1503             // of the 1. paragraph
1504             // It is not perfect, because we have 1 TextVerticalAdjust / 1 shape, and it
1505             // does not support justified, while we can have many ParagraphAdjust / 1 shape
1506             // (if the shape have more paragraphs)
1507             if (mpTextBody->getTextProperties().maPropertyMap.hasProperty(PROP_WritingMode)
1508                 && mpTextBody->getTextProperties().maPropertyMap.getProperty(PROP_WritingMode)
1509                        == uno::Any(text::WritingMode2::STACKED)
1510                 && mpTextBody->getParagraphs().size() > 0
1511                 && aServiceName != "com.sun.star.drawing.GroupShape")
1512             {
1513                 std::optional<css::style::ParagraphAdjust>& oParaAdjust
1514                     = mpTextBody->getParagraphs()[0]->getProperties().getParaAdjust();
1515 
1516                 if (oParaAdjust)
1517                 {
1518                     switch (*oParaAdjust)
1519                     {
1520                         case ParagraphAdjust::ParagraphAdjust_LEFT:
1521                             mpTextBody->getTextProperties().meVA
1522                                 = TextVerticalAdjust::TextVerticalAdjust_TOP;
1523                             break;
1524                         case ParagraphAdjust::ParagraphAdjust_CENTER:
1525                             mpTextBody->getTextProperties().meVA
1526                                 = TextVerticalAdjust::TextVerticalAdjust_CENTER;
1527                             break;
1528                         case ParagraphAdjust::ParagraphAdjust_RIGHT:
1529                             mpTextBody->getTextProperties().meVA
1530                                 = TextVerticalAdjust::TextVerticalAdjust_BOTTOM;
1531                             break;
1532                         default:
1533                             break;
1534                     }
1535                     mpTextBody->getTextProperties().maPropertyMap.setProperty(
1536                         PROP_TextVerticalAdjust, mpTextBody->getTextProperties().meVA);
1537                 }
1538             }
1539 
1540             // tdf#162571: In case of shapes with TextAutoGrowHeight, PP calculates/grow the
1541             // shapes size in edit mode (typing) based on the text horizontal alignment.
1542             // In LO, we simulate it by setting TextHorizontalAdjust based on the ParagraphAdjust
1543             // of the 1. paragraph
1544             // It is not perfect, because we have 1 TextHorizontalAdjust / 1 shape,
1545             // while we can have many ParagraphAdjust / 1 shape
1546             if (!mpTextBody->getTextProperties().maPropertyMap.hasProperty(PROP_WritingMode)
1547                 && mpTextBody->getParagraphs().size() > 0)
1548             {
1549                 std::optional<css::style::ParagraphAdjust>& oParaAdjust
1550                     = mpTextBody->getParagraphs()[0]->getProperties().getParaAdjust();
1551 
1552                 bool bAutoGrowHeight = getTextBody()
1553                     ->getTextProperties()
1554                     .maPropertyMap.getProperty(PROP_TextAutoGrowHeight)
1555                     .get<bool>();
1556 
1557                 bool bWrap = getTextBody()
1558                     ->getTextProperties()
1559                     .maPropertyMap.getProperty(PROP_TextWordWrap)
1560                     .get<bool>();
1561 
1562                 if (bAutoGrowHeight && !bWrap && nShapeRotateInclCamera == 0)
1563                 {
1564                     mpTextBody->getTextProperties().maPropertyMap.setProperty(
1565                         PROP_TextHorizontalAdjust, lcl_convertTextAdjust(
1566                             oParaAdjust ? *oParaAdjust : ParagraphAdjust_LEFT));
1567                 }
1568             }
1569 
1570             mpTextBody->getTextProperties().pushTextDistances(Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
1571             aShapeProps.assignUsed( mpTextBody->getTextProperties().maPropertyMap );
1572             // Push char properties as well - specifically useful when this is a placeholder
1573             if( mpMasterTextListStyle &&  mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.has_value() )
1574                 aShapeProps.setProperty(PROP_CharHeight, GetFontHeight( mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.value() ));
1575         }
1576 
1577         // applying properties
1578         aShapeProps.assignUsed( getShapeProperties() );
1579         aShapeProps.assignUsed( maDefaultShapeProperties );
1580         if(nShapeRotateInclCamera != 0 && bIsCustomShape)
1581             aShapeProps.setProperty(PROP_RotateAngle,
1582                                     sal_Int32(lcl_MSORotateAngleToAPIAngle(nShapeRotateInclCamera)));
1583         if( bIsEmbMedia ||
1584             bIsCustomShape ||
1585             aServiceName == "com.sun.star.drawing.GraphicObjectShape" ||
1586             aServiceName == "com.sun.star.drawing.OLE2Shape")
1587         {
1588             mpGraphicPropertiesPtr->pushToPropMap( aShapeProps, rGraphicHelper, mbFlipH, mbFlipV );
1589         }
1590         if ( mpTablePropertiesPtr && aServiceName == "com.sun.star.drawing.TableShape" )
1591         {
1592             mpTablePropertiesPtr->pushToPropSet( rFilterBase, xSet, mpMasterTextListStyle );
1593             if ( auto* pTableShape = dynamic_cast<sdr::table::SdrTableObj*>(SdrObject::getSdrObjectFromXShape(mxShape)) )
1594             {
1595                 // Disable layouting until table height is expanded to fit the content
1596                 pTableShape->SetSkipChangeLayout(true);
1597             }
1598         }
1599 
1600         FillProperties aFillProperties = getActualFillProperties(pTheme, &rShapeOrParentShapeFillProps);
1601         if (getFillProperties().moFillType.has_value() && getFillProperties().moFillType.value() == XML_grpFill)
1602             getFillProperties().assignUsed(aFillProperties);
1603         if(!bIsCroppedGraphic && !bIs3DGraphic)
1604             aFillProperties.pushToPropMap(aShapeProps, rGraphicHelper, mnRotation, nFillPhClr,
1605                                           css::awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height),
1606                                           nFillPhClrTheme, mbFlipH, mbFlipV, bIsCustomShape);
1607 
1608         LineProperties aLineProperties = getActualLineProperties(pTheme);
1609         aLineProperties.pushToPropMap( aShapeProps, rGraphicHelper, nLinePhClr, nLinePhClrTheme);
1610         EffectProperties aEffectProperties = getActualEffectProperties(pTheme);
1611         // TODO: use ph color when applying effect properties
1612         aEffectProperties.pushToPropMap( aShapeProps, rGraphicHelper );
1613 
1614         // applying autogrowheight property before setting shape size, because
1615         // the shape size might be changed if currently autogrowheight is true
1616         // we must also check that the PropertySet supports the property.
1617         Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1618         const OUString& rPropName = PropertyMap::getPropertyName( PROP_TextAutoGrowHeight );
1619         if( xSetInfo.is() && xSetInfo->hasPropertyByName( rPropName ) )
1620             if( aShapeProps.hasProperty( PROP_TextAutoGrowHeight ) )
1621                 xSet->setPropertyValue( rPropName, Any( false ) );
1622 
1623         // For extruded shapes, MSO uses the line color if no extrusion color is specified. LO uses
1624         // fill color in 'automatic' case. Thus we set extrusion color explicitly.
1625         if (bHas3DEffect && !aExtrusionColor.isUsed())
1626         {
1627             const OUString& rFillColor2PropName = PropertyMap::getPropertyName(PROP_FillColor2);
1628             if (xSetInfo.is() && xSetInfo->hasPropertyByName(rFillColor2PropName))
1629             {
1630                 Color aComplexColor;
1631                 if (aLineProperties.maLineFill.moFillType.has_value()
1632                     && aLineProperties.maLineFill.moFillType.value() != XML_noFill)
1633                     aComplexColor = aLineProperties.maLineFill.getBestSolidColor();
1634                 else if (aFillProperties.moFillType.has_value()
1635                     && aFillProperties.moFillType.value() != XML_noFill)
1636                     aComplexColor = aFillProperties.getBestSolidColor();
1637                 if (aComplexColor.isUsed())
1638                 {
1639                     const ::Color aSimpleColor = aComplexColor.getColor(rFilterBase.getGraphicHelper());
1640                     xSet->setPropertyValue(rFillColor2PropName, Any(aSimpleColor));
1641                 }
1642             }
1643         }
1644 
1645         // do not set properties at a group shape (this causes
1646         // assertions from svx) ...
1647         if( aServiceName != "com.sun.star.drawing.GroupShape" )
1648         {
1649             if (aServiceName == "com.sun.star.text.TextFrame")
1650             {
1651                 if (mpCustomShapePropertiesPtr && mpCustomShapePropertiesPtr->getShapeTypeOverride())
1652                 {
1653                     uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1654                     uno::Sequence<beans::PropertyValue> aGrabBag;
1655                     propertySet->getPropertyValue(u"FrameInteropGrabBag"_ustr) >>= aGrabBag;
1656                     sal_Int32 length = aGrabBag.getLength();
1657                     aGrabBag.realloc( length+1);
1658                     auto pGrabBag = aGrabBag.getArray();
1659                     pGrabBag[length].Name = "mso-orig-shape-type";
1660                     pGrabBag[length].Value <<= mpCustomShapePropertiesPtr->getShapePresetTypeName();
1661                     propertySet->setPropertyValue(u"FrameInteropGrabBag"_ustr,uno::Any(aGrabBag));
1662                 }
1663                 //If the text box has links then save the link information so that
1664                 //it can be accessed in DomainMapper_Impl.cxx while chaining the text frames.
1665                 if (isLinkedTxbx())
1666                 {
1667                     uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1668                     uno::Sequence<beans::PropertyValue> aGrabBag;
1669                     propertySet->getPropertyValue(u"FrameInteropGrabBag"_ustr) >>= aGrabBag;
1670                     sal_Int32 length = aGrabBag.getLength();
1671                     aGrabBag.realloc( length + 3 );
1672                     auto pGrabBag = aGrabBag.getArray();
1673                     pGrabBag[length].Name = "TxbxHasLink";
1674                     pGrabBag[length].Value <<= isLinkedTxbx();
1675                     pGrabBag[length + 1 ].Name = "Txbx-Id";
1676                     pGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1677                     pGrabBag[length + 2 ].Name = "Txbx-Seq";
1678                     pGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1679                     propertySet->setPropertyValue(u"FrameInteropGrabBag"_ustr,uno::Any(aGrabBag));
1680                 }
1681 
1682                 // TextFrames have BackColor, not FillColor
1683                 if (aShapeProps.hasProperty(PROP_FillColor))
1684                 {
1685                     aShapeProps.setAnyProperty(PROP_BackColor, aShapeProps.getProperty(PROP_FillColor));
1686                     aShapeProps.erase(PROP_FillColor);
1687                 }
1688                 // TextFrames have BackColorTransparency, not FillTransparence
1689                 if (aShapeProps.hasProperty(PROP_FillTransparence))
1690                 {
1691                     aShapeProps.setAnyProperty(PROP_BackColorTransparency, aShapeProps.getProperty(PROP_FillTransparence));
1692                     aShapeProps.erase(PROP_FillTransparence);
1693                 }
1694                 // TextFrames have BackGraphic, not FillBitmap
1695                 if (aShapeProps.hasProperty(PROP_FillBitmap))
1696                 {
1697                     aShapeProps.setAnyProperty(PROP_BackGraphic, aShapeProps.getProperty(PROP_FillBitmap));
1698                     aShapeProps.erase(PROP_FillBitmap);
1699                 }
1700                 if (aShapeProps.hasProperty(PROP_FillBitmapName))
1701                 {
1702                     uno::Any aAny = aShapeProps.getProperty(PROP_FillBitmapName);
1703                     OUString aFillBitmapName = aAny.get<OUString>();
1704                     uno::Reference<awt::XBitmap> xBitmap = rFilterBase.getModelObjectHelper().getFillBitmap(aFillBitmapName);
1705                     uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
1706                     aShapeProps.setProperty(PROP_BackGraphic, xGraphic);
1707                     // aShapeProps.erase(PROP_FillBitmapName);  // Maybe, leave the name as well
1708                 }
1709                 // And no LineColor property; individual borders can have colors
1710                 if (aShapeProps.hasProperty(PROP_LineColor))
1711                 {
1712                     uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1713                     static const sal_Int32 aBorders[] =
1714                     {
1715                         PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
1716                     };
1717                     for (sal_Int32 nBorder : aBorders)
1718                     {
1719                         css::table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<css::table::BorderLine2>();
1720                         aBorderLine.Color = aShapeProps.getProperty(PROP_LineColor).get<sal_Int32>();
1721                         if (aLineProperties.moLineWidth.has_value())
1722                             aBorderLine.LineWidth = convertEmuToHmm(aLineProperties.moLineWidth.value());
1723                         aShapeProps.setProperty(nBorder, aBorderLine);
1724                     }
1725                     aShapeProps.erase(PROP_LineColor);
1726                 }
1727                 if(mnRotation)
1728                 {
1729                     uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1730                     static constexpr OUString aGrabBagPropName = u"FrameInteropGrabBag"_ustr;
1731                     uno::Sequence<beans::PropertyValue> aGrabBag;
1732                     xPropertySet->getPropertyValue(aGrabBagPropName) >>= aGrabBag;
1733                     beans::PropertyValue aPair(comphelper::makePropertyValue(u"mso-rotation-angle"_ustr,
1734                                                                              mnRotation));
1735                     if (aGrabBag.hasElements())
1736                     {
1737                         sal_Int32 nLength = aGrabBag.getLength();
1738                         aGrabBag.realloc(nLength + 1);
1739                         aGrabBag.getArray()[nLength] = std::move(aPair);
1740                     }
1741                     else
1742                     {
1743                         aGrabBag = { std::move(aPair) };
1744                     }
1745                     xPropertySet->setPropertyValue(aGrabBagPropName, uno::Any(aGrabBag));
1746                 }
1747                 // TextFrames have ShadowFormat, not individual shadow properties.
1748                 std::optional<sal_Int32> oShadowDistance;
1749                 if (aShapeProps.hasProperty(PROP_ShadowXDistance))
1750                 {
1751                     oShadowDistance = aShapeProps.getProperty(PROP_ShadowXDistance).get<sal_Int32>();
1752                     aShapeProps.erase(PROP_ShadowXDistance);
1753                 }
1754                 if (aShapeProps.hasProperty(PROP_ShadowYDistance))
1755                 {
1756                     // There is a single 'dist' attribute, so no need to count the avg of x and y.
1757                     aShapeProps.erase(PROP_ShadowYDistance);
1758                 }
1759                 std::optional<sal_Int32> oShadowColor;
1760                 if (aShapeProps.hasProperty(PROP_ShadowColor))
1761                 {
1762                     oShadowColor = aShapeProps.getProperty(PROP_ShadowColor).get<sal_Int32>();
1763                     aShapeProps.erase(PROP_ShadowColor);
1764                 }
1765                 if (aShapeProps.hasProperty(PROP_Shadow))
1766                     aShapeProps.erase(PROP_Shadow);
1767 
1768                 if (oShadowDistance || oShadowColor || aEffectProperties.maShadow.moShadowDir.has_value())
1769                 {
1770                     css::table::ShadowFormat aFormat;
1771                     if (oShadowColor)
1772                         aFormat.Color = *oShadowColor;
1773                     if (aEffectProperties.maShadow.moShadowDir.has_value())
1774                     {
1775                         css::table::ShadowLocation nLocation = css::table::ShadowLocation_NONE;
1776                         switch (aEffectProperties.maShadow.moShadowDir.value())
1777                         {
1778                         case 13500000:
1779                             nLocation = css::table::ShadowLocation_TOP_LEFT;
1780                             break;
1781                         case 18900000:
1782                             nLocation = css::table::ShadowLocation_TOP_RIGHT;
1783                             break;
1784                         case 8100000:
1785                             nLocation = css::table::ShadowLocation_BOTTOM_LEFT;
1786                             break;
1787                         case 2700000:
1788                             nLocation = css::table::ShadowLocation_BOTTOM_RIGHT;
1789                             break;
1790                         }
1791                         aFormat.Location = nLocation;
1792                     }
1793                     aFormat.ShadowWidth = *oShadowDistance;
1794                     aShapeProps.setProperty(PROP_ShadowFormat, aFormat);
1795                 }
1796 
1797             }
1798             else if (mbTextBox)
1799             {
1800                 // This introduces a TextBox in a shape in Writer. ToDo: Can we restrict it to cases
1801                 // where the TextBox edit engine is really needed? tdf#82627
1802                 aShapeProps.setProperty(PROP_TextBox, true);
1803             }
1804 
1805             if (aServiceName != "com.sun.star.text.TextFrame" && isLinkedTxbx())
1806             {
1807                 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1808                 uno::Sequence<beans::PropertyValue> aGrabBag;
1809                 propertySet->getPropertyValue(u"InteropGrabBag"_ustr) >>= aGrabBag;
1810                 sal_Int32 length = aGrabBag.getLength();
1811                 aGrabBag.realloc( length + 3 );
1812                 auto pGrabBag = aGrabBag.getArray();
1813                 pGrabBag[length].Name = "TxbxHasLink";
1814                 pGrabBag[length].Value <<= isLinkedTxbx();
1815                 pGrabBag[length + 1 ].Name = "Txbx-Id";
1816                 pGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1817                 pGrabBag[length + 2 ].Name = "Txbx-Seq";
1818                 pGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1819                 propertySet->setPropertyValue(u"InteropGrabBag"_ustr,uno::Any(aGrabBag));
1820             }
1821 
1822             // set custom prompt text if available
1823             if (getCustomPrompt() && getTextBody() && !getTextBody()->isEmpty())
1824             {
1825                 aShapeProps.setProperty(PROP_CustomPromptText, getTextBody()->firstParatoString());
1826             }
1827             else if (pPlaceholder && pPlaceholder->getCustomPrompt() && pPlaceholder->getTextBody() && !pPlaceholder->getTextBody()->isEmpty())
1828             {
1829                 aShapeProps.setProperty(PROP_CustomPromptText, pPlaceholder->getTextBody()->firstParatoString());
1830             }
1831 
1832             PropertySet( xSet ).setProperties( aShapeProps );
1833 
1834             if (mpTablePropertiesPtr && aServiceName == "com.sun.star.drawing.TableShape")
1835             {
1836                 // Powerpoint exports desired row heights (i.e. what user attempted to set it as, not how it appears visually)
1837                 // Expand table height if there are rows that can't fit the content
1838                 if (auto* pTableShape = dynamic_cast<sdr::table::SdrTableObj*>(SdrObject::getSdrObjectFromXShape(mxShape)))
1839                 {
1840                     tools::Rectangle aArea{};
1841                     pTableShape->LayoutTableHeight(aArea);
1842                     sal_Int32 nCorrectedHeight = aArea.GetHeight();
1843                     const auto aShapeSize = mxShape->getSize();
1844                     if( nCorrectedHeight > aShapeSize.Height )
1845                         mxShape->setSize( {aShapeSize.Width, nCorrectedHeight} );
1846                     pTableShape->SetSkipChangeLayout(false);
1847                 }
1848             }
1849 
1850             if (mbLockedCanvas)
1851             {
1852                 putPropertyToGrabBag( u"LockedCanvas"_ustr, Any( true ) );
1853                 if (aServiceName == "com.sun.star.drawing.LineShape")
1854                 {
1855                     // It seems the position and size for lines inside a locked canvas is absolute.
1856                     mxShape->setPosition(awt::Point(aShapeRectHmm.X, aShapeRectHmm.Y));
1857                     mxShape->setSize(awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
1858                 }
1859             }
1860 
1861             if (mbWordprocessingCanvas)
1862             {
1863                 putPropertyToGrabBag(u"WordprocessingCanvas"_ustr, Any(true));
1864             }
1865 
1866             // Store original fill and line colors of the shape and the theme color name to InteropGrabBag
1867             std::vector<beans::PropertyValue> aProperties
1868             {
1869                 comphelper::makePropertyValue(u"EmuLineWidth"_ustr, aLineProperties.moLineWidth.value_or(0)),
1870                 comphelper::makePropertyValue(u"OriginalSolidFillClr"_ustr, aShapeProps.getProperty(PROP_FillColor)),
1871                 comphelper::makePropertyValue(u"OriginalLnSolidFillClr"_ustr, aShapeProps.getProperty(PROP_LineColor))
1872             };
1873             OUString sColorFillScheme = aFillProperties.maFillColor.getSchemeColorName();
1874             if( !aFillProperties.maFillColor.isPlaceHolder() && !sColorFillScheme.isEmpty() )
1875             {
1876                 aProperties.push_back(comphelper::makePropertyValue(u"SpPrSolidFillSchemeClr"_ustr, sColorFillScheme));
1877                 aProperties.push_back(comphelper::makePropertyValue(u"SpPrSolidFillSchemeClrTransformations"_ustr, aFillProperties.maFillColor.getTransformations()));
1878             }
1879             OUString sLnColorFillScheme = aLineProperties.maLineFill.maFillColor.getSchemeColorName();
1880             if( !aLineProperties.maLineFill.maFillColor.isPlaceHolder() && !sLnColorFillScheme.isEmpty() )
1881             {
1882                 aProperties.push_back(comphelper::makePropertyValue(u"SpPrLnSolidFillSchemeClr"_ustr, sLnColorFillScheme));
1883                 auto aResolvedSchemeClr = aLineProperties.maLineFill.maFillColor;
1884                 aResolvedSchemeClr.clearTransformations();
1885                 aProperties.push_back(comphelper::makePropertyValue(u"SpPrLnSolidFillResolvedSchemeClr"_ustr, aResolvedSchemeClr.getColor(rGraphicHelper, nFillPhClr)));
1886                 aProperties.push_back(comphelper::makePropertyValue(u"SpPrLnSolidFillSchemeClrTransformations"_ustr, aLineProperties.maLineFill.maFillColor.getTransformations()));
1887             }
1888             putPropertiesToGrabBag(comphelper::containerToSequence(aProperties));
1889 
1890             // Store original gradient fill of the shape to InteropGrabBag
1891             // LibreOffice doesn't support all the kinds of gradient so we save its complete definition
1892             if( aShapeProps.hasProperty( PROP_FillGradient ) )
1893             {
1894                 std::vector<beans::PropertyValue> aGradientStops;
1895                 size_t i = 0;
1896                 for( const auto& [rPos, rColor] : aFillProperties.maGradientProps.maGradientStops )
1897                 { // for each stop in the gradient definition:
1898 
1899                     // save position
1900                     std::vector<beans::PropertyValue> aGradientStop
1901                     {
1902                         comphelper::makePropertyValue(u"Pos"_ustr, rPos)
1903                     };
1904 
1905                     OUString sStopColorScheme = rColor.getSchemeColorName();
1906                     if( sStopColorScheme.isEmpty() )
1907                     {
1908                         // save RGB color
1909                         aGradientStop.push_back(comphelper::makePropertyValue(u"RgbClr"_ustr, rColor.getColor(rGraphicHelper, nFillPhClr)));
1910                         // in the case of a RGB color, transformations are already applied to
1911                         // the color with the exception of alpha transformations. We only need
1912                         // to keep the transparency value to calculate the alpha value later.
1913                         if( rColor.hasTransparency() )
1914                             aGradientStop.push_back(comphelper::makePropertyValue(u"Transparency"_ustr, rColor.getTransparency()));
1915                     }
1916                     else
1917                     {
1918                         // save color with scheme name
1919                         aGradientStop.push_back(comphelper::makePropertyValue(u"SchemeClr"_ustr, sStopColorScheme));
1920                         // save all color transformations
1921                         aGradientStop.push_back(comphelper::makePropertyValue(u"Transformations"_ustr, rColor.getTransformations()));
1922                     }
1923 
1924                     aGradientStops.push_back(comphelper::makePropertyValue(OUString::number(i), comphelper::containerToSequence(aGradientStop)));
1925                     ++i;
1926                 }
1927                 // If getFillProperties.moFillType is unused that means gradient is defined by a theme
1928                 // which is already saved into StyleFillRef property, so no need to save the explicit values too
1929                 if( getFillProperties().moFillType.has_value() )
1930                     putPropertyToGrabBag( u"GradFillDefinition"_ustr, uno::Any(comphelper::containerToSequence(aGradientStops)));
1931                 putPropertyToGrabBag( u"OriginalGradFill"_ustr, aShapeProps.getProperty(PROP_FillGradient) );
1932             }
1933 
1934             // store unsupported effect attributes in the grab bag
1935             if (!aEffectProperties.m_Effects.empty())
1936             {
1937                 std::vector<beans::PropertyValue> aEffects;
1938                 for (auto const& it : aEffectProperties.m_Effects)
1939                 {
1940                     PropertyValue aEffect = it->getEffect();
1941                     if( !aEffect.Name.isEmpty() )
1942                     {
1943                         std::vector<beans::PropertyValue> aEffectsGrabBag
1944                         {
1945                             comphelper::makePropertyValue(u"Attribs"_ustr, aEffect.Value)
1946                         };
1947 
1948                         Color& aColor( it->moColor );
1949                         OUString sColorScheme = aColor.getSchemeColorName();
1950                         if( sColorScheme.isEmpty() )
1951                         {
1952                             // RGB color and transparency value
1953                             aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"RgbClr"_ustr, aColor.getColor(rGraphicHelper, nFillPhClr)));
1954                             aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"RgbClrTransparency"_ustr, aColor.getTransparency()));
1955                         }
1956                         else
1957                         {
1958                             // scheme color with name and transformations
1959                             aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"SchemeClr"_ustr, sColorScheme));
1960                             aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"SchemeClrTransformations"_ustr, aColor.getTransformations()));
1961                         }
1962                         aEffects.push_back(comphelper::makePropertyValue(aEffect.Name, comphelper::containerToSequence(aEffectsGrabBag)));
1963                     }
1964                 }
1965                 putPropertyToGrabBag(u"EffectProperties"_ustr, uno::Any(comphelper::containerToSequence(aEffects)));
1966             }
1967 
1968             // add 3D effects if any to GrabBag. They are still used in export.
1969             Sequence< PropertyValue > aCamera3DEffects = get3DProperties().getCameraAttributes();
1970             Sequence< PropertyValue > aLightRig3DEffects = get3DProperties().getLightRigAttributes();
1971             Sequence< PropertyValue > aShape3DEffects = get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1972             if( aCamera3DEffects.hasElements() || aLightRig3DEffects.hasElements() || aShape3DEffects.hasElements() )
1973             {
1974                 uno::Sequence<beans::PropertyValue> a3DEffectsGrabBag = comphelper::InitPropertySequence(
1975                 {
1976                     {"Camera", uno::Any(aCamera3DEffects)},
1977                     {"LightRig", uno::Any(aLightRig3DEffects)},
1978                     {"Shape3D", uno::Any(aShape3DEffects)}
1979                 });
1980                 putPropertyToGrabBag( u"3DEffectProperties"_ustr, Any( a3DEffectsGrabBag ) );
1981             }
1982 
1983             if( bIsCustomShape && getTextBody())
1984             {
1985 
1986                 Sequence< PropertyValue > aTextCamera3DEffects = getTextBody()->get3DProperties().getCameraAttributes();
1987                 Sequence< PropertyValue > aTextLightRig3DEffects = getTextBody()->get3DProperties().getLightRigAttributes();
1988                 Sequence< PropertyValue > aTextShape3DEffects = getTextBody()->get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1989                 if( aTextCamera3DEffects.hasElements() || aTextLightRig3DEffects.hasElements() || aTextShape3DEffects.hasElements() )
1990                 {
1991                     uno::Sequence<beans::PropertyValue> aText3DEffectsGrabBag = comphelper::InitPropertySequence(
1992                     {
1993                         {"Camera", uno::Any(aTextCamera3DEffects)},
1994                         {"LightRig", uno::Any(aTextLightRig3DEffects)},
1995                         {"Shape3D", uno::Any(aTextShape3DEffects)}
1996                     });
1997                     putPropertyToGrabBag( u"Text3DEffectProperties"_ustr, Any( aText3DEffectsGrabBag ) );
1998                 }
1999             }
2000 
2001             // store bitmap artistic effects in the grab bag
2002             if( !mpGraphicPropertiesPtr->maBlipProps.maEffect.isEmpty() )
2003                 putPropertyToGrabBag( u"ArtisticEffectProperties"_ustr,
2004                                       Any( mpGraphicPropertiesPtr->maBlipProps.maEffect.getEffect() ) );
2005         }
2006 
2007         else if( mbLockedCanvas )
2008         {
2009             //If we have aServiceName as "com.sun.star.drawing.GroupShape" and lockedCanvas
2010             putPropertyToGrabBag( u"LockedCanvas"_ustr, Any( true ) );
2011         }
2012         else if (mbWordprocessingCanvas)
2013         {
2014             putPropertyToGrabBag(u"WordprocessingCanvas"_ustr, Any(true));
2015             putPropertyToGrabBag(u"mso-edit-as"_ustr, Any(u"canvas"_ustr)); // for export VML Fallback
2016         }
2017 
2018         // These can have a custom geometry, so position should be set here,
2019         // after creation but before custom shape handling, using the position
2020         // we got from the caller.
2021         if (mbWps && aServiceName == "com.sun.star.drawing.LineShape" && !pParentGroupShape)
2022             mxShape->setPosition(maPosition);
2023 
2024         SdrObject* pShape = SdrObject::getSdrObjectFromXShape(mxShape);
2025         if (pShape)
2026             aOrigSize = pShape->GetLogicRect();
2027 
2028         if (bIsConnectorShape)
2029         {
2030             msConnectorName = mpCustomShapePropertiesPtr->getShapePresetTypeName();
2031 
2032             const auto& aAdjustmentList = mpCustomShapePropertiesPtr->getAdjustmentGuideList();
2033             for (size_t i = 0; i < aAdjustmentList.size(); i++)
2034                 maConnectorAdjustmentList.push_back(aAdjustmentList[i].maFormula);
2035 
2036             sal_Int32 nType = mpCustomShapePropertiesPtr->getShapePresetType();
2037             switch (nType)
2038             {
2039             case XML_line:
2040             case XML_straightConnector1:
2041                 xSet->setPropertyValue(u"EdgeKind"_ustr, Any(ConnectorType_LINE));
2042                 break;
2043             case XML_bentConnector2:
2044             case XML_bentConnector3:
2045             case XML_bentConnector4:
2046             case XML_bentConnector5:
2047                 xSet->setPropertyValue(u"EdgeKind"_ustr, Any(ConnectorType_STANDARD));
2048                 break;
2049             case XML_curvedConnector2:
2050             case XML_curvedConnector3:
2051             case XML_curvedConnector4:
2052             case XML_curvedConnector5:
2053                 xSet->setPropertyValue(u"EdgeKind"_ustr, Any(ConnectorType_CURVE));
2054                 break;
2055             default:
2056                 break;
2057             }
2058         }
2059 
2060         if( bIsCustomShape )
2061         {
2062             if ( mbFlipH )
2063                 mpCustomShapePropertiesPtr->setMirroredX( true );
2064             if ( mbFlipV )
2065                 mpCustomShapePropertiesPtr->setMirroredY( true );
2066             if( getTextBody() )
2067             {
2068                 sal_Int32 nTextCameraZRotation = getTextBody()->get3DProperties().maCameraRotation.mnRevolution.value_or(0);
2069                 mpCustomShapePropertiesPtr->setTextCameraZRotateAngle( nTextCameraZRotation / 60000 );
2070 
2071                 // TextPreRotateAngle. Text rotates inside the text area. Might be used for diagram layout 'upr' and 'grav'.
2072                 sal_Int32 nTextPreRotateAngle = static_cast< sal_Int32 >( getTextBody()->getTextProperties().moTextPreRotation.value_or( 0 ) );
2073 
2074                 nTextPreRotateAngle -= mnDiagramRotation; // Use of mnDiagramRotation is unclear. It seems to be always 0 here.
2075 
2076                 // TextRotateAngle. The text area rotates.
2077                 sal_Int32 nTextAreaRotateAngle = getTextBody()->getTextProperties().moTextAreaRotation.value_or(0);
2078                 if (getTextBody()->getTextProperties().moUpright)
2079                 {
2080                     // When upright is set, any text area transformation and shape rotation is ignored
2081                     // in MS Office. To simulate this behaviour, we rotate the text area into the
2082                     // opposite direction of the shape rotation by as much as the shape was rotated
2083                     // and so compensate the shape rotation, which is added in rendering.
2084                     nTextAreaRotateAngle = -mnRotation;
2085                     // If 45° <= shape rotation < 135° or 225° <= shape rotation < 315°,
2086                     // then MS Office adds an additional 90° rotation to the text area.
2087                     const sal_Int32 nDeg(mnRotation / 60000);
2088                     if ((nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315))
2089                     {
2090                         nTextAreaRotateAngle += 5400000;
2091                         nTextPreRotateAngle -= 5400000; // compensate the additional text area rotation
2092                     }
2093                     putPropertyToGrabBag(u"Upright"_ustr, Any(true));
2094                 }
2095                 /* OOX measures text rotation clockwise in 1/60000th degrees,
2096                    relative to the containing shape. set*Angle wants degrees counter-clockwise. */
2097                 mpCustomShapePropertiesPtr->setTextPreRotateAngle(-nTextPreRotateAngle / 60000);
2098                 if (nTextAreaRotateAngle != 0)
2099                     mpCustomShapePropertiesPtr->setTextAreaRotateAngle(-nTextAreaRotateAngle / 60000);
2100 
2101                 auto sHorzOverflow = getTextBody()->getTextProperties().msHorzOverflow;
2102                 if (!sHorzOverflow.isEmpty())
2103                     putPropertyToGrabBag(u"horzOverflow"_ustr, uno::Any(getTextBody()->getTextProperties().msHorzOverflow));
2104                 if (XML_ellipsis == getTextBody()->getTextProperties().moVertOverflow)
2105                     putPropertyToGrabBag(u"vertOverflow"_ustr, uno::Any(u"ellipsis"_ustr));
2106             }
2107 
2108             // Note that the script oox/source/drawingml/customshapes/generatePresetsData.pl looks
2109             // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs
2110             SAL_INFO("oox.cscode", "==cscode== shape name: '" << msName << "'");
2111             SAL_INFO("oox.csdata", "==csdata== shape name: '" << msName << "'");
2112 
2113             mpCustomShapePropertiesPtr->pushToPropSet(xSet, maSize);
2114 
2115             // Consider WordArt
2116             if (mpTextBody && !mpTextBody->getTextProperties().msPrst.isEmpty()
2117                 && mpTextBody->getTextProperties().msPrst != u"textNoShape")
2118             {
2119                 bool bFromWordArt(aShapeProps.hasProperty(PROP_FromWordArt)
2120                                       ? aShapeProps.getProperty(PROP_FromWordArt).get<bool>()
2121                                       : false);
2122                 FontworkHelpers::putCustomShapeIntoTextPathMode(
2123                     mxShape, mpCustomShapePropertiesPtr, mpTextBody->getTextProperties().msPrst,
2124                     bFromWordArt);
2125             }
2126         }
2127         else if( getTextBody() )
2128             getTextBody()->getTextProperties().pushVertSimulation();
2129 
2130         // tdf#133037: a bit hackish: force Shape to rotate in the opposite direction the camera would rotate
2131         PropertySet aPropertySet(mxShape);
2132         if ( !bUseRotationTransform && (nShapeRotateInclCamera !=0) )
2133         {
2134             Degree100 nAngle(lcl_MSORotateAngleToAPIAngle(nShapeRotateInclCamera));
2135             aPropertySet.setAnyProperty(PROP_RotateAngle, Any( sal_Int32(nAngle)));
2136             aPropertySet.setAnyProperty( PROP_HoriOrientPosition, Any( maPosition.X ) );
2137             aPropertySet.setAnyProperty( PROP_VertOrientPosition, Any( maPosition.Y ) );
2138         }
2139 
2140         // Make sure to not set text to placeholders. Doing it here would eventually call
2141         // SvxTextEditSourceImpl::UpdateData, SdrObject::SetEmptyPresObj(false), and that
2142         // would make the object behave like a standard outline object.
2143         // TODO/FIXME: support custom prompt text in placeholders.
2144         if (rServiceName == "com.sun.star.presentation.GraphicObjectShape")
2145             mpTextBody.reset();
2146 
2147         // in some cases, we don't have any text body.
2148         if( mpTextBody && ( !pPlaceholder || !mpTextBody->isEmpty() ) )
2149         {
2150             Reference < XText > xText( mxShape, UNO_QUERY );
2151             if ( xText.is() )   // not every shape is supporting an XText interface (e.g. GroupShape)
2152             {
2153                 TextCharacterProperties aCharStyleProperties;
2154                 if( const ShapeStyleRef* pFontRef = getShapeStyleRef( XML_fontRef ) )
2155                 {
2156                     if( pFontRef->mnThemedIdx != 0 )
2157                     {
2158                         if( pTheme )
2159                             if( const TextCharacterProperties* pCharProps = pTheme->getFontStyle( pFontRef->mnThemedIdx ) )
2160                                 aCharStyleProperties.assignUsed( *pCharProps );
2161                         SAL_INFO("oox.drawingml", "Shape::createAndInsert: use font color");
2162                         if ( pFontRef->maPhClr.isUsed() )
2163                         {
2164                             aCharStyleProperties.maFillProperties.maFillColor = pFontRef->maPhClr;
2165                             aCharStyleProperties.maFillProperties.moFillType = XML_solidFill;
2166                         }
2167                     }
2168                 }
2169                 xText->setString(u""_ustr);
2170                 Reference < XTextCursor > xAt = xText->createTextCursor();
2171                 getTextBody()->insertAt( rFilterBase, xText, xAt, aCharStyleProperties, mpMasterTextListStyle );
2172 
2173                 const TextParagraphVector& rParagraphs = getTextBody()->getParagraphs();
2174                 if (!rParagraphs.empty())
2175                 {
2176                     const std::shared_ptr<TextParagraph>& pParagraph = rParagraphs[0];
2177                     if (pParagraph->getProperties().getParaAdjust())
2178                     {
2179                         style::ParagraphAdjust eAdjust = *pParagraph->getProperties().getParaAdjust();
2180                         if (eAdjust == style::ParagraphAdjust_CENTER)
2181                         {
2182                             // If the first paragraph is centered, then set the para adjustment of
2183                             // the shape itself to centered as well.
2184                             aPropertySet.setAnyProperty(PROP_ParaAdjust, uno::Any(eAdjust));
2185                         }
2186                     }
2187 
2188                     // tdf#144092 For empty textboxes push character styles &
2189                     // endParaRPr into the Shape's properties
2190                     if (rParagraphs.size() == 1 && pParagraph->getRuns().empty())
2191                     {
2192                         TextCharacterProperties aTextCharacterProps{ pParagraph->getCharacterStyle(
2193                             aCharStyleProperties, *mpMasterTextListStyle,
2194                             getTextBody()->getTextListStyle()) };
2195                         aTextCharacterProps.assignUsed(pParagraph->getEndProperties());
2196                         aTextCharacterProps.pushToPropSet(aPropertySet, rFilterBase);
2197                     }
2198                 }
2199 
2200                 // MS Office has e.g. fill and stroke of WordArt in the character properties,
2201                 // LibreOffice uses shape properties.
2202                 if (!mpTextBody->getTextProperties().msPrst.isEmpty()
2203                     && mpTextBody->getTextProperties().msPrst != u"textNoShape")
2204                 {
2205                     lcl_copyCharPropsToShape(mxShape, mpTextBody, rFilterBase);
2206                 }
2207             }
2208         }
2209         else if (mbTextBox)
2210         {
2211             // No drawingML text, but WPS text is expected: save the theme
2212             // character color on the shape, then.
2213             if(const ShapeStyleRef* pFontRef = getShapeStyleRef(XML_fontRef))
2214             {
2215                 ::Color nCharColor = pFontRef->maPhClr.getColor(rGraphicHelper);
2216                 aPropertySet.setAnyProperty(PROP_CharColor, uno::Any(nCharColor));
2217             }
2218         }
2219 
2220         // Set glow effect properties
2221         if (aEffectProperties.maGlow.moGlowRad.has_value()
2222             && aServiceName != "com.sun.star.drawing.GroupShape")
2223         {
2224             uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
2225             propertySet->setPropertyValue(u"GlowEffectRadius"_ustr, Any(convertEmuToHmm(aEffectProperties.maGlow.moGlowRad.value())));
2226             propertySet->setPropertyValue(u"GlowEffectColor"_ustr, Any(aEffectProperties.maGlow.moGlowColor.getColor(rGraphicHelper)));
2227             propertySet->setPropertyValue(u"GlowEffectTransparency"_ustr, Any(aEffectProperties.maGlow.moGlowColor.getTransparency()));
2228         }
2229 
2230         // Set soft edge effect properties
2231         if (aEffectProperties.maSoftEdge.moRad.has_value())
2232         {
2233             uno::Reference<beans::XPropertySet> propertySet(mxShape, uno::UNO_QUERY);
2234             propertySet->setPropertyValue(
2235                 u"SoftEdgeRadius"_ustr, Any(convertEmuToHmm(aEffectProperties.maSoftEdge.moRad.value())));
2236         }
2237 
2238         // Set text glow effect for shapes
2239         if (mpTextBody && (!pPlaceholder || !mpTextBody->isEmpty()))
2240         {
2241             const TextParagraphVector& rParagraphs = mpTextBody->getParagraphs();
2242             if (!rParagraphs.empty())
2243             {
2244                 EffectProperties aTextEffectProperties;
2245                 for (TextParagraphVector::const_iterator aPIt = rParagraphs.begin(), aPEnd = rParagraphs.end(); aPIt != aPEnd; ++aPIt)
2246                 {
2247                     const TextParagraph& rTextPara = **aPIt;
2248                     const TextCharacterProperties & rParaProps = rTextPara.getProperties().getTextCharacterProperties();
2249                     if (rParaProps.getEffectProperties().maGlow.moGlowRad.has_value())
2250                     {
2251                         aTextEffectProperties.assignUsed(rParaProps.getEffectProperties());
2252                         goto found;
2253                     }
2254                     else
2255                     {
2256                         for (TextRunVector::const_iterator aRIt = rTextPara.getRuns().begin(), aREnd = rTextPara.getRuns().end(); aRIt != aREnd; ++aRIt)
2257                         {
2258                             const TextRun& rTextRun = **aRIt;
2259                             const TextCharacterProperties& rRunrops = rTextRun.getTextCharacterProperties();
2260                             if (rRunrops.getEffectProperties().maGlow.moGlowRad.has_value())
2261                             {
2262                                 aTextEffectProperties.assignUsed(rRunrops.getEffectProperties());
2263                                 goto found;
2264                             }
2265                         }
2266                     }
2267                 }
2268 
2269             found:
2270                 if (aTextEffectProperties.maGlow.moGlowRad.has_value())
2271                 {
2272                     xSet->setPropertyValue(u"GlowTextEffectRadius"_ustr,
2273                         uno::Any(convertEmuToHmm(aTextEffectProperties.maGlow.moGlowRad.value())));
2274                     xSet->setPropertyValue(u"GlowTextEffectColor"_ustr,
2275                         uno::Any(aTextEffectProperties.maGlow.moGlowColor.getColor(rGraphicHelper)));
2276                     xSet->setPropertyValue(u"GlowTextEffectTransparency"_ustr,
2277                         uno::Any(aTextEffectProperties.maGlow.moGlowColor.getTransparency()));
2278                 }
2279             }
2280         }
2281 
2282         // Set the stroke and fill-color properties of the OLE shape
2283         if (aServiceName == "com.sun.star.drawing.OLE2Shape" && mxOleObjectInfo
2284             && !mxOleObjectInfo->maShapeId.isEmpty())
2285             if (::oox::vml::Drawing* pVmlDrawing = rFilterBase.getVmlDrawing())
2286                 if (const ::oox::vml::ShapeBase* pVmlShape
2287                     = pVmlDrawing->getShapes().getShapeById(mxOleObjectInfo->maShapeId))
2288                 {
2289                     // Apply stroke props from the type model of the related VML shape.
2290                     ShapePropertyMap aPropMap(rFilterBase.getModelObjectHelper());
2291                     pVmlShape->getTypeModel().maStrokeModel.pushToPropMap(
2292                         aPropMap, rFilterBase.getGraphicHelper());
2293                     // And, fill-color properties as well...
2294                     pVmlShape->getTypeModel().maFillModel.pushToPropMap(
2295                         aPropMap, rFilterBase.getGraphicHelper());
2296                     PropertySet(xSet).setProperties(aPropMap);
2297                 }
2298     }
2299 
2300     if (mxShape.is())
2301     {
2302         finalizeXShape( rFilterBase, rxShapes );
2303 
2304         if (mpTextBody)
2305         {
2306             // tdf#151518. The method readjustTextDistances is fix for tdf#148321, but conflicts with
2307             // text position in some of the SmartArt types in Writer. So exclude Writer here.
2308             OUString sDocumentService;
2309             rFilterBase.getMediaDescriptor()[utl::MediaDescriptor::PROP_DOCUMENTSERVICE] >>= sDocumentService;
2310             if (sDocumentService != u"com.sun.star.text.TextDocument")
2311                 mpTextBody->getTextProperties().readjustTextDistances(mxShape);
2312 
2313             // tdf#156857: ooxml files can have shape size with spAutoFit=true and the first priority of
2314             // shape size is the fix size even if TextAutoGrowHeight is true.
2315             bool bAutoHeight = false;
2316             Reference< XPropertySetInfo > xSetInfo(xSet->getPropertySetInfo());
2317             const OUString& rPropName = PropertyMap::getPropertyName(PROP_TextAutoGrowHeight);
2318             if (xSetInfo.is() && xSetInfo->hasPropertyByName(rPropName))
2319             {
2320                 uno::Any aTextAutoGrowHeight = xSet->getPropertyValue(u"TextAutoGrowHeight"_ustr);
2321                 aTextAutoGrowHeight >>= bAutoHeight;
2322             }
2323 
2324             SdrObject* pShape = SdrObject::getSdrObjectFromXShape(mxShape);
2325             if (pShape && bAutoHeight)
2326             {
2327                 tools::Rectangle aAutoSize = pShape->GetLogicRect();
2328                 // little tolerance same as in \svx\source\svdraw\svdoashp.cxx:AdjustTextFrameWidthAndHeight
2329                 if (!aOrigSize.IsEmpty() && (std::abs(aOrigSize.GetHeight() - aAutoSize.GetHeight()) > 1 ||
2330                     std::abs(aOrigSize.GetWidth() - aAutoSize.GetWidth()) > 1))
2331                 {
2332                     pShape->NbcSetLogicRect(aOrigSize, false);
2333                 }
2334             }
2335         }
2336     }
2337     return mxShape;
2338 }
2339 
keepDiagramDrawing(XmlFilterBase & rFilterBase,const OUString & rFragmentPath)2340 void Shape::keepDiagramDrawing(XmlFilterBase& rFilterBase, const OUString& rFragmentPath)
2341 {
2342 
2343     sal_Int32 length = maDiagramDoms.getLength();
2344     maDiagramDoms.realloc(length + 1);
2345 
2346     // drawingValue[0] => dom, drawingValue[1] => Sequence of associated relationships
2347     uno::Sequence<uno::Any> diagramDrawing{
2348         uno::Any(rFilterBase.importFragment(rFragmentPath)),
2349         uno::Any(resolveRelationshipsOfTypeFromOfficeDoc(rFilterBase, rFragmentPath, u"image"))
2350     };
2351 
2352     beans::PropertyValue* pValue = maDiagramDoms.getArray();
2353     pValue[length].Name = "OOXDrawing";
2354     pValue[length].Value <<= diagramDrawing;
2355 }
2356 
keepDiagramCompatibilityInfo()2357 void Shape::keepDiagramCompatibilityInfo()
2358 {
2359     try
2360     {
2361         if( !maDiagramDoms.hasElements() )
2362             return;
2363 
2364         Reference < XPropertySet > xSet( mxShape, UNO_QUERY_THROW );
2365         Reference < XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2366         if ( !xSetInfo.is() )
2367             return;
2368 
2369         const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2370         if( !xSetInfo->hasPropertyByName( aGrabBagPropName ) )
2371             return;
2372 
2373         Sequence < PropertyValue > aGrabBag;
2374         xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2375 
2376         // We keep the previous items, if present
2377         if ( aGrabBag.hasElements() )
2378             xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, maDiagramDoms) ) );
2379         else
2380             xSet->setPropertyValue( aGrabBagPropName, Any( maDiagramDoms ) );
2381     }
2382     catch( const Exception& )
2383     {
2384         TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::keepDiagramCompatibilityInfo" );
2385     }
2386 }
2387 
convertSmartArtToMetafile(XmlFilterBase const & rFilterBase)2388 void Shape::convertSmartArtToMetafile(XmlFilterBase const & rFilterBase)
2389 {
2390     try
2391     {
2392         Reference<XPropertySet> xSet(mxShape, UNO_QUERY_THROW);
2393 
2394         xSet->setPropertyValue(u"MoveProtect"_ustr, Any(true));
2395         xSet->setPropertyValue(u"SizeProtect"_ustr, Any(true));
2396 
2397         // Replace existing shapes with a new Graphic Object rendered
2398         // from them
2399         Reference<XShape> xShape(renderDiagramToGraphic(rFilterBase));
2400         Reference<XShapes> xShapes(mxShape, UNO_QUERY_THROW);
2401         tools::Rectangle aBackgroundRect
2402             = SdrObject::getSdrObjectFromXShape(
2403                   Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW))
2404                   ->GetLogicRect();
2405         while (xShapes->hasElements())
2406             xShapes->remove(Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW));
2407         xShapes->add(xShape);
2408         SdrObject::getSdrObjectFromXShape(
2409             Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW))
2410             ->NbcSetLogicRect(aBackgroundRect);
2411     }
2412     catch (const Exception&)
2413     {
2414         TOOLS_WARN_EXCEPTION("oox.drawingml", "Shape::convertSmartArtToMetafile");
2415     }
2416 }
2417 
renderDiagramToGraphic(XmlFilterBase const & rFilterBase)2418 Reference < XShape > Shape::renderDiagramToGraphic( XmlFilterBase const & rFilterBase )
2419 {
2420     Reference< XShape > xShape;
2421 
2422     try
2423     {
2424         if( !maDiagramDoms.hasElements() )
2425             return xShape;
2426 
2427         // Stream in which to place the rendered shape
2428         SvMemoryStream aTempStream;
2429         Reference < io::XStream > xStream( new utl::OStreamWrapper( aTempStream ) );
2430         Reference < io::XOutputStream > xOutputStream( xStream->getOutputStream() );
2431 
2432         // Size of the rendering
2433         awt::Size aActualSize = mxShape->getSize();
2434         Size aResolution(Application::GetDefaultDevice()->LogicToPixel(Size(100, 100), MapMode(MapUnit::MapCM)));
2435         double fPixelsPer100thmm = static_cast < double > ( aResolution.Width() ) / 100000.0;
2436         awt::Size aSize( static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Width ) + 0.5 ),
2437                          static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Height ) + 0.5 ) );
2438 
2439         Sequence< PropertyValue > aFilterData{
2440             comphelper::makePropertyValue(u"PixelWidth"_ustr, aSize.Width),
2441             comphelper::makePropertyValue(u"PixelHeight"_ustr, aSize.Height),
2442             comphelper::makePropertyValue(u"LogicalWidth"_ustr, aActualSize.Width),
2443             comphelper::makePropertyValue(u"LogicalHeight"_ustr, aActualSize.Height)
2444         };
2445 
2446         Sequence < PropertyValue > aDescriptor{
2447             comphelper::makePropertyValue(u"OutputStream"_ustr, xOutputStream),
2448             comphelper::makePropertyValue(u"FilterName"_ustr, u"SVM"_ustr), // Rendering format
2449             comphelper::makePropertyValue(u"FilterData"_ustr, aFilterData)
2450         };
2451 
2452         Reference < lang::XComponent > xSourceDoc( mxShape, UNO_QUERY_THROW );
2453         Reference < XGraphicExportFilter > xGraphicExporter = GraphicExportFilter::create( rFilterBase.getComponentContext() );
2454         xGraphicExporter->setSourceDocument( xSourceDoc );
2455         xGraphicExporter->filter( aDescriptor );
2456 
2457         aTempStream.Seek( STREAM_SEEK_TO_BEGIN );
2458 
2459         Graphic aGraphic;
2460         GraphicFilter aFilter;
2461         if ( aFilter.ImportGraphic( aGraphic, u"", aTempStream, GRFILTER_FORMAT_NOTFOUND, nullptr, GraphicFilterImportFlags::NONE ) != ERRCODE_NONE )
2462         {
2463             SAL_WARN( "oox.drawingml", "Shape::renderDiagramToGraphic: Unable to import rendered stream into graphic object" );
2464             return xShape;
2465         }
2466 
2467         Reference < graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() );
2468         Reference < lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
2469         xShape.set( xServiceFact->createInstance( u"com.sun.star.drawing.GraphicObjectShape"_ustr ), UNO_QUERY_THROW );
2470         Reference < XPropertySet > xPropSet( xShape, UNO_QUERY_THROW );
2471         xPropSet->setPropertyValue(  u"Graphic"_ustr, Any( xGraphic ) );
2472         xPropSet->setPropertyValue(  u"MoveProtect"_ustr, Any( true ) );
2473         xPropSet->setPropertyValue(  u"SizeProtect"_ustr, Any( true ) );
2474         xPropSet->setPropertyValue(  u"Name"_ustr, Any( u"RenderedShapes"_ustr ) );
2475     }
2476     catch( const Exception& )
2477     {
2478         TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::renderDiagramToGraphic" );
2479     }
2480 
2481     return xShape;
2482 }
2483 
setTextBody(const TextBodyPtr & pTextBody)2484 void Shape::setTextBody(const TextBodyPtr & pTextBody)
2485 {
2486     mpTextBody = pTextBody;
2487 }
2488 
setMasterTextListStyle(const TextListStylePtr & pMasterTextListStyle)2489 void Shape::setMasterTextListStyle( const TextListStylePtr& pMasterTextListStyle )
2490 {
2491     SAL_INFO("oox.drawingml", "Shape::setMasterTextListStyle: Set master text list style to shape id='" << msId << "'");
2492 
2493     mpMasterTextListStyle = pMasterTextListStyle;
2494 }
2495 
finalizeServiceName(XmlFilterBase & rFilter,const OUString & rServiceName,const awt::Rectangle & rShapeRect)2496 OUString Shape::finalizeServiceName( XmlFilterBase& rFilter, const OUString& rServiceName, const awt::Rectangle& rShapeRect )
2497 {
2498     OUString aServiceName = rServiceName;
2499     switch( meFrameType )
2500     {
2501         case FRAMETYPE_OLEOBJECT:
2502         {
2503             awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
2504             if( rFilter.getOleObjectHelper().importOleObject( maShapeProperties, *mxOleObjectInfo, aOleSize ) )
2505                 aServiceName = "com.sun.star.drawing.OLE2Shape";
2506 
2507             // get the path to the representation graphic
2508             OUString aGraphicPath;
2509             if( !mxOleObjectInfo->maShapeId.isEmpty() )
2510                 if( ::oox::vml::Drawing* pVmlDrawing = rFilter.getVmlDrawing() )
2511                     if( const ::oox::vml::ShapeBase* pVmlShape = pVmlDrawing->getShapes().getShapeById( mxOleObjectInfo->maShapeId ) )
2512                         aGraphicPath = pVmlShape->getGraphicPath();
2513 
2514             // import and store the graphic
2515             if( !aGraphicPath.isEmpty() )
2516             {
2517                 // Transfer shape's width and height to graphicsfilter (can be used by WMF/EMF)
2518                 WmfExternal aExtHeader;
2519                 aExtHeader.mapMode = 8; // MM_ANISOTROPIC
2520                 aExtHeader.xExt = rShapeRect.Width;
2521                 aExtHeader.yExt = rShapeRect.Height;
2522 
2523                 Reference< graphic::XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath, &aExtHeader );
2524                 if( xGraphic.is() )
2525                     maShapeProperties.setProperty(PROP_Graphic, xGraphic);
2526             }
2527         }
2528         break;
2529 
2530         default:;
2531     }
2532     return aServiceName;
2533 }
2534 
finalizeXShape(XmlFilterBase & rFilter,const Reference<XShapes> & rxShapes)2535 void Shape::finalizeXShape( XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes )
2536 {
2537     switch( meFrameType )
2538     {
2539         case FRAMETYPE_CHART:
2540         {
2541             OSL_ENSURE( !mxChartShapeInfo->maFragmentPath.isEmpty(), "Shape::finalizeXShape - missing chart fragment" );
2542             if( mxShape.is() && !mxChartShapeInfo->maFragmentPath.isEmpty() ) try
2543             {
2544                 // set the chart2 OLE class ID at the OLE shape
2545                 PropertySet aShapeProp( mxShape );
2546                 aShapeProp.setProperty( PROP_CLSID, u"12dcae26-281f-416f-a234-c3086127382e"_ustr );
2547 
2548                 // get the XModel interface of the embedded object from the OLE shape
2549                 Reference< frame::XModel > xDocModel;
2550                 aShapeProp.getProperty( xDocModel, PROP_Model );
2551                 Reference< chart2::XChartDocument > xChartDoc( xDocModel, UNO_QUERY_THROW );
2552 
2553                 // load the chart data from the XML fragment
2554 #if ENABLE_WASM_STRIP_CHART
2555                 (void) rFilter;
2556                 (void) rxShapes;
2557 #else
2558                 // WASM_CHART change
2559                 // TODO: Instead of using convertFromModel an alternative may be
2560                 // added to convert not to Chart/OLE SdrObejct, but to GraphicObject
2561                 // with the Chart visualization. There should be a preview available
2562                 // in the imported chart data
2563                 bool bMSO2007Doc = rFilter.isMSO2007Document();
2564                 chart::ChartSpaceModel aModel(bMSO2007Doc);
2565                 oox::ppt::PowerPointImport* pPowerPointImport
2566                     = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilter);
2567 
2568                 ClrMapPtr pClrMap; // The original color map
2569                 if (pPowerPointImport)
2570                 {
2571                     // Use a copy of current color map, which the fragment may override locally
2572                     pClrMap = pPowerPointImport->getActualSlidePersist()->getClrMap();
2573                     aModel.mpClrMap = pClrMap ? std::make_shared<ClrMap>(*pClrMap)
2574                                               : std::make_shared<ClrMap>();
2575                     pPowerPointImport->getActualSlidePersist()->setClrMap(aModel.mpClrMap);
2576                 }
2577 
2578                 rtl::Reference<chart::ChartSpaceFragment> pChartSpaceFragment = new chart::ChartSpaceFragment(
2579                         rFilter, mxChartShapeInfo->maFragmentPath, aModel );
2580                 const OUString aThemeOverrideFragmentPath( pChartSpaceFragment->
2581                         getFragmentPathFromFirstTypeFromOfficeDoc(u"themeOverride") );
2582                 rFilter.importFragment( pChartSpaceFragment );
2583 
2584                 // The original theme.
2585                 ThemePtr pTheme;
2586 
2587                 if (!aThemeOverrideFragmentPath.isEmpty() && pPowerPointImport)
2588                 {
2589                     // Handle theme override.
2590                     uno::Reference< xml::sax::XFastSAXSerializable > xDoc(
2591                             rFilter.importFragment(aThemeOverrideFragmentPath), uno::UNO_QUERY_THROW);
2592                     pTheme = pPowerPointImport->getActualSlidePersist()->getTheme();
2593                     auto pThemeOverride = std::make_shared<Theme>(*pTheme);
2594                     rFilter.importFragment(
2595                         new ThemeOverrideFragmentHandler(rFilter, aThemeOverrideFragmentPath, *pThemeOverride, *pThemeOverride->getTheme()),
2596                         xDoc);
2597                     pPowerPointImport->getActualSlidePersist()->setTheme(pThemeOverride);
2598                 }
2599 
2600                 // convert imported chart model to chart document
2601                 Reference< drawing::XShapes > xExternalPage;
2602                 if( !mxChartShapeInfo->mbEmbedShapes )
2603                     xExternalPage = rxShapes;
2604                 if( rFilter.getChartConverter() )
2605                 {
2606                     rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
2607                     if( !xChartDoc->hasInternalDataProvider() )
2608                     {
2609                         Reference< chart2::data::XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
2610                         Reference< chart2::data::XDataSource > xData = xDataRec->getUsedData();
2611                         if( !xData->getDataSequences().hasElements() || !xData->getDataSequences()[0]->getValues().is() ||
2612                                 !xData->getDataSequences()[0]->getValues()->getData().hasElements() )
2613                         {
2614                             rFilter.useInternalChartDataTable( true );
2615                             rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
2616                             rFilter.useInternalChartDataTable( false );
2617                         }
2618                     }
2619 
2620                 }
2621 
2622                 if (pPowerPointImport)
2623                 {
2624                     if (!aThemeOverrideFragmentPath.isEmpty())
2625                     {
2626                         // Restore the original theme.
2627                         pPowerPointImport->getActualSlidePersist()->setTheme(pTheme);
2628                     }
2629                     // Restore the original color map
2630                     pPowerPointImport->getActualSlidePersist()->setClrMap(std::move(pClrMap));
2631                 }
2632 #endif
2633             }
2634             catch( Exception& )
2635             {
2636             }
2637         }
2638         break;
2639 
2640         default:;
2641     }
2642 }
2643 
putPropertyToGrabBag(const OUString & sPropertyName,const Any & aPropertyValue)2644 void Shape::putPropertyToGrabBag( const OUString& sPropertyName, const Any& aPropertyValue )
2645 {
2646     PropertyValue aNewProperty;
2647     aNewProperty.Name = sPropertyName;
2648     aNewProperty.Value = aPropertyValue;
2649     putPropertyToGrabBag( aNewProperty );
2650 }
2651 
putPropertyToGrabBag(const PropertyValue & pProperty)2652 void Shape::putPropertyToGrabBag( const PropertyValue& pProperty )
2653 {
2654     Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2655     Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2656     const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2657     if( mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName ) )
2658     {
2659         Sequence< PropertyValue > aGrabBag;
2660         xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2661 
2662         sal_Int32 length = aGrabBag.getLength();
2663         aGrabBag.realloc( length + 1 );
2664         aGrabBag.getArray()[length] = pProperty;
2665 
2666         xSet->setPropertyValue( aGrabBagPropName, Any( aGrabBag ) );
2667     }
2668 }
2669 
putPropertiesToGrabBag(const Sequence<PropertyValue> & aProperties)2670 void Shape::putPropertiesToGrabBag( const Sequence< PropertyValue >& aProperties )
2671 {
2672     Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2673     Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2674     const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2675     if( !(mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName )) )
2676         return;
2677 
2678     // get existing grab bag
2679     Sequence< PropertyValue > aGrabBag;
2680     xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2681 
2682     std::vector<PropertyValue> aVec;
2683     aVec.reserve(aProperties.getLength());
2684 
2685     // put the new items
2686     std::transform(aProperties.begin(), aProperties.end(), std::back_inserter(aVec),
2687         [](const PropertyValue& rProp) {
2688             PropertyValue aProp;
2689             aProp.Name = rProp.Name;
2690             aProp.Value = rProp.Value;
2691             return aProp;
2692         });
2693 
2694     // put it back to the shape
2695     xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, aVec) ) );
2696 }
2697 
getActualFillProperties(const Theme * pTheme,const FillProperties * pParentShapeFillProps) const2698 FillProperties Shape::getActualFillProperties(const Theme* pTheme, const FillProperties* pParentShapeFillProps) const
2699 {
2700     FillProperties aFillProperties;
2701     aFillProperties.moFillType = XML_noFill;
2702 
2703     // Reference shape properties
2704     aFillProperties.assignUsed( *mpShapeRefFillPropPtr );
2705 
2706     // Theme
2707     if( pTheme != nullptr )
2708     {
2709         if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
2710         {
2711             if( const FillProperties* pFillProps = pTheme->getFillStyle( pFillRef->mnThemedIdx ) )
2712                 aFillProperties.assignUsed( *pFillProps );
2713         }
2714     }
2715 
2716     // Properties specified directly for this shape
2717     aFillProperties.assignUsed(getFillProperties());
2718 
2719     // Parent shape's properties
2720     if ( pParentShapeFillProps != nullptr)
2721         if( getFillProperties().moFillType.has_value() && getFillProperties().moFillType.value() == XML_grpFill )
2722             aFillProperties.assignUsed( *pParentShapeFillProps );
2723 
2724     return aFillProperties;
2725 }
2726 
getActualLineProperties(const Theme * pTheme) const2727 LineProperties Shape::getActualLineProperties(const Theme* pTheme) const
2728 {
2729     LineProperties aLineProperties;
2730     aLineProperties.maLineFill.moFillType = XML_noFill;
2731 
2732     // Reference shape properties
2733     aLineProperties.assignUsed( *mpShapeRefLinePropPtr );
2734 
2735     // Theme
2736     if( pTheme != nullptr )
2737     {
2738         if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
2739         {
2740             if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
2741                 aLineProperties.assignUsed( *pLineProps );
2742         }
2743     }
2744 
2745     // Properties specified directly for this shape
2746     aLineProperties.assignUsed( getLineProperties() );
2747 
2748     return aLineProperties;
2749 }
2750 
getActualEffectProperties(const Theme * pTheme) const2751 EffectProperties Shape::getActualEffectProperties(const Theme* pTheme) const
2752 {
2753     EffectProperties aEffectProperties;
2754 
2755     // Reference shape properties
2756     aEffectProperties.assignUsed( *mpShapeRefEffectPropPtr );
2757 
2758     // Theme
2759     if( pTheme != nullptr )
2760     {
2761         if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
2762         {
2763             if( const EffectProperties* pEffectProps = pTheme->getEffectStyle( pEffectRef->mnThemedIdx ) )
2764                 aEffectProperties.assignUsed( *pEffectProps );
2765         }
2766     }
2767 
2768     // Properties specified directly for this shape
2769     aEffectProperties.assignUsed ( getEffectProperties() );
2770 
2771     return aEffectProperties;
2772 }
2773 
resolveRelationshipsOfTypeFromOfficeDoc(core::XmlFilterBase & rFilter,const OUString & sFragment,std::u16string_view sType)2774 uno::Sequence< uno::Sequence< uno::Any > >  Shape::resolveRelationshipsOfTypeFromOfficeDoc(core::XmlFilterBase& rFilter, const OUString& sFragment, std::u16string_view sType )
2775 {
2776     uno::Sequence< uno::Sequence< uno::Any > > xRelListTemp;
2777     sal_Int32 counter = 0;
2778 
2779     core::RelationsRef xRels = rFilter.importRelations( sFragment );
2780     if ( xRels )
2781     {
2782         core::RelationsRef xImageRels = xRels->getRelationsFromTypeFromOfficeDoc( sType );
2783         if ( xImageRels )
2784         {
2785             xRelListTemp.realloc( xImageRels->size() );
2786             auto pxRelListTemp = xRelListTemp.getArray();
2787             for (auto const& imageRel : *xImageRels)
2788             {
2789                 uno::Sequence< uno::Any > diagramRelTuple (3);
2790                 auto pdiagramRelTuple = diagramRelTuple.getArray();
2791                 // [0] => RID, [1] => InputStream [2] => extension
2792                 OUString sRelId = imageRel.second.maId;
2793 
2794                 pdiagramRelTuple[0] <<= sRelId;
2795                 OUString sTarget = xImageRels->getFragmentPathFromRelId( sRelId );
2796 
2797                 uno::Reference< io::XInputStream > xImageInputStrm( rFilter.openInputStream( sTarget ), uno::UNO_SET_THROW );
2798                 StreamDataSequence dataSeq;
2799                 if ( rFilter.importBinaryData( dataSeq, sTarget ) )
2800                 {
2801                     pdiagramRelTuple[1] <<= dataSeq;
2802                 }
2803 
2804                 pdiagramRelTuple[2] <<= sTarget.copy( sTarget.lastIndexOf(".") );
2805 
2806                 pxRelListTemp[counter] = std::move(diagramRelTuple);
2807                 ++counter;
2808             }
2809             xRelListTemp.realloc(counter);
2810 
2811         }
2812     }
2813     return xRelListTemp;
2814 }
2815 
cloneFillProperties()2816 void Shape::cloneFillProperties()
2817 {
2818     auto pFillProperties = std::make_shared<FillProperties>();
2819     pFillProperties->assignUsed(*mpFillPropertiesPtr);
2820     mpFillPropertiesPtr = std::move(pFillProperties);
2821 }
2822 }
2823 
2824 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2825