Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / oox / source / drawingml / shape.cxx
blobcbfc2dae2dca73a16288a80747af5f65e2e1bb1f
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 "effectproperties.hxx"
32 #include <oox/drawingml/shapepropertymap.hxx>
33 #include <drawingml/textbody.hxx>
34 #include <drawingml/textparagraph.hxx>
35 #include <drawingml/ThemeOverrideFragmentHandler.hxx>
36 #include <drawingml/table/tableproperties.hxx>
37 #include <oox/drawingml/chart/chartconverter.hxx>
38 #include <drawingml/chart/chartspacefragment.hxx>
39 #include <drawingml/chart/chartspacemodel.hxx>
40 #include <o3tl/safeint.hxx>
41 #include <o3tl/unit_conversion.hxx>
42 #include <oox/ppt/pptimport.hxx>
43 #include <oox/vml/vmldrawing.hxx>
44 #include <oox/vml/vmlshape.hxx>
45 #include <oox/vml/vmlshapecontainer.hxx>
46 #include <oox/core/xmlfilterbase.hxx>
47 #include <oox/helper/graphichelper.hxx>
48 #include <oox/helper/propertyset.hxx>
49 #include <oox/helper/modelobjecthelper.hxx>
50 #include <oox/mathml/imexport.hxx>
51 #include <oox/mathml/importutils.hxx>
52 #include <oox/token/properties.hxx>
53 #include "diagram/datamodel.hxx"
54 #include "diagram/diagramhelper.hxx"
56 #include <comphelper/classids.hxx>
57 #include <comphelper/propertysequence.hxx>
58 #include <comphelper/propertyvalue.hxx>
59 #include <comphelper/sequence.hxx>
60 #include <comphelper/diagnose_ex.hxx>
61 #include <tools/gen.hxx>
62 #include <tools/globname.hxx>
63 #include <tools/mapunit.hxx>
64 #include <editeng/unoprnms.hxx>
65 #include <com/sun/star/awt/FontSlant.hpp>
66 #include <com/sun/star/awt/Size.hpp>
67 #include <com/sun/star/awt/XBitmap.hpp>
68 #include <com/sun/star/awt/FontWeight.hpp>
69 #include <com/sun/star/graphic/XGraphic.hpp>
70 #include <com/sun/star/container/XNamed.hpp>
71 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
72 #include <com/sun/star/xml/dom/XDocument.hpp>
73 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
74 #include <com/sun/star/drawing/FillStyle.hpp>
75 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
76 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
77 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
78 #include <com/sun/star/drawing/XShapes.hpp>
79 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
80 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
81 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
82 #include <com/sun/star/drawing/ConnectorType.hpp>
83 #include <com/sun/star/embed/XEmbeddedObject.hpp>
84 #include <com/sun/star/text/XText.hpp>
85 #include <com/sun/star/table/BorderLine2.hpp>
86 #include <com/sun/star/table/ShadowFormat.hpp>
87 #include <com/sun/star/chart2/XChartDocument.hpp>
88 #include <com/sun/star/style/ParagraphAdjust.hpp>
89 #include <com/sun/star/io/XOutputStream.hpp>
90 #include <com/sun/star/lang/Locale.hpp>
91 #include <com/sun/star/i18n/ScriptType.hpp>
93 #include <basegfx/point/b2dpoint.hxx>
94 #include <basegfx/polygon/b2dpolygon.hxx>
95 #include <basegfx/matrix/b2dhommatrix.hxx>
96 #include <com/sun/star/document/XActionLockable.hpp>
97 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
98 #include <com/sun/star/text/GraphicCrop.hpp>
99 #include <svx/svdobj.hxx>
100 #include <svx/svdotable.hxx>
101 #include <svx/svdtrans.hxx>
102 #include <tools/stream.hxx>
103 #include <unotools/streamwrap.hxx>
104 #include <unotools/fltrcfg.hxx>
105 #include <unotools/mediadescriptor.hxx>
106 #include <vcl/graph.hxx>
107 #include <vcl/graphicfilter.hxx>
108 #include <vcl/svapp.hxx>
109 #include <vcl/wmfexternal.hxx>
110 #include <sal/log.hxx>
111 #include <svx/sdtaitm.hxx>
112 #include <oox/drawingml/diagram/diagram.hxx>
113 #include <docmodel/theme/Theme.hxx>
114 #include <i18nlangtag/languagetag.hxx>
115 #include <i18nlangtag/mslangid.hxx>
117 using namespace ::oox::core;
118 using namespace ::com::sun::star;
119 using namespace ::com::sun::star::uno;
120 using namespace ::com::sun::star::beans;
121 using namespace ::com::sun::star::frame;
122 using namespace ::com::sun::star::text;
123 using namespace ::com::sun::star::drawing;
124 using namespace ::com::sun::star::style;
126 namespace oox::drawingml {
128 Shape::Shape( const char* pServiceName, bool bDefaultHeight )
129 : mpLinePropertiesPtr( std::make_shared<LineProperties>() )
130 , mpShapeRefLinePropPtr( std::make_shared<LineProperties>() )
131 , mpFillPropertiesPtr( std::make_shared<FillProperties>() )
132 , mpShapeRefFillPropPtr( std::make_shared<FillProperties>() )
133 , mpGraphicPropertiesPtr( std::make_shared<GraphicProperties>() )
134 , mpCustomShapePropertiesPtr( std::make_shared<CustomShapeProperties>() )
135 , mp3DPropertiesPtr( std::make_shared<Shape3DProperties>() )
136 , mpEffectPropertiesPtr( std::make_shared<EffectProperties>() )
137 , mpShapeRefEffectPropPtr( std::make_shared<EffectProperties>() )
138 , mpMasterTextListStyle( std::make_shared<TextListStyle>() )
139 , mnSubType( 0 )
140 , meFrameType( FRAMETYPE_GENERIC )
141 , mnRotation( 0 )
142 , mnDiagramRotation( 0 )
143 , mbFlipH( false )
144 , mbFlipV( false )
145 , mbHidden( false )
146 , mbHiddenMasterShape( false )
147 , mbLocked( false )
148 , mbWPGChild(false)
149 , mbLockedCanvas( false )
150 , mbWps( false )
151 , mbTextBox( false )
152 , mbHasLinkedTxbx( false )
153 , maDiagramDoms( 0 )
154 , mpDiagramHelper( nullptr )
156 if ( pServiceName )
157 msServiceName = OUString::createFromAscii( pServiceName );
158 setDefaults(bDefaultHeight);
161 Shape::Shape( const ShapePtr& pSourceShape )
162 : mpTextBody(pSourceShape->mpTextBody)
163 , mpLinePropertiesPtr( pSourceShape->mpLinePropertiesPtr )
164 , mpShapeRefLinePropPtr( pSourceShape->mpShapeRefLinePropPtr )
165 , mpFillPropertiesPtr( pSourceShape->mpFillPropertiesPtr )
166 , mpShapeRefFillPropPtr( pSourceShape->mpShapeRefFillPropPtr )
167 , mpGraphicPropertiesPtr( pSourceShape->mpGraphicPropertiesPtr )
168 , mpCustomShapePropertiesPtr( pSourceShape->mpCustomShapePropertiesPtr )
169 , mpTablePropertiesPtr( pSourceShape->mpTablePropertiesPtr )
170 , mp3DPropertiesPtr( pSourceShape->mp3DPropertiesPtr )
171 , mpEffectPropertiesPtr (pSourceShape->mpEffectPropertiesPtr)
172 , mpShapeRefEffectPropPtr(pSourceShape->mpShapeRefEffectPropPtr)
173 , maShapeProperties( pSourceShape->maShapeProperties )
174 , mpMasterTextListStyle( pSourceShape->mpMasterTextListStyle )
175 , msServiceName( pSourceShape->msServiceName )
176 , msName( pSourceShape->msName )
177 , msInternalName( pSourceShape->msInternalName )
178 , msId( pSourceShape->msId )
179 , mnSubType( pSourceShape->mnSubType )
180 , moSubTypeIndex( pSourceShape->moSubTypeIndex )
181 , maShapeStyleRefs( pSourceShape->maShapeStyleRefs )
182 , maSize( pSourceShape->maSize )
183 , maPosition( pSourceShape->maPosition )
184 , meFrameType( pSourceShape->meFrameType )
185 , mnRotation( pSourceShape->mnRotation )
186 , mnDiagramRotation( pSourceShape->mnDiagramRotation )
187 , mbFlipH( pSourceShape->mbFlipH )
188 , mbFlipV( pSourceShape->mbFlipV )
189 , mbHidden( pSourceShape->mbHidden )
190 , mbHiddenMasterShape( pSourceShape->mbHiddenMasterShape )
191 , mbLocked( pSourceShape->mbLocked )
192 , mbWPGChild( pSourceShape->mbWPGChild )
193 , mbLockedCanvas( pSourceShape->mbLockedCanvas )
194 , mbWps( pSourceShape->mbWps )
195 , mbTextBox( pSourceShape->mbTextBox )
196 , mbHasLinkedTxbx(false)
197 , maDiagramDoms( pSourceShape->maDiagramDoms )
198 , mnZOrder(pSourceShape->mnZOrder)
199 , mnZOrderOff(pSourceShape->mnZOrderOff)
200 , mnDataNodeType(pSourceShape->mnDataNodeType)
201 , mfAspectRatio(pSourceShape->mfAspectRatio)
202 , mpDiagramHelper( nullptr )
203 , msDiagramDataModelID(pSourceShape->msDiagramDataModelID)
206 Shape::~Shape()
208 // DiagramHelper should not be set here anymore, see
209 // propagateDiagramHelper below (maybe assert..?)
210 delete mpDiagramHelper;
213 void Shape::prepareDiagramHelper(
214 const std::shared_ptr< Diagram >& rDiagramPtr,
215 const std::shared_ptr<::oox::drawingml::Theme>& rTheme)
217 // Prepare Diagram data collecting for this Shape
218 if( nullptr == mpDiagramHelper && FRAMETYPE_DIAGRAM == meFrameType )
220 mpDiagramHelper = new AdvancedDiagramHelper(
221 rDiagramPtr,
222 rTheme,
223 getSize());
227 void Shape::propagateDiagramHelper()
229 // Propagate collected Diagram data to data holder
230 if (FRAMETYPE_DIAGRAM == meFrameType && nullptr != mpDiagramHelper)
232 SdrObjGroup* pAnchorObj = dynamic_cast<SdrObjGroup*>(SdrObject::getSdrObjectFromXShape(mxShape));
234 if(pAnchorObj)
236 static_cast<AdvancedDiagramHelper*>(mpDiagramHelper)->doAnchor(*pAnchorObj, *this);
237 mpDiagramHelper = nullptr;
241 // If propagation failed, delete/cleanup here. Since the DiagramHelper
242 // holds a Diagram and that this Shape it is necessary - the destructor
243 // will not be called and will be too late
244 if (nullptr != mpDiagramHelper)
246 delete mpDiagramHelper;
247 mpDiagramHelper = nullptr;
251 void Shape::migrateDiagramHelperToNewShape(const ShapePtr& pTarget)
253 if(!mpDiagramHelper)
255 return;
258 if(!pTarget)
260 // no migrate target, but cleanup helper
261 delete mpDiagramHelper;
262 mpDiagramHelper = nullptr;
263 return;
266 if(pTarget->mpDiagramHelper)
268 // this should no happen, but if there is already a helper, clean it up
269 delete pTarget->mpDiagramHelper;
270 pTarget->mpDiagramHelper = nullptr;
273 // exchange and reset to nullptr
274 pTarget->mpDiagramHelper = mpDiagramHelper;
275 mpDiagramHelper = nullptr;
278 table::TablePropertiesPtr const & Shape::getTableProperties()
280 if ( !mpTablePropertiesPtr )
281 mpTablePropertiesPtr = std::make_shared<table::TableProperties>();
282 return mpTablePropertiesPtr;
285 void Shape::setDefaults(bool bHeight)
287 maDefaultShapeProperties.setProperty(PROP_TextAutoGrowHeight, false);
288 maDefaultShapeProperties.setProperty(PROP_TextWordWrap, true);
289 maDefaultShapeProperties.setProperty(PROP_TextLeftDistance, static_cast< sal_Int32 >( 250 ));
290 maDefaultShapeProperties.setProperty(PROP_TextUpperDistance, static_cast< sal_Int32 >( 125 ));
291 maDefaultShapeProperties.setProperty(PROP_TextRightDistance, static_cast< sal_Int32 >( 250 ));
292 maDefaultShapeProperties.setProperty(PROP_TextLowerDistance, static_cast< sal_Int32 >( 125 ));
293 if (bHeight)
294 maDefaultShapeProperties.setProperty(PROP_CharHeight, static_cast< float >( 18.0 ));
295 maDefaultShapeProperties.setProperty(PROP_TextVerticalAdjust, TextVerticalAdjust_TOP);
296 maDefaultShapeProperties.setProperty(PROP_ParaAdjust,
297 static_cast<sal_Int16>(ParagraphAdjust_LEFT));
300 ::oox::vml::OleObjectInfo& Shape::setOleObjectType()
302 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setOleObjectType - multiple frame types" );
303 meFrameType = FRAMETYPE_OLEOBJECT;
304 mxOleObjectInfo = std::make_shared<::oox::vml::OleObjectInfo>( true );
305 return *mxOleObjectInfo;
308 ChartShapeInfo& Shape::setChartType( bool bEmbedShapes )
310 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setChartType - multiple frame types" );
311 meFrameType = FRAMETYPE_CHART;
312 if (mbWps)
313 msServiceName = "com.sun.star.drawing.temporaryForXMLImportOLE2Shape";
314 else
315 msServiceName = "com.sun.star.drawing.OLE2Shape";
316 mxChartShapeInfo = std::make_shared<ChartShapeInfo>( bEmbedShapes );
317 return *mxChartShapeInfo;
320 void Shape::setDiagramType()
322 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setDiagramType - multiple frame types" );
323 meFrameType = FRAMETYPE_DIAGRAM;
324 msServiceName = "com.sun.star.drawing.GroupShape";
325 mnSubType = 0;
328 void Shape::setTableType()
330 OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setTableType - multiple frame types" );
331 meFrameType = FRAMETYPE_TABLE;
332 msServiceName = "com.sun.star.drawing.TableShape";
333 mnSubType = 0;
336 void Shape::setServiceName( const char* pServiceName )
338 if ( pServiceName )
339 msServiceName = OUString::createFromAscii( pServiceName );
342 const ShapeStyleRef* Shape::getShapeStyleRef( sal_Int32 nRefType ) const
344 ShapeStyleRefMap::const_iterator aIt = maShapeStyleRefs.find( nRefType );
345 return (aIt == maShapeStyleRefs.end()) ? nullptr : &aIt->second;
348 void Shape::addShape(
349 ::oox::core::XmlFilterBase& rFilterBase,
350 const Theme* pTheme,
351 const Reference< XShapes >& rxShapes,
352 const basegfx::B2DHomMatrix& aTransformation,
353 const FillProperties& rShapeOrParentShapeFillProps,
354 ShapeIdMap* pShapeMap,
355 oox::drawingml::ShapePtr pParentGroupShape)
357 SAL_INFO("oox.drawingml", "Shape::addShape: id='" << msId << "'");
361 OUString sServiceName( msServiceName );
362 if( !sServiceName.isEmpty() )
364 basegfx::B2DHomMatrix aMatrix( aTransformation );
365 Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, false, false, aMatrix, rShapeOrParentShapeFillProps, pParentGroupShape) );
367 if( pShapeMap && !msId.isEmpty() )
369 (*pShapeMap)[ msId ] = shared_from_this();
372 // if this is a group shape, we have to add also each child shape
373 Reference< XShapes > xShapes( xShape, UNO_QUERY );
374 if ( xShapes.is() )
375 addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aMatrix );
377 if (isWPGChild() && xShape)
379 // This is a wps shape and it is the child of the WPG, now copy the
380 // the text body properties to the xshape.
381 Reference<XPropertySet> xChildWPSProperties(xShape, uno::UNO_QUERY);
383 if (getTextBody() && xChildWPSProperties)
385 xChildWPSProperties->setPropertyValue(
386 UNO_NAME_TEXT_VERTADJUST,
387 uno::Any(getTextBody()->getTextProperties().meVA));
389 xChildWPSProperties->setPropertyValue(
390 UNO_NAME_TEXT_LEFTDIST,
391 uno::Any(getTextBody()->getTextProperties().moInsets[0].has_value()
392 ? *getTextBody()->getTextProperties().moInsets[0]
393 : 0));
394 xChildWPSProperties->setPropertyValue(
395 UNO_NAME_TEXT_UPPERDIST,
396 uno::Any(getTextBody()->getTextProperties().moInsets[1].has_value()
397 ? *getTextBody()->getTextProperties().moInsets[1]
398 : 0));
399 xChildWPSProperties->setPropertyValue(
400 UNO_NAME_TEXT_RIGHTDIST,
401 uno::Any(getTextBody()->getTextProperties().moInsets[2].has_value()
402 ? *getTextBody()->getTextProperties().moInsets[2]
403 : 0));
404 xChildWPSProperties->setPropertyValue(
405 UNO_NAME_TEXT_LOWERDIST,
406 uno::Any(getTextBody()->getTextProperties().moInsets[3].has_value()
407 ? *getTextBody()->getTextProperties().moInsets[3]
408 : 0));
411 // tdf#145147 Set the Hyperlink property to the child wps shape.
412 if (getShapeProperties().hasProperty(PROP_URL)) try
414 uno::Any aAny = getShapeProperties().getProperty(PROP_URL);
415 OUString sUrl = aAny.get<OUString>();
416 if (!sUrl.isEmpty())
417 xChildWPSProperties->setPropertyValue(UNO_NAME_HYPERLINK, aAny);
419 catch (const Exception&)
424 if( meFrameType == FRAMETYPE_DIAGRAM )
426 keepDiagramCompatibilityInfo();
428 // set DiagramHelper at SdrObjGroup
429 propagateDiagramHelper();
431 // Check if this is the PPTX import, so far converting SmartArt to a non-editable
432 // metafile is only implemented for DOCX.
433 bool bPowerPoint = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilterBase) != nullptr;
435 if (!SvtFilterOptions::Get().IsSmartArt2Shape() && !bPowerPoint)
436 convertSmartArtToMetafile( rFilterBase );
439 NamedShapePairs* pNamedShapePairs = rFilterBase.getDiagramFontHeights();
440 if (xShape.is() && pNamedShapePairs)
442 auto itPairs = pNamedShapePairs->find(getInternalName());
443 if (itPairs != pNamedShapePairs->end())
445 auto it = itPairs->second.find(shared_from_this());
446 if (it != itPairs->second.end())
448 // Our drawingml::Shape is in the list of an internal name, remember the now
449 // inserted XShape.
450 it->second = xShape;
456 catch( const Exception& )
458 TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::addShape" );
462 void Shape::setLockedCanvas(bool bLockedCanvas)
464 mbLockedCanvas = bLockedCanvas;
467 void Shape::setWPGChild(bool bWPG)
469 mbWPGChild = bWPG;
472 void Shape::setWps(bool bWps)
474 mbWps = bWps;
477 void Shape::setTextBox(bool bTextBox)
479 mbTextBox = bTextBox;
482 void Shape::applyShapeReference( const Shape& rReferencedShape, bool bUseText )
484 SAL_INFO("oox.drawingml", "Shape::applyShapeReference: apply '" << rReferencedShape.msId << "' to '" << msId << "'");
486 if ( rReferencedShape.mpTextBody && bUseText )
487 mpTextBody = std::make_shared<TextBody>( *rReferencedShape.mpTextBody );
488 else
489 mpTextBody.reset();
490 maShapeProperties = rReferencedShape.maShapeProperties;
491 mpShapeRefLinePropPtr = std::make_shared<LineProperties>( rReferencedShape.getActualLineProperties(nullptr) );
492 mpShapeRefFillPropPtr = std::make_shared<FillProperties>( rReferencedShape.getActualFillProperties(nullptr, nullptr) );
493 mpCustomShapePropertiesPtr = std::make_shared<CustomShapeProperties>( *rReferencedShape.mpCustomShapePropertiesPtr );
494 mpTablePropertiesPtr = rReferencedShape.mpTablePropertiesPtr ? std::make_shared<table::TableProperties>( *rReferencedShape.mpTablePropertiesPtr ) : nullptr;
495 mpShapeRefEffectPropPtr = std::make_shared<EffectProperties>( rReferencedShape.getActualEffectProperties(nullptr) );
496 mpMasterTextListStyle = std::make_shared<TextListStyle>( *rReferencedShape.mpMasterTextListStyle );
497 maSize = rReferencedShape.maSize;
498 maPosition = rReferencedShape.maPosition;
499 mnRotation = rReferencedShape.mnRotation;
500 mbFlipH = rReferencedShape.mbFlipH;
501 mbFlipV = rReferencedShape.mbFlipV;
502 mbHidden = rReferencedShape.mbHidden;
503 mbLocked = rReferencedShape.mbLocked;
506 namespace {
508 struct ActionLockGuard
510 explicit ActionLockGuard(Reference<drawing::XShape> const& xShape)
511 : m_xLockable(xShape, UNO_QUERY)
513 if (m_xLockable.is()) {
514 m_xLockable->addActionLock();
517 ~ActionLockGuard()
519 if (m_xLockable.is()) {
520 m_xLockable->removeActionLock();
523 private:
524 Reference<document::XActionLockable> m_xLockable;
529 // for group shapes, the following method is also adding each child
530 void Shape::addChildren(
531 XmlFilterBase& rFilterBase,
532 Shape& rMaster,
533 const Theme* pTheme,
534 const Reference< XShapes >& rxShapes,
535 ShapeIdMap* pShapeMap,
536 const basegfx::B2DHomMatrix& aTransformation )
538 for (auto const& child : rMaster.maChildren)
540 child->setMasterTextListStyle( mpMasterTextListStyle );
541 child->addShape( rFilterBase, pTheme, rxShapes, aTransformation, getFillProperties(), pShapeMap, rMaster.shared_from_this());
545 static SdrTextHorzAdjust lcl_convertAdjust( ParagraphAdjust eAdjust )
547 if (eAdjust == ParagraphAdjust_LEFT)
548 return SDRTEXTHORZADJUST_LEFT;
549 else if (eAdjust == ParagraphAdjust_RIGHT)
550 return SDRTEXTHORZADJUST_RIGHT;
551 else if (eAdjust == ParagraphAdjust_CENTER)
552 return SDRTEXTHORZADJUST_CENTER;
553 return SDRTEXTHORZADJUST_LEFT;
556 // LO does not interpret properties in styles belonging to the text content of a FontWork shape,
557 // but only those in the shape style. This method copies properties from the text content styles to
558 // the shape style.
559 static void lcl_copyCharPropsToShape(const uno::Reference<drawing::XShape>& xShape,
560 const TextBodyPtr& pTextBody,
561 const ::oox::core::XmlFilterBase& rFilter)
563 if (!xShape.is() || !pTextBody)
564 return;
566 Reference<XPropertySet> xSet(xShape, UNO_QUERY);
567 if (!xSet.is())
568 return;
570 // Content stretches or scales to given width and height, thus disable autogrow.
571 xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::Any(false));
572 xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::Any(false));
574 // LibreOffice is not able (as of Nov 2022) to use different styles for the paragraphs or
575 // characters in FontWork, since that was not allowed in old binary WordArt. We use the
576 // properties of the first non empty paragraph for now.
577 const TextParagraphVector& rParagraphs = pTextBody->getParagraphs();
578 auto aParaIt = std::find_if_not(rParagraphs.cbegin(), rParagraphs.cend(),
579 [](const std::shared_ptr<TextParagraph> pParagraph) {
580 return pParagraph->getRuns().empty();
582 if (aParaIt != rParagraphs.cend())
584 std::shared_ptr<TextParagraph> pParagraph = *aParaIt;
585 const TextRunVector& rRuns = pParagraph->getRuns();
586 auto aRunIt = std::find_if_not(
587 rRuns.cbegin(), rRuns.cend(),
588 [](const std::shared_ptr<TextRun> pRun) { return pRun->getText().isEmpty(); });
589 if (aRunIt != rRuns.cend())
591 std::shared_ptr<TextRun> pRun = *aRunIt;
592 TextCharacterProperties& rCharProps = pRun->getTextCharacterProperties();
594 // set language
595 if (rCharProps.moLang.has_value() && !rCharProps.moLang.value().isEmpty())
597 LanguageTag aTag(rCharProps.moLang.value());
598 css::lang::Locale aLocale(aTag.getLocale(false));
599 switch (MsLangId::getScriptType(aTag.getLanguageType()))
601 case css::i18n::ScriptType::LATIN:
602 xSet->setPropertyValue(u"CharLocale", uno::Any(aLocale));
603 break;
604 case css::i18n::ScriptType::ASIAN:
605 xSet->setPropertyValue(u"CharLocaleAsian", uno::Any(aLocale));
606 break;
607 case css::i18n::ScriptType::COMPLEX:
608 xSet->setPropertyValue(u"CharLocaleComplex", uno::Any(aLocale));
609 break;
610 default:;
614 // Font Weight, Posture, Height
615 if (rCharProps.moBold.has_value() && rCharProps.moBold.value())
617 xSet->setPropertyValue(UNO_NAME_CHAR_WEIGHT, uno::Any(css::awt::FontWeight::BOLD));
619 if (rCharProps.moItalic.has_value() && rCharProps.moItalic.value())
621 xSet->setPropertyValue(UNO_NAME_CHAR_POSTURE,
622 uno::Any(css::awt::FontSlant::FontSlant_ITALIC));
624 if (rCharProps.moHeight.has_value())
626 sal_Int32 nHeight = rCharProps.moHeight.value() / 100;
627 xSet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::Any(nHeight));
630 // Put theme fonts into shape properties
631 OUString sFontName;
632 sal_Int16 nFontPitch = 0;
633 sal_Int16 nFontFamily = 0;
634 bool bRet(false);
635 if (const Theme* pTheme = rFilter.getCurrentTheme())
637 // minor Latin
638 if (const TextFont* pFont = pTheme->resolveFont(u"+mn-lt"))
640 bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, rFilter);
641 if (bRet)
643 xSet->setPropertyValue(u"CharFontName", uno::Any(sFontName));
644 xSet->setPropertyValue(u"CharFontPitch", uno::Any(nFontPitch));
645 xSet->setPropertyValue(u"CharFontFamily", uno::Any(nFontFamily));
648 // minor Asian
649 if (const TextFont* pFont = pTheme->resolveFont(u"+mn-ea"))
651 bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, rFilter);
652 if (bRet)
654 xSet->setPropertyValue(u"CharFontNameAsian", uno::Any(sFontName));
655 xSet->setPropertyValue(u"CharFontPitchAsian", uno::Any(nFontPitch));
656 xSet->setPropertyValue(u"CharFontFamilyAsian", uno::Any(nFontFamily));
659 // minor Complex
660 if (const TextFont* pFont = pTheme->resolveFont(u"+mn-cs"))
662 bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, rFilter);
663 if (bRet)
665 xSet->setPropertyValue(u"CharFontNameComplex", uno::Any(sFontName));
666 xSet->setPropertyValue(u"CharFontPitchComplex", uno::Any(nFontPitch));
667 xSet->setPropertyValue(u"CharFontFamilyComplex", uno::Any(nFontFamily));
672 // Replace theme fonts with formatting at run if any. ToDo: Inspect paragraph too?
673 // Latin
674 bRet = rCharProps.maLatinFont.getFontData(sFontName, nFontPitch, nFontFamily, rFilter);
675 if (!bRet)
676 // In case there is no direct font, try to look it up as a theme reference.
677 bRet = rCharProps.maLatinThemeFont.getFontData(sFontName, nFontPitch, nFontFamily,
678 rFilter);
680 if (bRet)
682 xSet->setPropertyValue(u"CharFontName", uno::Any(sFontName));
683 xSet->setPropertyValue(u"CharFontPitch", uno::Any(nFontPitch));
684 xSet->setPropertyValue(u"CharFontFamily", uno::Any(nFontFamily));
686 // Asian
687 bRet = rCharProps.maAsianFont.getFontData(sFontName, nFontPitch, nFontFamily, rFilter);
688 if (!bRet)
689 // In case there is no direct font, try to look it up as a theme reference.
690 bRet = rCharProps.maAsianThemeFont.getFontData(sFontName, nFontPitch, nFontFamily,
691 rFilter);
692 if (bRet)
694 xSet->setPropertyValue(u"CharFontNameAsian", uno::Any(sFontName));
695 xSet->setPropertyValue(u"CharFontPitchAsian", uno::Any(nFontPitch));
696 xSet->setPropertyValue(u"CharFontFamilyAsian", uno::Any(nFontFamily));
698 // Complex
699 bRet
700 = rCharProps.maComplexFont.getFontData(sFontName, nFontPitch, nFontFamily, rFilter);
701 if (!bRet)
702 // In case there is no direct font, try to look it up as a theme reference.
703 bRet = rCharProps.maComplexThemeFont.getFontData(sFontName, nFontPitch, nFontFamily,
704 rFilter);
705 if (bRet)
707 xSet->setPropertyValue(u"CharFontNameComplex", uno::Any(sFontName));
708 xSet->setPropertyValue(u"CharFontPitchComplex", uno::Any(nFontPitch));
709 xSet->setPropertyValue(u"CharFontFamilyComplex", uno::Any(nFontFamily));
712 // LO uses shape properties, MS Office character properties. Copy them from char to shape.
713 // Outline
714 if (rCharProps.moTextOutlineProperties.has_value())
716 oox::drawingml::ShapePropertyMap aStrokeShapeProps(rFilter.getModelObjectHelper());
717 rCharProps.moTextOutlineProperties.value().pushToPropMap(
718 aStrokeShapeProps, rFilter.getGraphicHelper());
719 for (const auto& rProp : aStrokeShapeProps.makePropertyValueSequence())
721 xSet->setPropertyValue(rProp.Name, rProp.Value);
724 else
726 xSet->setPropertyValue(UNO_NAME_LINESTYLE, uno::Any(drawing::LineStyle_NONE));
729 // Fill
730 // ToDo: Replace flip and rotate constants in parameters with actual values.
731 // tdf#155327 If color is not explicitly set, MS Office uses scheme color 'tx1'.
732 oox::drawingml::ShapePropertyMap aFillShapeProps(rFilter.getModelObjectHelper());
733 if (!rCharProps.maFillProperties.moFillType.has_value())
734 rCharProps.maFillProperties.moFillType = XML_solidFill;
735 if (!rCharProps.maFillProperties.maFillColor.isUsed())
736 rCharProps.maFillProperties.maFillColor.setSchemeClr(XML_tx1);
737 rCharProps.maFillProperties.pushToPropMap(aFillShapeProps, rFilter.getGraphicHelper(),
738 /*nShapeRotation*/ 0,
739 /*nPhClr*/ API_RGB_TRANSPARENT,
740 /*aShapeSize*/ css::awt::Size(0, 0),
741 /*nPhClrTheme*/ -1,
742 /*bFlipH*/ false, /*bFlipV*/ false,
743 /*bIsCustomShape*/ true);
744 for (const auto& rProp : aFillShapeProps.makePropertyValueSequence())
746 xSet->setPropertyValue(rProp.Name, rProp.Value);
749 // ToDo: Import WordArt glow and simple shadow effects. They are available in LO.
752 // LO does not evaluate paragraph alignment in text path mode. Use text area anchor instead.
754 ParagraphAdjust eAdjust = ParagraphAdjust_LEFT;
755 if (pParagraph->getProperties().getParaAdjust())
756 eAdjust = *pParagraph->getProperties().getParaAdjust();
757 xSet->setPropertyValue("ParaAdjust", uno::Any(eAdjust));
758 SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
759 assert(pShape);
760 SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust(eAdjust);
761 pShape->SetMergedItem(SdrTextHorzAdjustItem(eHorzAdjust));
765 // Vertical adjustment is only meaningful for OOXML WordArt shapes of 'Follow Path' kinds. We set
766 // it so, that text position is approximately same as in MS Office.
767 const OUString sMSPresetType = pTextBody->getTextProperties().msPrst;
768 const OUString sFontworkType = PresetGeometryTypeNames::GetFontworkType(sMSPresetType);
769 SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
770 assert(pShape);
771 if (sFontworkType == "fontwork-arch-up-curve" || sFontworkType == "fontwork-circle-curve")
772 pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM));
773 else if (sFontworkType == "fontwork-arch-down-curve")
774 pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP));
775 else
776 pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_CENTER));
779 // Some helper methods for createAndInsert
780 namespace
782 // mirrors aTransformation at its center axis
783 // only valid if neither rotation or shear included
784 void lcl_mirrorAtCenter(basegfx::B2DHomMatrix& aTransformation, bool bFlipH, bool bFlipV)
786 if (!bFlipH && !bFlipV)
787 return;
788 basegfx::B2DPoint aCenter(0.5, 0.5);
789 aCenter *= aTransformation;
790 aTransformation.translate(-aCenter);
791 aTransformation.scale(bFlipH ? -1.0 : 1.0, bFlipV ? -1.0 : 1.0);
792 aTransformation.translate(aCenter);
793 return;
796 // only valid if neither rotation or shear included
797 void lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix& aTransformation)
799 // The values are directly set at the matrix without any matrix multiplication.
800 // That way it is valid for lines too. Those have zero width or height.
801 const double fSx(aTransformation.get(0, 0));
802 const double fSy(aTransformation.get(1, 1));
803 const double fTx(aTransformation.get(0, 2));
804 const double fTy(aTransformation.get(1, 2));
805 aTransformation.set(0, 0, fSy);
806 aTransformation.set(1, 1, fSx);
807 aTransformation.set(0, 2, fTx + 0.5 * (fSx - fSy));
808 aTransformation.set(1, 2, fTy + 0.5 * (fSy - fSx));
809 return;
812 void lcl_RotateAtCenter(basegfx::B2DHomMatrix& aTransformation,sal_Int32 nMSORotationAngle)
814 if (nMSORotationAngle == 0)
815 return;
816 double fRad = basegfx::deg2rad<60000>(nMSORotationAngle);
817 basegfx::B2DPoint aCenter(0.5, 0.5);
818 aCenter *= aTransformation;
819 aTransformation.translate(-aCenter);
820 aTransformation.rotate(fRad);
821 aTransformation.translate(aCenter);
822 return;
826 Reference< XShape > const & Shape::createAndInsert(
827 ::oox::core::XmlFilterBase& rFilterBase,
828 const OUString& rServiceName,
829 const Theme* pTheme,
830 const css::uno::Reference< css::drawing::XShapes >& rxShapes,
831 bool bClearText,
832 bool bDoNotInsertEmptyTextBody,
833 basegfx::B2DHomMatrix& aParentTransformation,
834 const FillProperties& rShapeOrParentShapeFillProps,
835 oox::drawingml::ShapePtr pParentGroupShape)
837 bool bIsEmbMedia = false;
838 SAL_INFO("oox.drawingml", "Shape::createAndInsert: id='" << msId << "' service='" << rServiceName << "'");
840 formulaimport::XmlStreamBuilder * pMathXml(nullptr);
841 if (mpTextBody)
843 for (auto const& it : mpTextBody->getParagraphs())
845 if (it->HasMathXml())
847 if (!mpTextBody->isEmpty() || pMathXml != nullptr)
849 SAL_WARN("oox.drawingml", "losing a Math object...");
851 else
853 pMathXml = &it->GetMathXml();
859 // tdf#90403 PowerPoint ignores a:ext cx and cy values of p:xfrm, and uses real table width and height
860 if ( mpTablePropertiesPtr && rServiceName == "com.sun.star.drawing.TableShape" )
862 maSize.Width = 0;
863 for (auto const& elem : mpTablePropertiesPtr->getTableGrid())
865 maSize.Width = o3tl::saturating_add(maSize.Width, static_cast<sal_Int32>(elem));
867 maSize.Height = 0;
868 for (auto const& elem : mpTablePropertiesPtr->getTableRows())
870 // WARN: If some rows can't fit the content, this is not the final height
871 maSize.Height = o3tl::saturating_add(maSize.Height, elem.getHeight());
875 awt::Rectangle aShapeRectHmm(
876 o3tl::convert(maPosition.X, o3tl::Length::emu, o3tl::Length::mm100),
877 o3tl::convert(maPosition.Y, o3tl::Length::emu, o3tl::Length::mm100),
878 o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100),
879 o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100));
881 OUString aServiceName;
882 if (pMathXml)
884 // convert this shape to OLE
885 aServiceName = "com.sun.star.drawing.OLE2Shape";
886 msServiceName = aServiceName;
887 meFrameType = FRAMETYPE_GENERIC; // not OLEOBJECT, no stream in package
888 mnSubType = 0;
890 else if (rServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
891 mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->m_sMediaPackageURL.isEmpty())
893 aServiceName = finalizeServiceName( rFilterBase, "com.sun.star.presentation.MediaShape", aShapeRectHmm );
894 bIsEmbMedia = true;
896 else
898 aServiceName = finalizeServiceName( rFilterBase, rServiceName, aShapeRectHmm );
900 // Use custom shape instead of GraphicObjectShape if the image is cropped to
901 // shape. Except rectangle, which does not require further cropping
902 bool bIsCroppedGraphic = (aServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
903 !mpCustomShapePropertiesPtr->representsDefaultShape());
905 bool bIsCustomShape = (aServiceName == "com.sun.star.drawing.CustomShape" || bIsCroppedGraphic);
906 bool bIsConnectorShape = (aServiceName == "com.sun.star.drawing.ConnectorShape");
907 if(bIsCroppedGraphic)
909 aServiceName = "com.sun.star.drawing.CustomShape";
910 mpGraphicPropertiesPtr->mbIsCustomShape = true;
912 bool bUseRotationTransform = ( !mbWps ||
913 aServiceName == "com.sun.star.drawing.LineShape" ||
914 aServiceName == "com.sun.star.drawing.GroupShape" ||
915 mbFlipH ||
916 mbFlipV );
918 basegfx::B2DHomMatrix aTransformation; // will be cumulative transformation of this object
920 // Special for SmartArt import. Rotate diagram's shape around object's center before sizing.
921 if (bUseRotationTransform && mnDiagramRotation != 0)
923 aTransformation.translate(-0.5, -0.5);
924 aTransformation.rotate(basegfx::deg2rad<60000>(mnDiagramRotation));
925 aTransformation.translate(0.5, 0.5);
928 // Build object matrix from shape size and position; corresponds to MSO ext and off
929 // Only LineShape and ConnectorShape may have zero width or height.
930 if (aServiceName == "com.sun.star.drawing.LineShape"
931 || aServiceName == "com.sun.star.drawing.ConnectorShape")
932 aTransformation.scale(maSize.Width, maSize.Height);
933 else
935 aTransformation.scale(maSize.Width ? maSize.Width : 1.0,
936 maSize.Height ? maSize.Height : 1.0);
939 // Evaluate object flip. Other shapes than custom shapes have no attribute for flip but use
940 // negative scale. Flip in MSO is at object center.
941 if (!bIsCustomShape && (mbFlipH || mbFlipV))
942 lcl_mirrorAtCenter(aTransformation, mbFlipH, mbFlipV);
944 // Evaluate parent flip.
945 // A CustomShape has mirror not as negative scale, but as attributes.
946 basegfx::B2DVector aParentScale(1.0, 1.0);
947 basegfx::B2DVector aParentTranslate(0.0, 0.0);
948 double fParentRotate(0.0);
949 double fParentShearX(0.0);
950 if (pParentGroupShape)
952 aParentTransformation.decompose(aParentScale, aParentTranslate, fParentRotate, fParentShearX);
953 if (bIsCustomShape)
955 lcl_mirrorAtCenter(aTransformation, aParentScale.getX() < 0, aParentScale.getY() < 0);
956 if(aParentScale.getX() < 0)
957 mbFlipH = !mbFlipH;
958 if(aParentScale.getY() < 0)
959 mbFlipV = !mbFlipV;
963 if (maPosition.X != 0 || maPosition.Y != 0)
965 // if global position is used, add it to transformation
966 if (mbWps && pParentGroupShape == nullptr)
967 aTransformation.translate(
968 o3tl::convert(maPosition.X, o3tl::Length::mm100, o3tl::Length::emu),
969 o3tl::convert(maPosition.Y, o3tl::Length::mm100, o3tl::Length::emu));
970 else
971 aTransformation.translate(maPosition.X, maPosition.Y);
974 // Apply further parent transformations. First scale object then rotate. Other way round would
975 // introduce shearing.
977 // The attributes chExt and chOff of the group in oox file contain the values on which the size
978 // and position of the child is based on. If they differ from the actual size of the group as
979 // given in its ext and off attributes, the child has to be transformed according the new values.
980 if (pParentGroupShape)
982 // ToDo: A diagram in a group might need special handling because it cannot flip and only
983 // resize uniformly. But currently it is imported with zero size, see tdf#139575. That needs
984 // to be fixed beforehand.
986 // Scaling is done from left/top edges of the group. So these need to become coordinate axes.
987 aTransformation.translate(-pParentGroupShape->maChPosition.X,
988 -pParentGroupShape->maChPosition.Y);
990 // oox allows zero or missing attribute chExt. In that case the scaling factor is 1.
991 // Transform2DContext::onCreateContext has set maChSize to maSize for groups in oox file in
992 // such cases. For own made groups (e.g. diagrams) that is missing.
993 // The factors cumulate on the way through the parent groups, so we do not use maSize of the
994 // direct parent group but the cumulated value from aParentScale.
995 double fFactorX = 1.0;
996 double fFactorY = 1.0;
997 if (pParentGroupShape->maChSize.Width != 0)
998 fFactorX = aParentScale.getX() / pParentGroupShape->maChSize.Width;
999 if (pParentGroupShape->maChSize.Height != 0)
1000 fFactorY = aParentScale.getY() / pParentGroupShape->maChSize.Height;
1001 if (fFactorX != 1 || fFactorY != 1)
1003 // It depends on the object rotation angle whether scaling is applied to switched
1004 // width and height. MSO acts strange in that case (as of May 2021).
1005 const sal_Int32 nDeg(mnRotation / 60000);
1006 const bool bNeedsMSOWidthHeightToggle
1007 = (nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315);
1008 if (bNeedsMSOWidthHeightToggle)
1009 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
1011 aTransformation.scale(fFactorX, fFactorY);
1013 if (bNeedsMSOWidthHeightToggle)
1015 lcl_doSpecialMSOWidthHeightToggle(aTransformation);
1016 // In case of flip the special case needs an additional 180deg rotation.
1017 if ((aParentScale.getX() < 0) != (aParentScale.getY() < 0))
1018 lcl_RotateAtCenter(aTransformation, 10800000);
1023 // Apply object rotation at current object center
1024 // The flip contained in aParentScale will affect orientation of object rotation angle.
1025 sal_Int16 nOrientation = ((aParentScale.getX() < 0) != (aParentScale.getY() < 0)) ? -1 : 1;
1026 // ToDo: Not sure about the restrictions given by bUseRotationTransform.
1027 // Since LibreOffice doesn't have 3D camera options for 2D shapes, rotate the shape opposite of
1028 // the camera Z axis rotation, in order to produce the same visual result from MSO
1029 const sal_Int32 nCameraRotation = get3DProperties().maCameraRotation.mnRevolution.value_or(0);
1030 if (bUseRotationTransform && (mnRotation != 0 || nCameraRotation != 0))
1031 lcl_RotateAtCenter(aTransformation, nOrientation * (mnRotation - nCameraRotation));
1033 if (fParentRotate != 0.0)
1034 aTransformation.rotate(fParentRotate);
1035 if (!aParentTranslate.equalZero())
1036 aTransformation.translate(aParentTranslate);
1038 aParentTransformation = aTransformation;
1040 constexpr double fEmuToMm100 = o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::mm100);
1041 aTransformation.scale(fEmuToMm100, fEmuToMm100);
1043 // OOXML flips shapes before rotating them, so the rotation needs to be inverted
1044 if( bIsCustomShape && mbFlipH != mbFlipV )
1046 basegfx::B2DVector aScale, aTranslate;
1047 double fRotate, fShearX;
1048 aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
1050 if(fRotate != 0)
1052 basegfx::B2DPoint aCenter(0.5, 0.5);
1053 aCenter *= aTransformation;
1054 aTransformation.translate( -aCenter.getX(), -aCenter.getY() );
1055 aTransformation.rotate( fRotate * -2.0 );
1056 aTransformation.translate( aCenter.getX(), aCenter.getY() );
1060 // special for lineshape
1061 if ( aServiceName == "com.sun.star.drawing.LineShape" )
1063 ::basegfx::B2DPolygon aPoly;
1064 aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
1065 aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
1066 aPoly.transform( aTransformation );
1068 // now creating the corresponding PolyPolygon
1069 sal_Int32 i, nNumPoints = aPoly.count();
1070 uno::Sequence< awt::Point > aPointSequence( nNumPoints );
1071 awt::Point* pPoints = aPointSequence.getArray();
1072 for( i = 0; i < nNumPoints; ++i )
1074 basegfx::B2DPoint aPoint( aPoly.getB2DPoint( i ) );
1076 // Guard against zero width or height.
1077 if (i)
1079 const basegfx::B2DPoint& rPreviousPoint = aPoly.getB2DPoint(i - 1);
1080 if (aPoint.getX() - rPreviousPoint.getX() == 0)
1081 aPoint.setX(aPoint.getX() + 1);
1082 if (aPoint.getY() - rPreviousPoint.getY() == 0)
1083 aPoint.setY(aPoint.getY() + 1);
1086 pPoints[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()), static_cast<sal_Int32>(aPoint.getY()));
1088 uno::Sequence< uno::Sequence< awt::Point > > aPolyPolySequence( 1 );
1089 aPolyPolySequence.getArray()[ 0 ] = aPointSequence;
1091 maShapeProperties.setProperty(PROP_PolyPolygon, aPolyPolySequence);
1093 else if ( aServiceName == "com.sun.star.drawing.ConnectorShape" )
1095 ::basegfx::B2DPolygon aPoly;
1096 aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
1097 aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
1098 aPoly.transform( aTransformation );
1100 basegfx::B2DPoint aStartPosition( aPoly.getB2DPoint( 0 ) );
1101 basegfx::B2DPoint aEndPosition( aPoly.getB2DPoint( 1 ) );
1102 awt::Point aAWTStartPosition( static_cast< sal_Int32 >( aStartPosition.getX() ), static_cast< sal_Int32 >( aStartPosition.getY() ) );
1103 awt::Point aAWTEndPosition( static_cast< sal_Int32 >( aEndPosition.getX() ), static_cast< sal_Int32 >( aEndPosition.getY() ) );
1105 maShapeProperties.setProperty(PROP_StartPosition, aAWTStartPosition);
1106 maShapeProperties.setProperty(PROP_EndPosition, aAWTEndPosition);
1108 else
1110 // now set transformation for this object
1111 HomogenMatrix3 aMatrix;
1113 aMatrix.Line1.Column1 = aTransformation.get(0,0);
1114 aMatrix.Line1.Column2 = aTransformation.get(0,1);
1115 aMatrix.Line1.Column3 = aTransformation.get(0,2);
1117 aMatrix.Line2.Column1 = aTransformation.get(1,0);
1118 aMatrix.Line2.Column2 = aTransformation.get(1,1);
1119 aMatrix.Line2.Column3 = aTransformation.get(1,2);
1121 aMatrix.Line3.Column1 = 0;
1122 aMatrix.Line3.Column2 = 0;
1123 aMatrix.Line3.Column3 = 1;
1125 maShapeProperties.setProperty(PROP_Transformation, aMatrix);
1128 Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
1129 if ( !mxShape.is() )
1131 mxShape.set( xServiceFact->createInstance( aServiceName ), UNO_QUERY_THROW );
1134 Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
1135 if (xSet.is())
1137 if( !msName.isEmpty() )
1139 Reference< container::XNamed > xNamed( mxShape, UNO_QUERY );
1140 if( xNamed.is() )
1141 xNamed->setName( msName );
1143 if( !msDescription.isEmpty() )
1145 xSet->setPropertyValue( "Description", Any( msDescription ) );
1147 if (m_isDecorative)
1149 xSet->setPropertyValue("Decorative", Any(m_isDecorative));
1151 if (aServiceName != "com.sun.star.text.TextFrame")
1152 rxShapes->add( mxShape );
1154 if ( mbHidden || mbHiddenMasterShape )
1156 SAL_INFO("oox.drawingml", "Shape::createAndInsert: invisible shape with id='" << msId << "'");
1157 xSet->setPropertyValue( "Visible", Any( false ) );
1158 // In Excel hidden means not printed, let's use visibility for now until that's handled separately
1159 xSet->setPropertyValue( "Printable", Any( false ) );
1162 if (mbLocked)
1164 xSet->setPropertyValue("MoveProtect", Any(true));
1165 xSet->setPropertyValue("SizeProtect", Any(true));
1168 ActionLockGuard const alg(mxShape);
1170 // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape
1171 if ( bClearText )
1173 uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY );
1174 if ( xText.is() )
1176 xText->setString( "" );
1180 if (pMathXml)
1182 // the "EmbeddedObject" property is read-only, so we have to create
1183 // the shape first, and it can be read only after the shape is
1184 // inserted into the document, so delay the actual import until here
1185 SvGlobalName name(SO3_SM_CLASSID);
1186 xSet->setPropertyValue("CLSID", uno::Any(name.GetHexName()));
1187 uno::Reference<embed::XEmbeddedObject> const xObj(
1188 xSet->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY);
1189 if (xObj.is())
1191 uno::Reference<uno::XInterface> const xMathModel(xObj->getComponent());
1192 oox::FormulaImExportBase *const pMagic(
1193 dynamic_cast<oox::FormulaImExportBase*>(xMathModel.get()));
1194 assert(pMagic);
1195 pMagic->readFormulaOoxml(*pMathXml);
1199 const GraphicHelper& rGraphicHelper = rFilterBase.getGraphicHelper();
1201 ::Color nLinePhClr(ColorTransparency, 0xffffffff);
1202 ::Color nFillPhClr(ColorTransparency, 0xffffffff);
1203 sal_Int16 nFillPhClrTheme = -1;
1204 sal_Int16 nLinePhClrTheme = -1;
1205 // TODO: use ph color when applying effect properties
1206 //sal_Int32 nEffectPhClr = -1;
1208 // dmapper needs the original rotation angle for calculating square wrap. This angle is not
1209 // available as property there, so store it in InteropGrabBag.
1210 putPropertyToGrabBag("mso-rotation-angle", Any(mnRotation));
1212 if( pTheme )
1214 if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
1216 LineProperties aLineProperties;
1217 aLineProperties.maLineFill.moFillType = XML_noFill;
1218 if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
1219 aLineProperties.assignUsed( *pLineProps );
1220 nLinePhClr = pLineRef->maPhClr.getColor( rGraphicHelper );
1221 nLinePhClrTheme = pLineRef->maPhClr.getSchemeColorIndex();
1223 // Store style-related properties to InteropGrabBag to be able to export them back
1224 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1226 {"SchemeClr", uno::Any(pLineRef->maPhClr.getSchemeColorName())},
1227 {"Idx", uno::Any(pLineRef->mnThemedIdx)},
1228 {"Color", uno::Any(nLinePhClr)},
1229 {"LineStyle", uno::Any(aLineProperties.getLineStyle())},
1230 {"LineCap", uno::Any(aLineProperties.getLineCap())},
1231 {"LineJoint", uno::Any(aLineProperties.getLineJoint())},
1232 {"LineWidth", uno::Any(aLineProperties.getLineWidth())},
1233 {"Transformations", uno::Any(pLineRef->maPhClr.getTransformations())}
1235 putPropertyToGrabBag( "StyleLnRef", Any( aProperties ) );
1237 if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
1239 if (!getFillProperties().moUseBgFill.value_or(false))
1241 nFillPhClr = pFillRef->maPhClr.getColor(rGraphicHelper);
1242 nFillPhClrTheme = pFillRef->maPhClr.getSchemeColorIndex();
1245 OUString sColorScheme = pFillRef->maPhClr.getSchemeColorName();
1246 if( !sColorScheme.isEmpty() )
1248 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1250 {"SchemeClr", uno::Any(sColorScheme)},
1251 {"Idx", uno::Any(pFillRef->mnThemedIdx)},
1252 {"Color", uno::Any(nFillPhClr)},
1253 {"Transformations", uno::Any(pFillRef->maPhClr.getTransformations())}
1256 putPropertyToGrabBag( "StyleFillRef", Any( aProperties ) );
1259 if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
1261 // TODO: use ph color when applying effect properties
1262 // nEffectPhClr = pEffectRef->maPhClr.getColor( rGraphicHelper );
1264 // Store style-related properties to InteropGrabBag to be able to export them back
1265 uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
1267 {"SchemeClr", uno::Any(pEffectRef->maPhClr.getSchemeColorName())},
1268 {"Idx", uno::Any(pEffectRef->mnThemedIdx)},
1269 {"Transformations", uno::Any(pEffectRef->maPhClr.getTransformations())}
1271 putPropertyToGrabBag( "StyleEffectRef", Any( aProperties ) );
1274 ShapePropertyMap aShapeProps( rFilterBase.getModelObjectHelper() );
1276 // add properties from textbody to shape properties
1277 if( mpTextBody )
1279 mpTextBody->getTextProperties().pushTextDistances(Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
1280 aShapeProps.assignUsed( mpTextBody->getTextProperties().maPropertyMap );
1281 // Push char properties as well - specifically useful when this is a placeholder
1282 if( mpMasterTextListStyle && mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.has_value() )
1283 aShapeProps.setProperty(PROP_CharHeight, GetFontHeight( mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.value() ));
1286 // applying properties
1287 aShapeProps.assignUsed( getShapeProperties() );
1288 aShapeProps.assignUsed( maDefaultShapeProperties );
1289 if(mnRotation != 0 && bIsCustomShape)
1290 aShapeProps.setProperty( PROP_RotateAngle, sal_Int32( NormAngle36000( Degree100(mnRotation / -600) ) ));
1291 if( bIsEmbMedia ||
1292 bIsCustomShape ||
1293 aServiceName == "com.sun.star.drawing.GraphicObjectShape" ||
1294 aServiceName == "com.sun.star.drawing.OLE2Shape")
1296 mpGraphicPropertiesPtr->pushToPropMap( aShapeProps, rGraphicHelper, mbFlipH, mbFlipV );
1298 if ( mpTablePropertiesPtr && aServiceName == "com.sun.star.drawing.TableShape" )
1300 mpTablePropertiesPtr->pushToPropSet( rFilterBase, xSet, mpMasterTextListStyle );
1301 if ( auto* pTableShape = dynamic_cast<sdr::table::SdrTableObj*>(SdrObject::getSdrObjectFromXShape(mxShape)) )
1303 // Disable layouting until table height is expanded to fit the content
1304 pTableShape->SetSkipChangeLayout(true);
1308 FillProperties aFillProperties = getActualFillProperties(pTheme, &rShapeOrParentShapeFillProps);
1309 if (getFillProperties().moFillType.has_value() && getFillProperties().moFillType.value() == XML_grpFill)
1310 getFillProperties().assignUsed(aFillProperties);
1311 if(!bIsCroppedGraphic)
1312 aFillProperties.pushToPropMap(aShapeProps, rGraphicHelper, mnRotation, nFillPhClr,
1313 css::awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height),
1314 nFillPhClrTheme, mbFlipH, mbFlipV, bIsCustomShape);
1316 LineProperties aLineProperties = getActualLineProperties(pTheme);
1317 aLineProperties.pushToPropMap( aShapeProps, rGraphicHelper, nLinePhClr, nLinePhClrTheme);
1318 EffectProperties aEffectProperties = getActualEffectProperties(pTheme);
1319 // TODO: use ph color when applying effect properties
1320 aEffectProperties.pushToPropMap( aShapeProps, rGraphicHelper );
1322 // applying autogrowheight property before setting shape size, because
1323 // the shape size might be changed if currently autogrowheight is true
1324 // we must also check that the PropertySet supports the property.
1325 Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1326 const OUString& rPropName = PropertyMap::getPropertyName( PROP_TextAutoGrowHeight );
1327 if( xSetInfo.is() && xSetInfo->hasPropertyByName( rPropName ) )
1328 if( aShapeProps.hasProperty( PROP_TextAutoGrowHeight ) )
1329 xSet->setPropertyValue( rPropName, Any( false ) );
1331 // do not set properties at a group shape (this causes
1332 // assertions from svx) ...
1333 if( aServiceName != "com.sun.star.drawing.GroupShape" )
1335 if (aServiceName == "com.sun.star.text.TextFrame")
1337 if (mpCustomShapePropertiesPtr && mpCustomShapePropertiesPtr->getShapeTypeOverride())
1339 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1340 uno::Sequence<beans::PropertyValue> aGrabBag;
1341 propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
1342 sal_Int32 length = aGrabBag.getLength();
1343 aGrabBag.realloc( length+1);
1344 auto pGrabBag = aGrabBag.getArray();
1345 pGrabBag[length].Name = "mso-orig-shape-type";
1346 uno::Sequence< sal_Int8 > const & aNameSeq =
1347 mpCustomShapePropertiesPtr->getShapePresetTypeName();
1348 OUString sShapePresetTypeName(reinterpret_cast< const char* >(
1349 aNameSeq.getConstArray()), aNameSeq.getLength(), RTL_TEXTENCODING_UTF8);
1350 pGrabBag[length].Value <<= sShapePresetTypeName;
1351 propertySet->setPropertyValue("FrameInteropGrabBag",uno::Any(aGrabBag));
1353 //If the text box has links then save the link information so that
1354 //it can be accessed in DomainMapper_Impl.cxx while chaining the text frames.
1355 if (isLinkedTxbx())
1357 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1358 uno::Sequence<beans::PropertyValue> aGrabBag;
1359 propertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
1360 sal_Int32 length = aGrabBag.getLength();
1361 aGrabBag.realloc( length + 3 );
1362 auto pGrabBag = aGrabBag.getArray();
1363 pGrabBag[length].Name = "TxbxHasLink";
1364 pGrabBag[length].Value <<= isLinkedTxbx();
1365 pGrabBag[length + 1 ].Name = "Txbx-Id";
1366 pGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1367 pGrabBag[length + 2 ].Name = "Txbx-Seq";
1368 pGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1369 propertySet->setPropertyValue("FrameInteropGrabBag",uno::Any(aGrabBag));
1372 // TextFrames have BackColor, not FillColor
1373 if (aShapeProps.hasProperty(PROP_FillColor))
1375 aShapeProps.setAnyProperty(PROP_BackColor, aShapeProps.getProperty(PROP_FillColor));
1376 aShapeProps.erase(PROP_FillColor);
1378 // TextFrames have BackColorTransparency, not FillTransparence
1379 if (aShapeProps.hasProperty(PROP_FillTransparence))
1381 aShapeProps.setAnyProperty(PROP_BackColorTransparency, aShapeProps.getProperty(PROP_FillTransparence));
1382 aShapeProps.erase(PROP_FillTransparence);
1384 // TextFrames have BackGraphic, not FillBitmap
1385 if (aShapeProps.hasProperty(PROP_FillBitmap))
1387 aShapeProps.setAnyProperty(PROP_BackGraphic, aShapeProps.getProperty(PROP_FillBitmap));
1388 aShapeProps.erase(PROP_FillBitmap);
1390 if (aShapeProps.hasProperty(PROP_FillBitmapName))
1392 uno::Any aAny = aShapeProps.getProperty(PROP_FillBitmapName);
1393 OUString aFillBitmapName = aAny.get<OUString>();
1394 uno::Reference<awt::XBitmap> xBitmap = rFilterBase.getModelObjectHelper().getFillBitmap(aFillBitmapName);
1395 uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
1396 aShapeProps.setProperty(PROP_BackGraphic, xGraphic);
1397 // aShapeProps.erase(PROP_FillBitmapName); // Maybe, leave the name as well
1399 // And no LineColor property; individual borders can have colors
1400 if (aShapeProps.hasProperty(PROP_LineColor))
1402 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1403 static const sal_Int32 aBorders[] =
1405 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
1407 for (sal_Int32 nBorder : aBorders)
1409 css::table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<css::table::BorderLine2>();
1410 aBorderLine.Color = aShapeProps.getProperty(PROP_LineColor).get<sal_Int32>();
1411 if (aLineProperties.moLineWidth.has_value())
1412 aBorderLine.LineWidth = convertEmuToHmm(aLineProperties.moLineWidth.value());
1413 aShapeProps.setProperty(nBorder, aBorderLine);
1415 aShapeProps.erase(PROP_LineColor);
1417 if(mnRotation)
1419 uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
1420 static const OUStringLiteral aGrabBagPropName = u"FrameInteropGrabBag";
1421 uno::Sequence<beans::PropertyValue> aGrabBag;
1422 xPropertySet->getPropertyValue(aGrabBagPropName) >>= aGrabBag;
1423 beans::PropertyValue aPair(comphelper::makePropertyValue("mso-rotation-angle",
1424 mnRotation));
1425 if (aGrabBag.hasElements())
1427 sal_Int32 nLength = aGrabBag.getLength();
1428 aGrabBag.realloc(nLength + 1);
1429 aGrabBag.getArray()[nLength] = aPair;
1431 else
1433 aGrabBag = { aPair };
1435 xPropertySet->setPropertyValue(aGrabBagPropName, uno::Any(aGrabBag));
1437 // TextFrames have ShadowFormat, not individual shadow properties.
1438 std::optional<sal_Int32> oShadowDistance;
1439 if (aShapeProps.hasProperty(PROP_ShadowXDistance))
1441 oShadowDistance = aShapeProps.getProperty(PROP_ShadowXDistance).get<sal_Int32>();
1442 aShapeProps.erase(PROP_ShadowXDistance);
1444 if (aShapeProps.hasProperty(PROP_ShadowYDistance))
1446 // There is a single 'dist' attribute, so no need to count the avg of x and y.
1447 aShapeProps.erase(PROP_ShadowYDistance);
1449 std::optional<sal_Int32> oShadowColor;
1450 if (aShapeProps.hasProperty(PROP_ShadowColor))
1452 oShadowColor = aShapeProps.getProperty(PROP_ShadowColor).get<sal_Int32>();
1453 aShapeProps.erase(PROP_ShadowColor);
1455 if (aShapeProps.hasProperty(PROP_Shadow))
1456 aShapeProps.erase(PROP_Shadow);
1458 if (oShadowDistance || oShadowColor || aEffectProperties.maShadow.moShadowDir.has_value())
1460 css::table::ShadowFormat aFormat;
1461 if (oShadowColor)
1462 aFormat.Color = *oShadowColor;
1463 if (aEffectProperties.maShadow.moShadowDir.has_value())
1465 css::table::ShadowLocation nLocation = css::table::ShadowLocation_NONE;
1466 switch (aEffectProperties.maShadow.moShadowDir.value())
1468 case 13500000:
1469 nLocation = css::table::ShadowLocation_TOP_LEFT;
1470 break;
1471 case 18900000:
1472 nLocation = css::table::ShadowLocation_TOP_RIGHT;
1473 break;
1474 case 8100000:
1475 nLocation = css::table::ShadowLocation_BOTTOM_LEFT;
1476 break;
1477 case 2700000:
1478 nLocation = css::table::ShadowLocation_BOTTOM_RIGHT;
1479 break;
1481 aFormat.Location = nLocation;
1483 aFormat.ShadowWidth = *oShadowDistance;
1484 aShapeProps.setProperty(PROP_ShadowFormat, aFormat);
1488 else if (mbTextBox)
1490 // This introduces a TextBox in a shape in Writer. ToDo: Can we restrict it to cases
1491 // where the TextBox edit engine is really needed? tdf#82627
1492 aShapeProps.setProperty(PROP_TextBox, true);
1495 if (aServiceName != "com.sun.star.text.TextFrame" && isLinkedTxbx())
1497 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1498 uno::Sequence<beans::PropertyValue> aGrabBag;
1499 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1500 sal_Int32 length = aGrabBag.getLength();
1501 aGrabBag.realloc( length + 3 );
1502 auto pGrabBag = aGrabBag.getArray();
1503 pGrabBag[length].Name = "TxbxHasLink";
1504 pGrabBag[length].Value <<= isLinkedTxbx();
1505 pGrabBag[length + 1 ].Name = "Txbx-Id";
1506 pGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
1507 pGrabBag[length + 2 ].Name = "Txbx-Seq";
1508 pGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
1509 propertySet->setPropertyValue("InteropGrabBag",uno::Any(aGrabBag));
1512 // If the shape is a picture placeholder.
1513 if (aServiceName == "com.sun.star.presentation.GraphicObjectShape" && !bClearText)
1515 // Placeholder text should be in center of the shape.
1516 aShapeProps.setProperty(PROP_TextContourFrame, false);
1518 /* Placeholder icon should be at the center of the parent shape.
1519 * We use negative graphic crop property because of that we don't
1520 * have padding support.
1522 uno::Reference<beans::XPropertySet> xGraphic(xSet->getPropertyValue("Graphic"), uno::UNO_QUERY);
1523 if (xGraphic.is())
1525 awt::Size aBitmapSize;
1526 xGraphic->getPropertyValue("Size100thMM") >>= aBitmapSize;
1527 sal_Int32 nXMargin = (aShapeRectHmm.Width - aBitmapSize.Width) / 2;
1528 sal_Int32 nYMargin = (aShapeRectHmm.Height - aBitmapSize.Height) / 2;
1529 if (nXMargin > 0 && nYMargin > 0)
1531 text::GraphicCrop aGraphicCrop;
1532 aGraphicCrop.Top = nYMargin * -1;
1533 aGraphicCrop.Bottom = nYMargin * -1;
1534 aGraphicCrop.Left = nXMargin * -1;
1535 aGraphicCrop.Right = nXMargin * -1;
1536 aShapeProps.setProperty(PROP_GraphicCrop, aGraphicCrop);
1541 PropertySet( xSet ).setProperties( aShapeProps );
1543 if (mpTablePropertiesPtr && aServiceName == "com.sun.star.drawing.TableShape")
1545 // Powerpoint exports desired row heights (i.e. what user attempted to set it as, not how it appears visually)
1546 // Expand table height if there are rows that can't fit the content
1547 if (auto* pTableShape = dynamic_cast<sdr::table::SdrTableObj*>(SdrObject::getSdrObjectFromXShape(mxShape)))
1549 tools::Rectangle aArea{};
1550 pTableShape->LayoutTableHeight(aArea, /*bFit=*/false);
1551 sal_Int32 nCorrectedHeight = aArea.GetHeight();
1552 const auto& aShapeSize = mxShape->getSize();
1553 if( nCorrectedHeight > aShapeSize.Height )
1554 mxShape->setSize( {aShapeSize.Width, nCorrectedHeight} );
1555 pTableShape->SetSkipChangeLayout(false);
1559 if (mbLockedCanvas)
1561 putPropertyToGrabBag( "LockedCanvas", Any( true ) );
1562 if (aServiceName == "com.sun.star.drawing.LineShape")
1564 // It seems the position and size for lines inside a locked canvas is absolute.
1565 mxShape->setPosition(awt::Point(aShapeRectHmm.X, aShapeRectHmm.Y));
1566 mxShape->setSize(awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
1570 // Store original fill and line colors of the shape and the theme color name to InteropGrabBag
1571 std::vector<beans::PropertyValue> aProperties
1573 comphelper::makePropertyValue("EmuLineWidth", aLineProperties.moLineWidth.value_or(0)),
1574 comphelper::makePropertyValue("OriginalSolidFillClr", aShapeProps.getProperty(PROP_FillColor)),
1575 comphelper::makePropertyValue("OriginalLnSolidFillClr", aShapeProps.getProperty(PROP_LineColor))
1577 OUString sColorFillScheme = aFillProperties.maFillColor.getSchemeColorName();
1578 if( !aFillProperties.maFillColor.isPlaceHolder() && !sColorFillScheme.isEmpty() )
1580 aProperties.push_back(comphelper::makePropertyValue("SpPrSolidFillSchemeClr", sColorFillScheme));
1581 aProperties.push_back(comphelper::makePropertyValue("SpPrSolidFillSchemeClrTransformations", aFillProperties.maFillColor.getTransformations()));
1583 OUString sLnColorFillScheme = aLineProperties.maLineFill.maFillColor.getSchemeColorName();
1584 if( !aLineProperties.maLineFill.maFillColor.isPlaceHolder() && !sLnColorFillScheme.isEmpty() )
1586 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillSchemeClr", sLnColorFillScheme));
1587 auto aResolvedSchemeClr = aLineProperties.maLineFill.maFillColor;
1588 aResolvedSchemeClr.clearTransformations();
1589 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillResolvedSchemeClr", aResolvedSchemeClr.getColor(rGraphicHelper, nFillPhClr)));
1590 aProperties.push_back(comphelper::makePropertyValue("SpPrLnSolidFillSchemeClrTransformations", aLineProperties.maLineFill.maFillColor.getTransformations()));
1592 putPropertiesToGrabBag(comphelper::containerToSequence(aProperties));
1594 // Store original gradient fill of the shape to InteropGrabBag
1595 // LibreOffice doesn't support all the kinds of gradient so we save its complete definition
1596 if( aShapeProps.hasProperty( PROP_FillGradient ) )
1598 std::vector<beans::PropertyValue> aGradientStops;
1599 size_t i = 0;
1600 for( const auto& [rPos, rColor] : aFillProperties.maGradientProps.maGradientStops )
1601 { // for each stop in the gradient definition:
1603 // save position
1604 std::vector<beans::PropertyValue> aGradientStop
1606 comphelper::makePropertyValue("Pos", rPos)
1609 OUString sStopColorScheme = rColor.getSchemeColorName();
1610 if( sStopColorScheme.isEmpty() )
1612 // save RGB color
1613 aGradientStop.push_back(comphelper::makePropertyValue("RgbClr", rColor.getColor(rGraphicHelper, nFillPhClr)));
1614 // in the case of a RGB color, transformations are already applied to
1615 // the color with the exception of alpha transformations. We only need
1616 // to keep the transparency value to calculate the alpha value later.
1617 if( rColor.hasTransparency() )
1618 aGradientStop.push_back(comphelper::makePropertyValue("Transparency", rColor.getTransparency()));
1620 else
1622 // save color with scheme name
1623 aGradientStop.push_back(comphelper::makePropertyValue("SchemeClr", sStopColorScheme));
1624 // save all color transformations
1625 aGradientStop.push_back(comphelper::makePropertyValue("Transformations", rColor.getTransformations()));
1628 aGradientStops.push_back(comphelper::makePropertyValue(OUString::number(i), comphelper::containerToSequence(aGradientStop)));
1629 ++i;
1631 // If getFillProperties.moFillType is unused that means gradient is defined by a theme
1632 // which is already saved into StyleFillRef property, so no need to save the explicit values too
1633 if( getFillProperties().moFillType.has_value() )
1634 putPropertyToGrabBag( "GradFillDefinition", uno::Any(comphelper::containerToSequence(aGradientStops)));
1635 putPropertyToGrabBag( "OriginalGradFill", aShapeProps.getProperty(PROP_FillGradient) );
1638 // store unsupported effect attributes in the grab bag
1639 if (!aEffectProperties.m_Effects.empty())
1641 std::vector<beans::PropertyValue> aEffects;
1642 for (auto const& it : aEffectProperties.m_Effects)
1644 PropertyValue aEffect = it->getEffect();
1645 if( !aEffect.Name.isEmpty() )
1647 std::vector<beans::PropertyValue> aEffectsGrabBag
1649 comphelper::makePropertyValue("Attribs", aEffect.Value)
1652 Color& aColor( it->moColor );
1653 OUString sColorScheme = aColor.getSchemeColorName();
1654 if( sColorScheme.isEmpty() )
1656 // RGB color and transparency value
1657 aEffectsGrabBag.push_back(comphelper::makePropertyValue("RgbClr", aColor.getColor(rGraphicHelper, nFillPhClr)));
1658 aEffectsGrabBag.push_back(comphelper::makePropertyValue("RgbClrTransparency", aColor.getTransparency()));
1660 else
1662 // scheme color with name and transformations
1663 aEffectsGrabBag.push_back(comphelper::makePropertyValue("SchemeClr", sColorScheme));
1664 aEffectsGrabBag.push_back(comphelper::makePropertyValue("SchemeClrTransformations", aColor.getTransformations()));
1666 aEffects.push_back(comphelper::makePropertyValue(aEffect.Name, comphelper::containerToSequence(aEffectsGrabBag)));
1669 putPropertyToGrabBag("EffectProperties", uno::Any(comphelper::containerToSequence(aEffects)));
1672 // add 3D effects if any
1673 Sequence< PropertyValue > aCamera3DEffects = get3DProperties().getCameraAttributes();
1674 Sequence< PropertyValue > aLightRig3DEffects = get3DProperties().getLightRigAttributes();
1675 Sequence< PropertyValue > aShape3DEffects = get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1676 if( aCamera3DEffects.hasElements() || aLightRig3DEffects.hasElements() || aShape3DEffects.hasElements() )
1678 uno::Sequence<beans::PropertyValue> a3DEffectsGrabBag = comphelper::InitPropertySequence(
1680 {"Camera", uno::Any(aCamera3DEffects)},
1681 {"LightRig", uno::Any(aLightRig3DEffects)},
1682 {"Shape3D", uno::Any(aShape3DEffects)}
1684 putPropertyToGrabBag( "3DEffectProperties", Any( a3DEffectsGrabBag ) );
1687 if( bIsCustomShape && getTextBody())
1690 Sequence< PropertyValue > aTextCamera3DEffects = getTextBody()->get3DProperties().getCameraAttributes();
1691 Sequence< PropertyValue > aTextLightRig3DEffects = getTextBody()->get3DProperties().getLightRigAttributes();
1692 Sequence< PropertyValue > aTextShape3DEffects = getTextBody()->get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr );
1693 if( aTextCamera3DEffects.hasElements() || aTextLightRig3DEffects.hasElements() || aTextShape3DEffects.hasElements() )
1695 uno::Sequence<beans::PropertyValue> aText3DEffectsGrabBag = comphelper::InitPropertySequence(
1697 {"Camera", uno::Any(aTextCamera3DEffects)},
1698 {"LightRig", uno::Any(aTextLightRig3DEffects)},
1699 {"Shape3D", uno::Any(aTextShape3DEffects)}
1701 putPropertyToGrabBag( "Text3DEffectProperties", Any( aText3DEffectsGrabBag ) );
1705 // store bitmap artistic effects in the grab bag
1706 if( !mpGraphicPropertiesPtr->maBlipProps.maEffect.isEmpty() )
1707 putPropertyToGrabBag( "ArtisticEffectProperties",
1708 Any( mpGraphicPropertiesPtr->maBlipProps.maEffect.getEffect() ) );
1711 else if( mbLockedCanvas )
1713 //If we have aServiceName as "com.sun.star.drawing.GroupShape" and lockedCanvas
1714 putPropertyToGrabBag( "LockedCanvas", Any( true ) );
1717 // These can have a custom geometry, so position should be set here,
1718 // after creation but before custom shape handling, using the position
1719 // we got from the caller.
1720 if (mbWps && aServiceName == "com.sun.star.drawing.LineShape" && !pParentGroupShape)
1721 mxShape->setPosition(maPosition);
1723 if (bIsConnectorShape)
1725 OUString sConnectorShapePresetTypeName(
1726 reinterpret_cast<const char*>(
1727 mpCustomShapePropertiesPtr->getShapePresetTypeName().getConstArray()),
1728 mpCustomShapePropertiesPtr->getShapePresetTypeName().getLength(),
1729 RTL_TEXTENCODING_UTF8);
1730 msConnectorName = sConnectorShapePresetTypeName;
1732 auto aAdjustmentList = mpCustomShapePropertiesPtr->getAdjustmentGuideList();
1733 for (size_t i = 0; i < aAdjustmentList.size(); i++)
1734 maConnectorAdjustmentList.push_back(aAdjustmentList[i].maFormula);
1736 sal_Int32 nType = mpCustomShapePropertiesPtr->getShapePresetType();
1737 switch (nType)
1739 case XML_line:
1740 case XML_straightConnector1:
1741 xSet->setPropertyValue("EdgeKind", Any(ConnectorType_LINE));
1742 break;
1743 case XML_bentConnector2:
1744 case XML_bentConnector3:
1745 case XML_bentConnector4:
1746 case XML_bentConnector5:
1747 xSet->setPropertyValue("EdgeKind", Any(ConnectorType_STANDARD));
1748 break;
1749 case XML_curvedConnector2:
1750 case XML_curvedConnector3:
1751 case XML_curvedConnector4:
1752 case XML_curvedConnector5:
1753 xSet->setPropertyValue("EdgeKind", Any(ConnectorType_CURVE));
1754 break;
1755 default:
1756 break;
1760 if( bIsCustomShape )
1762 if ( mbFlipH )
1763 mpCustomShapePropertiesPtr->setMirroredX( true );
1764 if ( mbFlipV )
1765 mpCustomShapePropertiesPtr->setMirroredY( true );
1766 if( getTextBody() )
1768 sal_Int32 nTextCameraZRotation = getTextBody()->get3DProperties().maCameraRotation.mnRevolution.value_or(0);
1769 mpCustomShapePropertiesPtr->setTextCameraZRotateAngle( nTextCameraZRotation / 60000 );
1771 // TextPreRotateAngle. Text rotates inside the text area. Might be used for diagram layout 'upr' and 'grav'.
1772 sal_Int32 nTextPreRotateAngle = static_cast< sal_Int32 >( getTextBody()->getTextProperties().moTextPreRotation.value_or( 0 ) );
1774 nTextPreRotateAngle -= mnDiagramRotation; // Use of mnDiagramRotation is unclear. It seems to be always 0 here.
1776 // TextRotateAngle. The text area rotates.
1777 sal_Int32 nTextAreaRotateAngle = getTextBody()->getTextProperties().moTextAreaRotation.value_or(0);
1778 if (getTextBody()->getTextProperties().moUpright)
1780 // When upright is set, any text area transformation and shape rotation is ignored
1781 // in MS Office. To simulate this behaviour, we rotate the text area into the
1782 // opposite direction of the shape rotation by as much as the shape was rotated
1783 // and so compensate the shape rotation, which is added in rendering.
1784 nTextAreaRotateAngle = -mnRotation;
1785 // If 45° <= shape rotation < 135° or 225° <= shape rotation < 315°,
1786 // then MS Office adds an additional 90° rotation to the text area.
1787 const sal_Int32 nDeg(mnRotation / 60000);
1788 if ((nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315))
1790 nTextAreaRotateAngle += 5400000;
1791 nTextPreRotateAngle -= 5400000; // compensate the additional text area rotation
1793 putPropertyToGrabBag("Upright", Any(true));
1795 /* OOX measures text rotation clockwise in 1/60000th degrees,
1796 relative to the containing shape. set*Angle wants degrees counter-clockwise. */
1797 mpCustomShapePropertiesPtr->setTextPreRotateAngle(-nTextPreRotateAngle / 60000);
1798 if (nTextAreaRotateAngle != 0)
1799 mpCustomShapePropertiesPtr->setTextAreaRotateAngle(-nTextAreaRotateAngle / 60000);
1801 auto sHorzOverflow = getTextBody()->getTextProperties().msHorzOverflow;
1802 if (!sHorzOverflow.isEmpty())
1803 putPropertyToGrabBag("horzOverflow", uno::Any(getTextBody()->getTextProperties().msHorzOverflow));
1804 if (XML_ellipsis == getTextBody()->getTextProperties().moVertOverflow)
1805 putPropertyToGrabBag("vertOverflow", uno::Any(OUString{"ellipsis"}));
1808 // Note that the script oox/source/drawingml/customshapes/generatePresetsData.pl looks
1809 // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs
1810 SAL_INFO("oox.cscode", "==cscode== shape name: '" << msName << "'");
1811 SAL_INFO("oox.csdata", "==csdata== shape name: '" << msName << "'");
1813 mpCustomShapePropertiesPtr->pushToPropSet(xSet, maSize);
1815 // Consider WordArt
1816 if (mpTextBody && !mpTextBody->getTextProperties().msPrst.isEmpty()
1817 && mpTextBody->getTextProperties().msPrst != u"textNoShape")
1819 bool bFromWordArt(aShapeProps.hasProperty(PROP_FromWordArt)
1820 ? aShapeProps.getProperty(PROP_FromWordArt).get<bool>()
1821 : false);
1822 FontworkHelpers::putCustomShapeIntoTextPathMode(
1823 mxShape, mpCustomShapePropertiesPtr, mpTextBody->getTextProperties().msPrst,
1824 bFromWordArt);
1827 else if( getTextBody() )
1828 getTextBody()->getTextProperties().pushVertSimulation();
1830 // tdf#133037: a bit hackish: force Shape to rotate in the opposite direction the camera would rotate
1831 PropertySet aPropertySet(mxShape);
1832 if ( !bUseRotationTransform && (mnRotation != 0 || nCameraRotation != 0) )
1834 // use the same logic for rotation from VML exporter (SimpleShape::implConvertAndInsert at vmlshape.cxx)
1835 Degree100 nAngle = NormAngle36000( Degree100((mnRotation - nCameraRotation) / -600) );
1836 aPropertySet.setAnyProperty( PROP_RotateAngle, Any( sal_Int32( nAngle.get() ) ) );
1837 aPropertySet.setAnyProperty( PROP_HoriOrientPosition, Any( maPosition.X ) );
1838 aPropertySet.setAnyProperty( PROP_VertOrientPosition, Any( maPosition.Y ) );
1841 // in some cases, we don't have any text body.
1842 if( mpTextBody && ( !bDoNotInsertEmptyTextBody || !mpTextBody->isEmpty() ) )
1844 Reference < XText > xText( mxShape, UNO_QUERY );
1845 if ( xText.is() ) // not every shape is supporting an XText interface (e.g. GroupShape)
1847 TextCharacterProperties aCharStyleProperties;
1848 if( const ShapeStyleRef* pFontRef = getShapeStyleRef( XML_fontRef ) )
1850 if( pFontRef->mnThemedIdx != 0 )
1852 if( pTheme )
1853 if( const TextCharacterProperties* pCharProps = pTheme->getFontStyle( pFontRef->mnThemedIdx ) )
1854 aCharStyleProperties.assignUsed( *pCharProps );
1855 SAL_INFO("oox.drawingml", "Shape::createAndInsert: use font color");
1856 if ( pFontRef->maPhClr.isUsed() )
1858 aCharStyleProperties.maFillProperties.maFillColor = pFontRef->maPhClr;
1859 aCharStyleProperties.maFillProperties.moFillType = XML_solidFill;
1863 xText->setString("");
1864 Reference < XTextCursor > xAt = xText->createTextCursor();
1865 getTextBody()->insertAt( rFilterBase, xText, xAt, aCharStyleProperties, mpMasterTextListStyle );
1867 const TextParagraphVector& rParagraphs = getTextBody()->getParagraphs();
1868 if (!rParagraphs.empty())
1870 const std::shared_ptr<TextParagraph>& pParagraph = rParagraphs[0];
1871 if (pParagraph->getProperties().getParaAdjust())
1873 style::ParagraphAdjust eAdjust = *pParagraph->getProperties().getParaAdjust();
1874 if (eAdjust == style::ParagraphAdjust_CENTER)
1876 // If the first paragraph is centered, then set the para adjustment of
1877 // the shape itself to centered as well.
1878 aPropertySet.setAnyProperty(PROP_ParaAdjust, uno::Any(eAdjust));
1882 // tdf#144092 For empty textboxes push character styles &
1883 // endParaRPr into the Shape's properties
1884 if (rParagraphs.size() == 1 && pParagraph->getRuns().empty())
1886 TextCharacterProperties aTextCharacterProps{ pParagraph->getCharacterStyle(
1887 aCharStyleProperties, *mpMasterTextListStyle,
1888 getTextBody()->getTextListStyle()) };
1889 aTextCharacterProps.assignUsed(pParagraph->getEndProperties());
1890 aTextCharacterProps.pushToPropSet(aPropertySet, rFilterBase);
1894 // MS Office has e.g. fill and stroke of WordArt in the character properties,
1895 // LibreOffice uses shape properties.
1896 if (!mpTextBody->getTextProperties().msPrst.isEmpty()
1897 && mpTextBody->getTextProperties().msPrst != u"textNoShape")
1899 lcl_copyCharPropsToShape(mxShape, mpTextBody, rFilterBase);
1903 else if (mbTextBox)
1905 // No drawingML text, but WPS text is expected: save the theme
1906 // character color on the shape, then.
1907 if(const ShapeStyleRef* pFontRef = getShapeStyleRef(XML_fontRef))
1909 ::Color nCharColor = pFontRef->maPhClr.getColor(rGraphicHelper);
1910 aPropertySet.setAnyProperty(PROP_CharColor, uno::Any(nCharColor));
1914 // Set glow effect properties
1915 if (aEffectProperties.maGlow.moGlowRad.has_value()
1916 && aServiceName != "com.sun.star.drawing.GroupShape")
1918 uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
1919 propertySet->setPropertyValue("GlowEffectRadius", Any(convertEmuToHmm(aEffectProperties.maGlow.moGlowRad.value())));
1920 propertySet->setPropertyValue("GlowEffectColor", Any(aEffectProperties.maGlow.moGlowColor.getColor(rGraphicHelper)));
1921 propertySet->setPropertyValue("GlowEffectTransparency", Any(aEffectProperties.maGlow.moGlowColor.getTransparency()));
1924 // Set soft edge effect properties
1925 if (aEffectProperties.maSoftEdge.moRad.has_value())
1927 uno::Reference<beans::XPropertySet> propertySet(mxShape, uno::UNO_QUERY);
1928 propertySet->setPropertyValue(
1929 "SoftEdgeRadius", Any(convertEmuToHmm(aEffectProperties.maSoftEdge.moRad.value())));
1932 // Set the stroke and fill-color properties of the OLE shape
1933 if (aServiceName == "com.sun.star.drawing.OLE2Shape" && mxOleObjectInfo
1934 && !mxOleObjectInfo->maShapeId.isEmpty())
1935 if (::oox::vml::Drawing* pVmlDrawing = rFilterBase.getVmlDrawing())
1936 if (const ::oox::vml::ShapeBase* pVmlShape
1937 = pVmlDrawing->getShapes().getShapeById(mxOleObjectInfo->maShapeId))
1939 // Apply stroke props from the type model of the related VML shape.
1940 ShapePropertyMap aPropMap(rFilterBase.getModelObjectHelper());
1941 pVmlShape->getTypeModel().maStrokeModel.pushToPropMap(
1942 aPropMap, rFilterBase.getGraphicHelper());
1943 // And, fill-color properties as well...
1944 pVmlShape->getTypeModel().maFillModel.pushToPropMap(
1945 aPropMap, rFilterBase.getGraphicHelper());
1946 PropertySet(xSet).setProperties(aPropMap);
1950 if (mxShape.is())
1952 finalizeXShape( rFilterBase, rxShapes );
1954 if (mpTextBody)
1956 // tdf#151518. The method readjustTextDistances is fix for tdf#148321, but conflicts with
1957 // text position in some of the SmartArt types in Writer. So exclude Writer here.
1958 OUString sDocumentService;
1959 rFilterBase.getMediaDescriptor()[utl::MediaDescriptor::PROP_DOCUMENTSERVICE] >>= sDocumentService;
1960 if (sDocumentService != u"com.sun.star.text.TextDocument")
1961 mpTextBody->getTextProperties().readjustTextDistances(mxShape);
1964 return mxShape;
1967 void Shape::keepDiagramDrawing(XmlFilterBase& rFilterBase, const OUString& rFragmentPath)
1970 sal_Int32 length = maDiagramDoms.getLength();
1971 maDiagramDoms.realloc(length + 1);
1973 // drawingValue[0] => dom, drawingValue[1] => Sequence of associated relationships
1974 uno::Sequence<uno::Any> diagramDrawing{
1975 uno::Any(rFilterBase.importFragment(rFragmentPath)),
1976 uno::Any(resolveRelationshipsOfTypeFromOfficeDoc(rFilterBase, rFragmentPath, u"image"))
1979 beans::PropertyValue* pValue = maDiagramDoms.getArray();
1980 pValue[length].Name = "OOXDrawing";
1981 pValue[length].Value <<= diagramDrawing;
1984 void Shape::keepDiagramCompatibilityInfo()
1988 if( !maDiagramDoms.hasElements() )
1989 return;
1991 Reference < XPropertySet > xSet( mxShape, UNO_QUERY_THROW );
1992 Reference < XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
1993 if ( !xSetInfo.is() )
1994 return;
1996 const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
1997 if( !xSetInfo->hasPropertyByName( aGrabBagPropName ) )
1998 return;
2000 Sequence < PropertyValue > aGrabBag;
2001 xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2003 // We keep the previous items, if present
2004 if ( aGrabBag.hasElements() )
2005 xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, maDiagramDoms) ) );
2006 else
2007 xSet->setPropertyValue( aGrabBagPropName, Any( maDiagramDoms ) );
2009 catch( const Exception& )
2011 TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::keepDiagramCompatibilityInfo" );
2015 void Shape::convertSmartArtToMetafile(XmlFilterBase const & rFilterBase)
2019 Reference<XPropertySet> xSet(mxShape, UNO_QUERY_THROW);
2021 xSet->setPropertyValue("MoveProtect", Any(true));
2022 xSet->setPropertyValue("SizeProtect", Any(true));
2024 // Replace existing shapes with a new Graphic Object rendered
2025 // from them
2026 Reference<XShape> xShape(renderDiagramToGraphic(rFilterBase));
2027 Reference<XShapes> xShapes(mxShape, UNO_QUERY_THROW);
2028 tools::Rectangle aBackgroundRect
2029 = SdrObject::getSdrObjectFromXShape(
2030 Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW))
2031 ->GetLogicRect();
2032 while (xShapes->hasElements())
2033 xShapes->remove(Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW));
2034 xShapes->add(xShape);
2035 SdrObject::getSdrObjectFromXShape(
2036 Reference<XShape>(xShapes->getByIndex(0), UNO_QUERY_THROW))
2037 ->NbcSetLogicRect(aBackgroundRect);
2039 catch (const Exception&)
2041 TOOLS_WARN_EXCEPTION("oox.drawingml", "Shape::convertSmartArtToMetafile");
2045 Reference < XShape > Shape::renderDiagramToGraphic( XmlFilterBase const & rFilterBase )
2047 Reference< XShape > xShape;
2051 if( !maDiagramDoms.hasElements() )
2052 return xShape;
2054 // Stream in which to place the rendered shape
2055 SvMemoryStream aTempStream;
2056 Reference < io::XStream > xStream( new utl::OStreamWrapper( aTempStream ) );
2057 Reference < io::XOutputStream > xOutputStream( xStream->getOutputStream() );
2059 // Size of the rendering
2060 awt::Size aActualSize = mxShape->getSize();
2061 Size aResolution(Application::GetDefaultDevice()->LogicToPixel(Size(100, 100), MapMode(MapUnit::MapCM)));
2062 double fPixelsPer100thmm = static_cast < double > ( aResolution.Width() ) / 100000.0;
2063 awt::Size aSize( static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Width ) + 0.5 ),
2064 static_cast < sal_Int32 > ( ( fPixelsPer100thmm * aActualSize.Height ) + 0.5 ) );
2066 Sequence< PropertyValue > aFilterData{
2067 comphelper::makePropertyValue("PixelWidth", aSize.Width),
2068 comphelper::makePropertyValue("PixelHeight", aSize.Height),
2069 comphelper::makePropertyValue("LogicalWidth", aActualSize.Width),
2070 comphelper::makePropertyValue("LogicalHeight", aActualSize.Height)
2073 Sequence < PropertyValue > aDescriptor{
2074 comphelper::makePropertyValue("OutputStream", xOutputStream),
2075 comphelper::makePropertyValue("FilterName", OUString("SVM")), // Rendering format
2076 comphelper::makePropertyValue("FilterData", aFilterData)
2079 Reference < lang::XComponent > xSourceDoc( mxShape, UNO_QUERY_THROW );
2080 Reference < XGraphicExportFilter > xGraphicExporter = GraphicExportFilter::create( rFilterBase.getComponentContext() );
2081 xGraphicExporter->setSourceDocument( xSourceDoc );
2082 xGraphicExporter->filter( aDescriptor );
2084 aTempStream.Seek( STREAM_SEEK_TO_BEGIN );
2086 Graphic aGraphic;
2087 GraphicFilter aFilter( false );
2088 if ( aFilter.ImportGraphic( aGraphic, u"", aTempStream, GRFILTER_FORMAT_NOTFOUND, nullptr, GraphicFilterImportFlags::NONE ) != ERRCODE_NONE )
2090 SAL_WARN( "oox.drawingml", "Shape::renderDiagramToGraphic: Unable to import rendered stream into graphic object" );
2091 return xShape;
2094 Reference < graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() );
2095 Reference < lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
2096 xShape.set( xServiceFact->createInstance( "com.sun.star.drawing.GraphicObjectShape" ), UNO_QUERY_THROW );
2097 Reference < XPropertySet > xPropSet( xShape, UNO_QUERY_THROW );
2098 xPropSet->setPropertyValue( "Graphic", Any( xGraphic ) );
2099 xPropSet->setPropertyValue( "MoveProtect", Any( true ) );
2100 xPropSet->setPropertyValue( "SizeProtect", Any( true ) );
2101 xPropSet->setPropertyValue( "Name", Any( OUString( "RenderedShapes" ) ) );
2103 catch( const Exception& )
2105 TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::renderDiagramToGraphic" );
2108 return xShape;
2111 void Shape::setTextBody(const TextBodyPtr & pTextBody)
2113 mpTextBody = pTextBody;
2116 void Shape::setMasterTextListStyle( const TextListStylePtr& pMasterTextListStyle )
2118 SAL_INFO("oox.drawingml", "Shape::setMasterTextListStyle: Set master text list style to shape id='" << msId << "'");
2120 mpMasterTextListStyle = pMasterTextListStyle;
2123 OUString Shape::finalizeServiceName( XmlFilterBase& rFilter, const OUString& rServiceName, const awt::Rectangle& rShapeRect )
2125 OUString aServiceName = rServiceName;
2126 switch( meFrameType )
2128 case FRAMETYPE_OLEOBJECT:
2130 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
2131 if( rFilter.getOleObjectHelper().importOleObject( maShapeProperties, *mxOleObjectInfo, aOleSize ) )
2132 aServiceName = "com.sun.star.drawing.OLE2Shape";
2134 // get the path to the representation graphic
2135 OUString aGraphicPath;
2136 if( !mxOleObjectInfo->maShapeId.isEmpty() )
2137 if( ::oox::vml::Drawing* pVmlDrawing = rFilter.getVmlDrawing() )
2138 if( const ::oox::vml::ShapeBase* pVmlShape = pVmlDrawing->getShapes().getShapeById( mxOleObjectInfo->maShapeId ) )
2139 aGraphicPath = pVmlShape->getGraphicPath();
2141 // import and store the graphic
2142 if( !aGraphicPath.isEmpty() )
2144 // Transfer shape's width and height to graphicsfilter (can be used by WMF/EMF)
2145 WmfExternal aExtHeader;
2146 aExtHeader.mapMode = 8; // MM_ANISOTROPIC
2147 aExtHeader.xExt = rShapeRect.Width;
2148 aExtHeader.yExt = rShapeRect.Height;
2150 Reference< graphic::XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic( aGraphicPath, &aExtHeader );
2151 if( xGraphic.is() )
2152 maShapeProperties.setProperty(PROP_Graphic, xGraphic);
2155 break;
2157 default:;
2159 return aServiceName;
2162 void Shape::finalizeXShape( XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes )
2164 switch( meFrameType )
2166 case FRAMETYPE_CHART:
2168 OSL_ENSURE( !mxChartShapeInfo->maFragmentPath.isEmpty(), "Shape::finalizeXShape - missing chart fragment" );
2169 if( mxShape.is() && !mxChartShapeInfo->maFragmentPath.isEmpty() ) try
2171 // set the chart2 OLE class ID at the OLE shape
2172 PropertySet aShapeProp( mxShape );
2173 aShapeProp.setProperty( PROP_CLSID, OUString( "12dcae26-281f-416f-a234-c3086127382e" ) );
2175 // get the XModel interface of the embedded object from the OLE shape
2176 Reference< frame::XModel > xDocModel;
2177 aShapeProp.getProperty( xDocModel, PROP_Model );
2178 Reference< chart2::XChartDocument > xChartDoc( xDocModel, UNO_QUERY_THROW );
2180 // load the chart data from the XML fragment
2181 #if ENABLE_WASM_STRIP_CHART
2182 (void) rFilter;
2183 (void) rxShapes;
2184 #else
2185 // WASM_CHART change
2186 // TODO: Instead of using convertFromModel an alternative may be
2187 // added to convert not to Chart/OLE SdrObejct, but to GraphicObject
2188 // with the Chart visualization. There should be a preview available
2189 // in the imported chart data
2190 bool bMSO2007Doc = rFilter.isMSO2007Document();
2191 chart::ChartSpaceModel aModel(bMSO2007Doc);
2192 oox::ppt::PowerPointImport* pPowerPointImport
2193 = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilter);
2195 ClrMapPtr pClrMap; // The original color map
2196 if (pPowerPointImport)
2198 // Use a copy of current color map, which the fragment may override locally
2199 pClrMap = pPowerPointImport->getActualSlidePersist()->getClrMap();
2200 aModel.mpClrMap = pClrMap ? std::make_shared<ClrMap>(*pClrMap)
2201 : std::make_shared<ClrMap>();
2202 pPowerPointImport->getActualSlidePersist()->setClrMap(aModel.mpClrMap);
2205 rtl::Reference<chart::ChartSpaceFragment> pChartSpaceFragment = new chart::ChartSpaceFragment(
2206 rFilter, mxChartShapeInfo->maFragmentPath, aModel );
2207 const OUString aThemeOverrideFragmentPath( pChartSpaceFragment->
2208 getFragmentPathFromFirstTypeFromOfficeDoc(u"themeOverride") );
2209 rFilter.importFragment( pChartSpaceFragment );
2211 // The original theme.
2212 ThemePtr pTheme;
2214 if (!aThemeOverrideFragmentPath.isEmpty() && pPowerPointImport)
2216 // Handle theme override.
2217 uno::Reference< xml::sax::XFastSAXSerializable > xDoc(
2218 rFilter.importFragment(aThemeOverrideFragmentPath), uno::UNO_QUERY_THROW);
2219 pTheme = pPowerPointImport->getActualSlidePersist()->getTheme();
2220 auto pThemeOverride = std::make_shared<Theme>(*pTheme);
2221 rFilter.importFragment(
2222 new ThemeOverrideFragmentHandler(rFilter, aThemeOverrideFragmentPath, *pThemeOverride, *pThemeOverride->getTheme()),
2223 xDoc);
2224 pPowerPointImport->getActualSlidePersist()->setTheme(pThemeOverride);
2227 // convert imported chart model to chart document
2228 Reference< drawing::XShapes > xExternalPage;
2229 if( !mxChartShapeInfo->mbEmbedShapes )
2230 xExternalPage = rxShapes;
2231 if( rFilter.getChartConverter() )
2233 rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
2234 if( !xChartDoc->hasInternalDataProvider() )
2236 Reference< chart2::data::XDataReceiver > xDataRec( xChartDoc, UNO_QUERY );
2237 Reference< chart2::data::XDataSource > xData = xDataRec->getUsedData();
2238 if( !xData->getDataSequences().hasElements() || !xData->getDataSequences()[0]->getValues().is() ||
2239 !xData->getDataSequences()[0]->getValues()->getData().hasElements() )
2241 rFilter.useInternalChartDataTable( true );
2242 rFilter.getChartConverter()->convertFromModel( rFilter, aModel, xChartDoc, xExternalPage, mxShape->getPosition(), mxShape->getSize() );
2243 rFilter.useInternalChartDataTable( false );
2249 if (pPowerPointImport)
2251 if (!aThemeOverrideFragmentPath.isEmpty())
2253 // Restore the original theme.
2254 pPowerPointImport->getActualSlidePersist()->setTheme(pTheme);
2256 // Restore the original color map
2257 pPowerPointImport->getActualSlidePersist()->setClrMap(pClrMap);
2259 #endif
2261 catch( Exception& )
2265 break;
2267 default:;
2271 void Shape::putPropertyToGrabBag( const OUString& sPropertyName, const Any& aPropertyValue )
2273 PropertyValue aNewProperty;
2274 aNewProperty.Name = sPropertyName;
2275 aNewProperty.Value = aPropertyValue;
2276 putPropertyToGrabBag( aNewProperty );
2279 void Shape::putPropertyToGrabBag( const PropertyValue& pProperty )
2281 Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2282 Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2283 const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2284 if( mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName ) )
2286 Sequence< PropertyValue > aGrabBag;
2287 xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2289 sal_Int32 length = aGrabBag.getLength();
2290 aGrabBag.realloc( length + 1 );
2291 aGrabBag.getArray()[length] = pProperty;
2293 xSet->setPropertyValue( aGrabBagPropName, Any( aGrabBag ) );
2297 void Shape::putPropertiesToGrabBag( const Sequence< PropertyValue >& aProperties )
2299 Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
2300 Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() );
2301 const OUString aGrabBagPropName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
2302 if( !(mxShape.is() && xSet.is() && xSetInfo.is() && xSetInfo->hasPropertyByName( aGrabBagPropName )) )
2303 return;
2305 // get existing grab bag
2306 Sequence< PropertyValue > aGrabBag;
2307 xSet->getPropertyValue( aGrabBagPropName ) >>= aGrabBag;
2309 std::vector<PropertyValue> aVec;
2310 aVec.reserve(aProperties.getLength());
2312 // put the new items
2313 std::transform(aProperties.begin(), aProperties.end(), std::back_inserter(aVec),
2314 [](const PropertyValue& rProp) {
2315 PropertyValue aProp;
2316 aProp.Name = rProp.Name;
2317 aProp.Value = rProp.Value;
2318 return aProp;
2321 // put it back to the shape
2322 xSet->setPropertyValue( aGrabBagPropName, Any( comphelper::concatSequences(aGrabBag, aVec) ) );
2325 FillProperties Shape::getActualFillProperties(const Theme* pTheme, const FillProperties* pParentShapeFillProps) const
2327 FillProperties aFillProperties;
2328 aFillProperties.moFillType = XML_noFill;
2330 // Reference shape properties
2331 aFillProperties.assignUsed( *mpShapeRefFillPropPtr );
2333 // Theme
2334 if( pTheme != nullptr )
2336 if( const ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
2338 if( const FillProperties* pFillProps = pTheme->getFillStyle( pFillRef->mnThemedIdx ) )
2339 aFillProperties.assignUsed( *pFillProps );
2343 // Properties specified directly for this shape
2344 aFillProperties.assignUsed(getFillProperties());
2346 // Parent shape's properties
2347 if ( pParentShapeFillProps != nullptr)
2348 if( getFillProperties().moFillType.has_value() && getFillProperties().moFillType.value() == XML_grpFill )
2349 aFillProperties.assignUsed( *pParentShapeFillProps );
2351 return aFillProperties;
2354 LineProperties Shape::getActualLineProperties(const Theme* pTheme) const
2356 LineProperties aLineProperties;
2357 aLineProperties.maLineFill.moFillType = XML_noFill;
2359 // Reference shape properties
2360 aLineProperties.assignUsed( *mpShapeRefLinePropPtr );
2362 // Theme
2363 if( pTheme != nullptr )
2365 if( const ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
2367 if( const LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
2368 aLineProperties.assignUsed( *pLineProps );
2372 // Properties specified directly for this shape
2373 aLineProperties.assignUsed( getLineProperties() );
2375 return aLineProperties;
2378 EffectProperties Shape::getActualEffectProperties(const Theme* pTheme) const
2380 EffectProperties aEffectProperties;
2382 // Reference shape properties
2383 aEffectProperties.assignUsed( *mpShapeRefEffectPropPtr );
2385 // Theme
2386 if( pTheme != nullptr )
2388 if( const ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
2390 if( const EffectProperties* pEffectProps = pTheme->getEffectStyle( pEffectRef->mnThemedIdx ) )
2391 aEffectProperties.assignUsed( *pEffectProps );
2395 // Properties specified directly for this shape
2396 aEffectProperties.assignUsed ( getEffectProperties() );
2398 return aEffectProperties;
2401 uno::Sequence< uno::Sequence< uno::Any > > Shape::resolveRelationshipsOfTypeFromOfficeDoc(core::XmlFilterBase& rFilter, const OUString& sFragment, std::u16string_view sType )
2403 uno::Sequence< uno::Sequence< uno::Any > > xRelListTemp;
2404 sal_Int32 counter = 0;
2406 core::RelationsRef xRels = rFilter.importRelations( sFragment );
2407 if ( xRels )
2409 core::RelationsRef xImageRels = xRels->getRelationsFromTypeFromOfficeDoc( sType );
2410 if ( xImageRels )
2412 xRelListTemp.realloc( xImageRels->size() );
2413 auto pxRelListTemp = xRelListTemp.getArray();
2414 for (auto const& imageRel : *xImageRels)
2416 uno::Sequence< uno::Any > diagramRelTuple (3);
2417 auto pdiagramRelTuple = diagramRelTuple.getArray();
2418 // [0] => RID, [1] => InputStream [2] => extension
2419 OUString sRelId = imageRel.second.maId;
2421 pdiagramRelTuple[0] <<= sRelId;
2422 OUString sTarget = xImageRels->getFragmentPathFromRelId( sRelId );
2424 uno::Reference< io::XInputStream > xImageInputStrm( rFilter.openInputStream( sTarget ), uno::UNO_SET_THROW );
2425 StreamDataSequence dataSeq;
2426 if ( rFilter.importBinaryData( dataSeq, sTarget ) )
2428 pdiagramRelTuple[1] <<= dataSeq;
2431 pdiagramRelTuple[2] <<= sTarget.copy( sTarget.lastIndexOf(".") );
2433 pxRelListTemp[counter] = diagramRelTuple;
2434 ++counter;
2436 xRelListTemp.realloc(counter);
2440 return xRelListTemp;
2443 void Shape::cloneFillProperties()
2445 auto pFillProperties = std::make_shared<FillProperties>();
2446 pFillProperties->assignUsed(*mpFillPropertiesPtr);
2447 mpFillPropertiesPtr = pFillProperties;
2451 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */