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