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