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