Bump version to 24.04.3.4
[LibreOffice.git] / oox / source / vml / vmlshape.cxx
blob8f16c62672110f221dcec5562a97a5ce1e9f26a6
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 <algorithm>
22 #include <optional>
24 #include <o3tl/safeint.hxx>
25 #include <oox/vml/vmlshape.hxx>
26 #include <utility>
27 #include <vcl/wmfexternal.hxx>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
31 #include <com/sun/star/drawing/FillStyle.hpp>
32 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
33 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
34 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
35 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
36 #include <com/sun/star/drawing/XShapes.hpp>
37 #include <com/sun/star/drawing/XControlShape.hpp>
38 #include <com/sun/star/graphic/XGraphic.hpp>
39 #include <com/sun/star/table/BorderLine2.hpp>
40 #include <com/sun/star/text/HoriOrientation.hpp>
41 #include <com/sun/star/text/RelOrientation.hpp>
42 #include <com/sun/star/text/SizeType.hpp>
43 #include <com/sun/star/text/VertOrientation.hpp>
44 #include <com/sun/star/text/WrapTextMode.hpp>
45 #include <com/sun/star/lang/XServiceInfo.hpp>
46 #include <com/sun/star/text/TextContentAnchorType.hpp>
47 #include <com/sun/star/text/GraphicCrop.hpp>
48 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
49 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
50 #include <com/sun/star/text/WritingMode2.hpp>
51 #include <com/sun/star/drawing/ColorMode.hpp>
52 #include <sal/log.hxx>
53 #include <oox/drawingml/shapepropertymap.hxx>
54 #include <oox/helper/graphichelper.hxx>
55 #include <oox/helper/propertyset.hxx>
56 #include <oox/ole/axcontrol.hxx>
57 #include <oox/ole/axcontrolfragment.hxx>
58 #include <oox/ole/oleobjecthelper.hxx>
59 #include <oox/token/properties.hxx>
60 #include <oox/token/tokens.hxx>
61 #include <oox/vml/vmldrawing.hxx>
62 #include <oox/vml/vmlshapecontainer.hxx>
63 #include <oox/vml/vmltextbox.hxx>
64 #include <oox/core/xmlfilterbase.hxx>
65 #include <oox/helper/containerhelper.hxx>
66 #include <svx/msdffdef.hxx>
67 #include <svx/sdtagitm.hxx>
68 #include <svx/svdobj.hxx>
69 #include <comphelper/sequence.hxx>
70 #include <comphelper/processfactory.hxx>
71 #include <comphelper/propertyvalue.hxx>
72 #include <comphelper/storagehelper.hxx>
73 #include <o3tl/string_view.hxx>
75 using ::com::sun::star::beans::XPropertySet;
76 using ::com::sun::star::uno::Any;
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::text;
81 namespace oox::vml {
83 using namespace ::com::sun::star::drawing;
84 using namespace ::com::sun::star::graphic;
85 using namespace ::com::sun::star::uno;
86 using namespace ::com::sun::star::io;
88 using ::oox::core::XmlFilterBase;
90 namespace {
92 const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75;
93 const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201;
95 awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
97 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
98 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
99 awt::Point aAbsPoint;
100 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
101 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
102 return aAbsPoint;
105 awt::Rectangle lclGetAbsRect( const awt::Rectangle& rRelRect, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
107 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
108 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
109 awt::Rectangle aAbsRect;
110 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
111 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
112 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
113 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
114 return aAbsRect;
117 /// Count the crop value based on a crop fraction and a reference size.
118 sal_Int32 lclConvertCrop(std::u16string_view rCrop, sal_uInt32 nSize)
120 if (o3tl::ends_with(rCrop, u"f"))
122 // Numeric value is specified in 1/65536-ths.
123 sal_uInt32 nCrop = o3tl::toUInt32(rCrop.substr(0, rCrop.size() - 1));
124 return (nCrop * nSize) / 65536;
127 return 0;
130 } // namespace
132 ShapeTypeModel::ShapeTypeModel():
133 mbAutoHeight( false ),
134 mbVisible( true )
138 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
140 assignIfUsed( moShapeType, rSource.moShapeType );
141 assignIfUsed( moCoordPos, rSource.moCoordPos );
142 assignIfUsed( moCoordSize, rSource.moCoordSize );
143 /* The style properties position, left, top, width, height, margin-left,
144 margin-top are not derived from shape template to shape. */
145 maStrokeModel.assignUsed( rSource.maStrokeModel );
146 maFillModel.assignUsed( rSource.maFillModel );
147 assignIfUsed( moGraphicPath, rSource.moGraphicPath );
148 assignIfUsed( moGraphicTitle, rSource.moGraphicTitle );
151 ShapeType::ShapeType( Drawing& rDrawing ) :
152 mrDrawing( rDrawing )
156 ShapeType::~ShapeType()
160 sal_Int32 ShapeType::getShapeType() const
162 return maTypeModel.moShapeType.value_or( 0 );
165 OUString ShapeType::getGraphicPath() const
167 return maTypeModel.moGraphicPath.value_or( OUString() );
170 awt::Rectangle ShapeType::getCoordSystem() const
172 Int32Pair aCoordPos = maTypeModel.moCoordPos.value_or( Int32Pair( 0, 0 ) );
173 Int32Pair aCoordSize = maTypeModel.moCoordSize.value_or( Int32Pair( 1000, 1000 ) );
174 if( aCoordSize.first == 0 )
175 aCoordSize.first = 1;
176 if( aCoordSize.second == 0 )
177 aCoordSize.second = 1;
178 return awt::Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second );
181 awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
183 return pParentAnchor ?
184 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
185 getAbsRectangle();
188 awt::Rectangle ShapeType::getAbsRectangle() const
190 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
192 sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
193 if ( nWidth == 0 )
194 nWidth = 1;
196 sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
197 if ( nHeight == 0 )
198 nHeight = 1;
200 sal_Int32 nLeft;
201 if (o3tl::checked_add<sal_Int32>(ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maLeft, 0, true, true),
202 ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true),
203 nLeft))
205 SAL_WARN("oox", "overflow in addition");
206 nLeft = 0;
208 if (nLeft == 0 && maTypeModel.maPosition == "absolute")
209 nLeft = 1;
211 return awt::Rectangle(
212 nLeft,
213 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
214 nWidth, nHeight );
217 awt::Rectangle ShapeType::getRelRectangle() const
219 sal_Int32 nWidth = maTypeModel.maWidth.toInt32();
220 if ( nWidth == 0 )
221 nWidth = 1;
223 sal_Int32 nHeight = maTypeModel.maHeight.toInt32();
224 if ( nHeight == 0 )
225 nHeight = 1;
227 return awt::Rectangle(
228 maTypeModel.maLeft.toInt32(),
229 maTypeModel.maTop.toInt32(),
230 nWidth, nHeight );
233 ClientData::ClientData() :
234 mnObjType( XML_TOKEN_INVALID ),
235 mnTextHAlign( XML_Left ),
236 mnTextVAlign( XML_Top ),
237 mnCol( -1 ),
238 mnRow( -1 ),
239 mnChecked( VML_CLIENTDATA_UNCHECKED ),
240 mnDropStyle( XML_Combo ),
241 mnDropLines( 1 ),
242 mnVal( 0 ),
243 mnMin( 0 ),
244 mnMax( 0 ),
245 mnInc( 0 ),
246 mnPage( 0 ),
247 mnSelType( XML_Single ),
248 mnVTEdit( VML_CLIENTDATA_TEXT ),
249 mbPrintObject( true ),
250 mbVisible( false ),
251 mbDde( false ),
252 mbNo3D( false ),
253 mbNo3D2( false ),
254 mbMultiLine( false ),
255 mbVScroll( false ),
256 mbSecretEdit( false )
260 ShapeModel::ShapeModel()
261 : mbIsSignatureLine(false)
262 , mbSignatureLineShowSignDate(true)
263 , mbSignatureLineCanAddComment(false)
264 , mbInGroup(false)
268 ShapeModel::~ShapeModel()
272 TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
274 mxTextBox.reset( new TextBox(rModel) );
275 return *mxTextBox;
278 ClientData& ShapeModel::createClientData()
280 mxClientData.reset( new ClientData );
281 return *mxClientData;
284 ShapeBase::ShapeBase( Drawing& rDrawing ) :
285 ShapeType( rDrawing )
289 void ShapeBase::finalizeFragmentImport()
291 if( maShapeModel.maType.getLength() <= 1 )
292 return;
294 OUString aType = maShapeModel.maType;
295 if (aType[ 0 ] == '#')
296 aType = aType.copy(1);
297 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( aType ) )
299 // Make sure that the props from maTypeModel have priority over the props from
300 // the shape type.
301 StrokeModel aMergedStrokeModel;
302 aMergedStrokeModel.assignUsed(pShapeType->getTypeModel().maStrokeModel);
303 aMergedStrokeModel.assignUsed(maTypeModel.maStrokeModel);
304 FillModel aMergedFillModel;
305 aMergedFillModel.assignUsed(pShapeType->getTypeModel().maFillModel);
306 aMergedFillModel.assignUsed(maTypeModel.maFillModel);
308 maTypeModel.assignUsed( pShapeType->getTypeModel() );
309 maTypeModel.maStrokeModel = aMergedStrokeModel;
310 maTypeModel.maFillModel = aMergedFillModel;
312 else {
313 // Temporary fix, shapetype not found if referenced from different substream
314 // FIXME: extend scope of ShapeContainer to store all shapetypes from the document
315 static constexpr OUString sShapeTypePrefix = u"shapetype_"_ustr;
316 OUString tmp;
317 if (aType.startsWith(sShapeTypePrefix)) {
318 maTypeModel.moShapeType = o3tl::toInt32(aType.subView(sShapeTypePrefix.getLength()));
320 else if (aType.startsWith("_x0000_t", &tmp)) {
321 maTypeModel.moShapeType = tmp.toInt32();
326 OUString ShapeBase::getShapeName() const
328 if( !maTypeModel.maShapeName.isEmpty() )
329 return maTypeModel.maShapeName;
331 OUString aBaseName = mrDrawing.getShapeBaseName( *this );
332 if( !aBaseName.isEmpty() )
334 sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
335 if( nShapeIdx > 0 )
336 return aBaseName + OUStringChar(' ') + OUString::number( nShapeIdx );
339 return OUString();
342 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
344 return nullptr;
347 const ShapeBase* ShapeBase::getChildById( const OUString& ) const
349 return nullptr;
352 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
354 Reference< XShape > xShape;
355 if( mrDrawing.isShapeSupported( *this ) )
357 /* Calculate shape rectangle. Applications may do something special
358 according to some imported shape client data (e.g. Excel cell anchor). */
359 awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
361 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
363 xShape = implConvertAndInsert( rxShapes, aShapeRect );
364 if( xShape.is() )
366 // set imported or generated shape name (not supported by form controls)
367 PropertySet aShapeProp( xShape );
368 if( aShapeProp.hasProperty( PROP_Name ) )
369 aShapeProp.setProperty( PROP_Name, getShapeName() );
370 uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
372 OUString sLinkChainName = getTypeModel().maLegacyId;
373 sal_Int32 id = 0;
374 sal_Int32 idPos = sLinkChainName.indexOf("_x");
375 sal_Int32 seq = 0;
376 if (idPos >= 0)
378 sal_Int32 seqPos = sLinkChainName.indexOf("_s",idPos);
379 if (idPos < seqPos)
381 auto idPosEnd = idPos+2;
382 id = o3tl::toInt32(sLinkChainName.subView(idPosEnd, seqPos - idPosEnd));
383 seq = o3tl::toInt32(sLinkChainName.subView(seqPos+2));
387 OUString s_mso_next_textbox;
388 if( getTextBox() )
389 s_mso_next_textbox = getTextBox()->msNextTextbox;
390 if( s_mso_next_textbox.startsWith("#") )
391 s_mso_next_textbox = s_mso_next_textbox.copy(1);
393 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
395 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
396 uno::Any aAny = propertySet->getPropertyValue("FrameInteropGrabBag");
397 auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >());
399 aGrabBag.push_back(comphelper::makePropertyValue("VML-Z-ORDER", maTypeModel.maZIndex.toInt32()));
401 if( !s_mso_next_textbox.isEmpty() )
402 aGrabBag.push_back(comphelper::makePropertyValue("mso-next-textbox", s_mso_next_textbox));
404 if( !sLinkChainName.isEmpty() )
406 aGrabBag.push_back(comphelper::makePropertyValue("TxbxHasLink", true));
407 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Id", id));
408 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Seq", seq));
409 aGrabBag.push_back(comphelper::makePropertyValue("LinkChainName", sLinkChainName));
412 if(!maTypeModel.maRotation.isEmpty())
413 aGrabBag.push_back(comphelper::makePropertyValue("mso-rotation-angle", ConversionHelper::decodeRotation(maTypeModel.maRotation).get()));
414 propertySet->setPropertyValue("FrameInteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag)));
415 sal_Int32 backColorTransparency = 0;
416 propertySet->getPropertyValue("BackColorTransparency")
417 >>= backColorTransparency;
418 if (propertySet->getPropertyValue("FillStyle") == FillStyle_NONE &&
419 backColorTransparency == 100)
421 // If there is no fill, the Word default is 100% transparency.
422 propertySet->setPropertyValue("FillTransparence", Any(sal_Int16(100)));
425 else
427 if( maTypeModel.maZIndex.toInt32() )
429 uno::Sequence<beans::PropertyValue> aGrabBag;
430 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
431 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
432 sal_Int32 length;
434 length = aGrabBag.getLength();
435 aGrabBag.realloc( length+1 );
436 auto pGrabBag = aGrabBag.getArray();
437 pGrabBag[length].Name = "VML-Z-ORDER";
438 pGrabBag[length].Value <<= maTypeModel.maZIndex.toInt32();
440 if( !s_mso_next_textbox.isEmpty() )
442 length = aGrabBag.getLength();
443 aGrabBag.realloc( length+1 );
444 pGrabBag = aGrabBag.getArray();
445 pGrabBag[length].Name = "mso-next-textbox";
446 pGrabBag[length].Value <<= s_mso_next_textbox;
449 if( !sLinkChainName.isEmpty() )
451 length = aGrabBag.getLength();
452 aGrabBag.realloc( length+4 );
453 pGrabBag = aGrabBag.getArray();
454 pGrabBag[length].Name = "TxbxHasLink";
455 pGrabBag[length].Value <<= true;
456 pGrabBag[length+1].Name = "Txbx-Id";
457 pGrabBag[length+1].Value <<= id;
458 pGrabBag[length+2].Name = "Txbx-Seq";
459 pGrabBag[length+2].Value <<= seq;
460 pGrabBag[length+3].Name = "LinkChainName";
461 pGrabBag[length+3].Value <<= sLinkChainName;
463 propertySet->setPropertyValue( "InteropGrabBag", uno::Any(aGrabBag) );
466 Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
467 if ( xControlShape.is() && !getTypeModel().mbVisible )
469 PropertySet aControlShapeProp( xControlShape->getControl() );
470 aControlShapeProp.setProperty( PROP_EnableVisible, uno::Any( false ) );
473 xShape = finalImplConvertAndInsert(xShape);
474 /* Notify the drawing that a new shape has been inserted. For
475 convenience, pass the rectangle that contains position and
476 size of the shape. */
477 bool bGroupChild = pParentAnchor != nullptr;
478 mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
481 else
482 SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
484 return xShape;
487 awt::Rectangle ShapeBase::getShapeRectangle() const
489 /* Calculate shape rectangle. Applications may do something special
490 according to some imported shape client data (e.g. Excel cell anchor). */
491 return calcShapeRectangle(nullptr);
494 void ShapeBase::setContainer(ShapeContainer* pContainer) { mpContainer = pContainer; }
496 ShapeContainer* ShapeBase::getContainer() const { return mpContainer; }
498 // protected ------------------------------------------------------------------
500 awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
502 /* Calculate shape rectangle. Applications may do something special
503 according to some imported shape client data (e.g. Excel cell anchor). */
504 awt::Rectangle aShapeRect;
505 const ClientData* pClientData = getClientData();
506 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
507 aShapeRect = getRectangle( pParentAnchor );
508 return aShapeRect;
511 ::oox::drawingml::ShapePropertyMap ShapeBase::makeShapePropertyMap() const
513 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
514 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
515 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
516 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
517 return aPropMap;
520 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
522 ::oox::drawingml::ShapePropertyMap aPropMap(makeShapePropertyMap());
524 uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
525 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
527 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
528 // Any other service supporting the ShadowFormat property?
529 maTypeModel.maShadowModel.pushToPropMap(aPropMap, rGraphicHelper);
530 // TextFrames have BackColor, not FillColor
531 if (aPropMap.hasProperty(PROP_FillColor))
533 aPropMap.setAnyProperty(PROP_BackColor, aPropMap.getProperty(PROP_FillColor));
534 aPropMap.erase(PROP_FillColor);
536 // TextFrames have BackColorTransparency, not FillTransparence
537 if (aPropMap.hasProperty(PROP_FillTransparence))
539 aPropMap.setAnyProperty(PROP_BackColorTransparency, aPropMap.getProperty(PROP_FillTransparence));
540 aPropMap.erase(PROP_FillTransparence);
542 // And no LineColor property; individual borders can have colors and widths
543 std::optional<sal_Int32> oLineWidth;
544 if (maTypeModel.maStrokeModel.moWeight.has_value())
545 oLineWidth = ConversionHelper::decodeMeasureToHmm(
546 rGraphicHelper, maTypeModel.maStrokeModel.moWeight.value(), 0, false, false);
547 if (aPropMap.hasProperty(PROP_LineColor))
549 uno::Reference<beans::XPropertySet> xPropertySet(rxShape, uno::UNO_QUERY);
550 static const sal_Int32 aBorders[] = {
551 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
553 for (sal_Int32 nBorder : aBorders)
555 table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<table::BorderLine2>();
556 aBorderLine.Color = aPropMap.getProperty(PROP_LineColor).get<sal_Int32>();
557 if (oLineWidth)
558 aBorderLine.LineWidth = *oLineWidth;
559 aPropMap.setProperty(nBorder, aBorderLine);
561 aPropMap.erase(PROP_LineColor);
564 else if (xSInfo->supportsService("com.sun.star.drawing.CustomShape"))
566 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
567 maTypeModel.maTextpathModel.pushToPropMap(aPropMap, rxShape, rGraphicHelper);
570 PropertySet( rxShape ).setProperties( aPropMap );
573 SimpleShape::SimpleShape( Drawing& rDrawing, OUString aService ) :
574 ShapeBase( rDrawing ),
575 maService(std::move( aService ))
579 static void lcl_setSurround(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
581 OUString aWrapType = rTypeModel.moWrapType.value_or("");
583 // Extreme negative top margin? Then the shape will end up at the top of the page, it's pointless to perform any kind of wrapping.
584 sal_Int32 nMarginTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, rTypeModel.maMarginTop, 0, false, true);
585 if (nMarginTop < -35277) // Less than 1000 points.
586 aWrapType.clear();
588 css::text::WrapTextMode nSurround = css::text::WrapTextMode_THROUGH;
589 if ( aWrapType == "square" || aWrapType == "tight" ||
590 aWrapType == "through" )
592 nSurround = css::text::WrapTextMode_PARALLEL;
593 if ( !rTypeModel.moWrapSide.has_value() )
594 ; // leave as PARALLEL
595 else if ( rTypeModel.moWrapSide.value() == "left" )
596 nSurround = css::text::WrapTextMode_LEFT;
597 else if ( rTypeModel.moWrapSide.value() == "right" )
598 nSurround = css::text::WrapTextMode_RIGHT;
600 else if ( aWrapType == "topAndBottom" )
601 nSurround = css::text::WrapTextMode_NONE;
603 rPropSet.setProperty(PROP_Surround, static_cast<sal_Int32>(nSurround));
604 rPropSet.setProperty(PROP_SurroundContour, aWrapType == "tight");
607 static void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
609 if ( rTypeModel.maPosition == "absolute" )
611 // Word supports as-character (inline) and at-character only, absolute can't be inline.
612 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
613 // anchor is set after insertion, so reset to NONE
614 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::NONE));
616 if ( rTypeModel.maPositionVerticalRelative == "page" )
618 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
620 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
622 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
624 else if (rTypeModel.maPositionVerticalRelative == "top-margin-area")
626 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA_TOP);
628 else if (rTypeModel.maPositionVerticalRelative == "bottom-margin-area")
630 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA_BOTTOM);
632 else
634 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
637 else if( rTypeModel.maPosition == "relative" )
638 { // I'm not very sure this is correct either.
639 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
640 // anchor is set after insertion, so reset to NONE
641 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::NONE));
643 else // static (is the default) means anchored inline
645 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
646 // Use top orientation, this one seems similar to what MSO uses as inline
647 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::TOP));
650 // if the anchor is not inline, and is relative to left or right, then apply the margins
651 bool bHonorMargins = rTypeModel.maPosition == "relative" || rTypeModel.maPosition == "absolute";
652 if ( rTypeModel.maPositionHorizontal == "center" )
654 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::CENTER));
655 bHonorMargins = false;
657 else if ( rTypeModel.maPositionHorizontal == "left" )
658 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::LEFT));
659 else if ( rTypeModel.maPositionHorizontal == "right" )
660 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::RIGHT));
661 else if ( rTypeModel.maPositionHorizontal == "inside" )
663 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::LEFT));
664 rPropSet.setAnyProperty(PROP_PageToggle, Any(true));
666 else if ( rTypeModel.maPositionHorizontal == "outside" )
668 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::RIGHT));
669 rPropSet.setAnyProperty(PROP_PageToggle, Any(true));
671 else
672 bHonorMargins = false;
674 if ( rTypeModel.maPositionHorizontalRelative == "page" )
675 rPropSet.setAnyProperty(PROP_HoriOrientRelation, Any(text::RelOrientation::PAGE_FRAME));
676 else if ( rTypeModel.maPositionHorizontalRelative == "margin" )
677 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
678 else if (rTypeModel.maPositionHorizontalRelative == "right-margin-area" ||
679 rTypeModel.maPositionHorizontalRelative == "inner-margin-area")
680 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::PAGE_RIGHT);
681 else if (rTypeModel.maPositionHorizontalRelative == "left-margin-area" ||
682 rTypeModel.maPositionHorizontalRelative == "outer-margin-area")
683 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::PAGE_LEFT);
684 else // "text"
686 if (bHonorMargins)
687 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::PRINT_AREA);
688 else
689 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::FRAME);
691 if ( rTypeModel.maPositionVertical == "center" )
692 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::CENTER));
693 else if ( rTypeModel.maPositionVertical == "top" )
694 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::TOP));
695 else if ( rTypeModel.maPositionVertical == "bottom" )
696 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::BOTTOM));
697 else if ( rTypeModel.maPositionVertical == "inside" )
698 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::TOP));
699 else if ( rTypeModel.maPositionVertical == "outside" )
700 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::BOTTOM));
702 lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper );
705 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
707 awt::Rectangle aShapeRect(rShapeRect);
708 std::optional<Degree100> oRotation;
709 bool bFlipX = false, bFlipY = false;
710 // tdf#137765: skip this rotation for line shapes
711 if (!maTypeModel.maRotation.isEmpty() && maService != "com.sun.star.drawing.LineShape")
712 oRotation = ConversionHelper::decodeRotation(maTypeModel.maRotation);
713 if (!maTypeModel.maFlip.isEmpty())
715 if (maTypeModel.maFlip.startsWith("x"))
717 bFlipX = true;
719 if (maTypeModel.maFlip.endsWith("y"))
721 bFlipY = true;
725 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
726 SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
727 if( pShape && getShapeType() >= 0 )
729 //The resize autoshape to fit text attr of FontWork/Word-Art should always be false
730 //for the fallback geometry.
731 sal_Int32 nType = getShapeType();
732 if((mso_sptTextSimple <= nType && nType <= mso_sptTextOnRing)
733 || (mso_sptTextPlainText <= nType && nType <= mso_sptTextCanDown))
735 pShape->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
736 pShape->SetMergedItem(makeSdrTextAutoGrowWidthItem(false));
739 convertShapeProperties( xShape );
741 // Handle left/right/top/bottom wrap distance.
742 // Default value of mso-wrap-distance-left/right is supposed to be 0 (see
743 // 19.1.2.19 of the VML spec), but Word implements a non-zero value.
744 // [MS-ODRAW] says the below default value in 2.3.4.9.
745 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
746 OUString aWrapDistanceLeft = OUString::number(0x0001BE7C);
747 if (!maTypeModel.maWrapDistanceLeft.isEmpty())
748 aWrapDistanceLeft = maTypeModel.maWrapDistanceLeft;
749 sal_Int32 nWrapDistanceLeft = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceLeft, 0, true, false);
750 PropertySet(xShape).setAnyProperty(PROP_LeftMargin, uno::Any(nWrapDistanceLeft));
751 OUString aWrapDistanceRight = OUString::number(0x0001BE7C);
752 if (!maTypeModel.maWrapDistanceRight.isEmpty())
753 aWrapDistanceRight = maTypeModel.maWrapDistanceRight;
754 sal_Int32 nWrapDistanceRight = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceRight, 0, true, false);
755 PropertySet(xShape).setAnyProperty(PROP_RightMargin, uno::Any(nWrapDistanceRight));
756 sal_Int32 nWrapDistanceTop = 0;
757 if (!maTypeModel.maWrapDistanceTop.isEmpty())
758 nWrapDistanceTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceTop, 0, false, true);
759 PropertySet(xShape).setAnyProperty(PROP_TopMargin, uno::Any(nWrapDistanceTop));
760 sal_Int32 nWrapDistanceBottom = 0;
761 if (!maTypeModel.maWrapDistanceBottom.isEmpty())
762 nWrapDistanceBottom = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceBottom, 0, false, true);
763 PropertySet(xShape).setAnyProperty(PROP_BottomMargin, uno::Any(nWrapDistanceBottom));
765 if ( maService == "com.sun.star.text.TextFrame" )
767 PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, Any( maTypeModel.mbAutoHeight ) );
768 PropertySet( xShape ).setAnyProperty( PROP_SizeType, Any( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
769 if( getTextBox()->borderDistanceSet )
771 PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceLeft )));
772 PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceTop )));
773 PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceRight )));
774 PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceBottom )));
777 sal_Int16 nWritingMode = text::WritingMode2::LR_TB;
778 if (getTextBox()->maLayoutFlow == "vertical" && maTypeModel.maLayoutFlowAlt.isEmpty())
780 nWritingMode = text::WritingMode2::TB_RL;
782 else if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
784 nWritingMode = text::WritingMode2::BT_LR;
786 if (nWritingMode != text::WritingMode2::LR_TB)
788 PropertySet(xShape).setAnyProperty(PROP_WritingMode, uno::Any(nWritingMode));
790 // tdf#123626
791 if (!maShapeModel.maHyperlink.isEmpty())
792 PropertySet(xShape).setAnyProperty(PROP_HyperLinkURL, Any(maShapeModel.maHyperlink));
794 else
796 // FIXME Setting the relative width/height only for everything but text frames as
797 // TextFrames already have relative width/height feature... but currently not working
798 // in the way we need.
800 // Set the relative width / height if any
801 if ( !maTypeModel.maWidthPercent.isEmpty( ) )
803 // Only page-relative width is supported ATM
804 if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
806 sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
807 // Only apply if nWidth != 0
808 if ( nWidth )
809 PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, Any( nWidth ) );
812 if ( !maTypeModel.maHeightPercent.isEmpty( ) )
814 // Only page-relative height is supported ATM
815 if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
817 sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
818 // Only apply if nHeight != 0
819 if ( nHeight )
820 PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, Any( nHeight ) );
824 // drawinglayer default is center, MSO default is top.
825 drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP;
826 if (maTypeModel.maVTextAnchor == "middle")
827 eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER;
828 else if (maTypeModel.maVTextAnchor == "bottom")
829 eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
830 PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, Any(eTextVerticalAdjust));
832 // tdf#97618
833 if(!maTypeModel.maWrapStyle.isEmpty())
834 PropertySet(xShape).setAnyProperty(PROP_TextWordWrap, Any(maTypeModel.maWrapStyle == "square"));
836 // tdf#123626
837 if (!maShapeModel.maHyperlink.isEmpty())
838 PropertySet(xShape).setAnyProperty(PROP_Hyperlink, Any(maShapeModel.maHyperlink));
840 PropertySet(xShape).setAnyProperty(PROP_TextAutoGrowHeight,
841 Any(maTypeModel.mbAutoHeight));
843 if (getTextBox())
845 getTextBox()->convert(xShape);
846 if (getTextBox()->borderDistanceSet)
848 awt::Size aSize = xShape->getSize();
849 PropertySet(xShape).setAnyProperty(PROP_TextLeftDistance, Any(sal_Int32(getTextBox()->borderDistanceLeft)));
850 PropertySet(xShape).setAnyProperty(PROP_TextUpperDistance, Any(sal_Int32(getTextBox()->borderDistanceTop)));
851 PropertySet(xShape).setAnyProperty(PROP_TextRightDistance, Any(sal_Int32(getTextBox()->borderDistanceRight)));
852 PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, Any(sal_Int32(getTextBox()->borderDistanceBottom)));
853 xShape->setSize(aSize);
858 // Import Legacy Fragments (if any)
859 if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
861 Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
862 if( xInStrm.is() )
863 PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
866 PropertySet aPropertySet(xShape);
867 if (xShape.is())
869 if (oRotation)
871 aPropertySet.setAnyProperty(PROP_RotateAngle, Any((*oRotation).get()));
872 uno::Reference<lang::XServiceInfo> xServiceInfo(rxShapes, uno::UNO_QUERY);
873 if (!xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
875 // If rotation is used, simple setPosition() is not enough.
876 aPropertySet.setAnyProperty(PROP_HoriOrientPosition, Any(aShapeRect.X));
877 aPropertySet.setAnyProperty(PROP_VertOrientPosition, Any(aShapeRect.Y));
881 // custom shape geometry attributes
882 std::vector<css::beans::PropertyValue> aPropVec;
884 // When flip has 'x' or 'y', the associated ShapeRect will be changed but direction change doesn't occur.
885 // It might occur internally in SdrObject of "sw" module, not here.
886 // The associated properties "PROP_MirroredX" and "PROP_MirroredY" have to be set here so that direction change will occur internally.
887 if (bFlipX)
888 aPropVec.push_back(comphelper::makePropertyValue("MirroredX", true));
889 if (bFlipY)
890 aPropVec.push_back(comphelper::makePropertyValue("MirroredY", true));
892 if (!maTypeModel.maAdjustments.isEmpty())
894 std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
895 sal_Int32 nIndex = 0;
898 std::u16string_view aToken = o3tl::getToken(maTypeModel.maAdjustments, 0, ',', nIndex);
899 drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue;
900 if (aToken.empty())
901 aAdjustmentValue.State = css::beans::PropertyState::PropertyState_DEFAULT_VALUE;
902 else
903 aAdjustmentValue.Value <<= o3tl::toInt32(aToken);
904 aAdjustmentValues.push_back(aAdjustmentValue);
905 } while (nIndex >= 0);
907 css::beans::PropertyValue aProp;
908 aProp.Name = "AdjustmentValues";
909 aProp.Value <<= comphelper::containerToSequence(aAdjustmentValues);
910 aPropVec.push_back(aProp);
913 if (!aPropVec.empty())
914 aPropertySet.setAnyProperty(PROP_CustomShapeGeometry, Any(comphelper::containerToSequence(aPropVec)));
917 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper );
919 return xShape;
922 Reference<XShape> SimpleShape::finalImplConvertAndInsert(const css::uno::Reference<css::drawing::XShape>& rxShape) const
924 // tdf#41466 This setting must be done here, because the position of textbox will be set as an
925 // effect of the PROP_TextBox property setting, and if we do this setting earlier (setting of
926 // properties of position and size) then the position of textbox will be set with wrong data.
927 // TODO: TextShape is set if we have rect shape in group; we should use the shape-with-textbox
928 // mechanism to handle this situation
929 if (getTextBox() && maService != "com.sun.star.text.TextFrame" && maService != "com.sun.star.drawing.TextShape"
930 && !maShapeModel.mbInGroup)
932 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
933 const auto& nLeft = ConversionHelper::decodeMeasureToHmm(
934 rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true);
935 PropertySet aPropertySet(rxShape);
936 aPropertySet.setProperty(PROP_HoriOrientPosition, nLeft);
937 const auto& nTop = ConversionHelper::decodeMeasureToHmm(
938 rGraphicHelper, maTypeModel.maMarginTop, 0, true, true);
939 aPropertySet.setProperty(PROP_VertOrientPosition, nTop);
940 aPropertySet.setProperty(PROP_TextBox, true);
942 // And these properties must be set after textbox creation (set PROP_Textbox property).
943 // Note: if you set a new property then you have to handle it in the proper
944 // SwTextBoxHelper::syncProperty function.
945 if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
946 aPropertySet.setAnyProperty(PROP_TextWritingMode, uno::Any(text::WritingMode2::BT_LR));
948 return ShapeBase::finalImplConvertAndInsert(rxShape);
950 Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
952 Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath);
953 return SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
956 Reference< XShape > SimpleShape::createPictureObject(const Reference< XShapes >& rxShapes,
957 const awt::Rectangle& rShapeRect,
958 uno::Reference<graphic::XGraphic> const & rxGraphic) const
960 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
961 if( xShape.is() )
963 PropertySet aPropSet(xShape);
964 if (rxGraphic.is())
966 aPropSet.setProperty(PROP_Graphic, rxGraphic);
968 uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
969 // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
970 if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
972 aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
973 aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
974 aPropSet.setProperty(PROP_Opaque, false);
976 // fdo#70457: preserve rotation information
977 if ( !maTypeModel.maRotation.isEmpty() )
978 aPropSet.setAnyProperty(PROP_RotateAngle, Any(ConversionHelper::decodeRotation(maTypeModel.maRotation).get()));
980 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
981 lcl_SetAnchorType(aPropSet, maTypeModel, rGraphicHelper);
983 const sal_Int32 nWrapDistanceLeft = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceLeft, 0, true, true);
984 const sal_Int32 nWrapDistanceRight = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceRight, 0, true, true);
985 const sal_Int32 nWrapDistanceTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceTop, 0, false, true);
986 const sal_Int32 nWrapDistanceBottom = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceBottom, 0, false, true);
987 aPropSet.setProperty(PROP_LeftMargin, uno::Any(nWrapDistanceLeft));
988 aPropSet.setProperty(PROP_RightMargin, uno::Any(nWrapDistanceRight));
989 aPropSet.setProperty(PROP_TopMargin, uno::Any(nWrapDistanceTop));
990 aPropSet.setProperty(PROP_BottomMargin, uno::Any(nWrapDistanceBottom));
992 if (maTypeModel.moCropBottom.has_value() || maTypeModel.moCropLeft.has_value() || maTypeModel.moCropRight.has_value() || maTypeModel.moCropTop.has_value())
994 text::GraphicCrop aGraphicCrop;
995 awt::Size aOriginalSize = rGraphicHelper.getOriginalSize(rxGraphic);
997 if (maTypeModel.moCropBottom.has_value())
998 aGraphicCrop.Bottom = lclConvertCrop(maTypeModel.moCropBottom.value(), aOriginalSize.Height);
999 if (maTypeModel.moCropLeft.has_value())
1000 aGraphicCrop.Left = lclConvertCrop(maTypeModel.moCropLeft.value(), aOriginalSize.Width);
1001 if (maTypeModel.moCropRight.has_value())
1002 aGraphicCrop.Right = lclConvertCrop(maTypeModel.moCropRight.value(), aOriginalSize.Width);
1003 if (maTypeModel.moCropTop.has_value())
1004 aGraphicCrop.Top = lclConvertCrop(maTypeModel.moCropTop.value(), aOriginalSize.Height);
1006 aPropSet.setProperty(PROP_GraphicCrop, aGraphicCrop);
1009 if (maTypeModel.mnGain == -70 && maTypeModel.mnBlacklevel == 70)
1011 // Map MSO 'washout' to our watermark colormode.
1012 aPropSet.setProperty(PROP_GraphicColorMode, uno::Any(drawing::ColorMode_WATERMARK));
1015 return xShape;
1018 RectangleShape::RectangleShape( Drawing& rDrawing ) :
1019 SimpleShape( rDrawing, "com.sun.star.drawing.RectangleShape" )
1023 Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
1025 OUString aGraphicPath = getGraphicPath();
1027 // try to create a picture object
1028 if(!aGraphicPath.isEmpty())
1029 return SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1031 // default: try to create a rectangle shape
1032 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
1033 OUString sArcsize = maTypeModel.maArcsize;
1034 if ( !sArcsize.isEmpty( ) )
1036 sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
1037 sal_Int32 nValue = o3tl::toInt32(sArcsize.subView( 0, sArcsize.getLength() - 1 ));
1038 // Get the smallest half-side
1039 double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
1040 sal_Int32 nRadius = 0;
1041 if ( cLastChar == 'f' )
1042 nRadius = size * nValue / 65536;
1043 else if ( cLastChar == '%' )
1044 nRadius = size * nValue / 100;
1045 PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, Any( nRadius ) );
1047 return xShape;
1050 EllipseShape::EllipseShape( Drawing& rDrawing ) :
1051 SimpleShape( rDrawing, "com.sun.star.drawing.EllipseShape" )
1055 PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
1056 SimpleShape( rDrawing, "com.sun.star.drawing.PolyLineShape" )
1060 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1062 ::std::vector<awt::Point> aAbsPoints;
1063 awt::Rectangle aCoordSys = getCoordSystem();
1064 if (!maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0))
1066 for (auto const& point : maShapeModel.maPoints)
1067 aAbsPoints.push_back(lclGetAbsPoint(point, rShapeRect, aCoordSys));
1068 // A polyline cannot be filled but only a polygon. We treat first point == last point as
1069 // indicator for being closed. In that case we force to type PolyPolygonShape.
1070 if (aAbsPoints.size() > 2 && aAbsPoints.front().X == aAbsPoints.back().X
1071 && aAbsPoints.front().Y == aAbsPoints.back().Y)
1073 const_cast<PolyLineShape*>(this)->setService("com.sun.star.drawing.PolyPolygonShape");
1077 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
1079 // polygon path
1081 if (!aAbsPoints.empty())
1083 PointSequenceSequence aPointSeq{ comphelper::containerToSequence( aAbsPoints ) };
1084 PropertySet aPropSet( xShape );
1085 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
1087 return xShape;
1090 namespace
1092 void doMirrorX(SdrObject* pShape)
1094 Point aCenter(pShape->GetSnapRect().Center());
1095 Point aPoint2(aCenter);
1096 aPoint2.setY(aPoint2.getY() + 1);
1097 pShape->NbcMirror(aCenter, aPoint2);
1100 void doMirrorY(SdrObject* pShape)
1102 Point aCenter(pShape->GetSnapRect().Center());
1103 Point aPoint2(aCenter);
1104 aPoint2.setX(aPoint2.getX() + 1);
1105 pShape->NbcMirror(aCenter, aPoint2);
1108 void handleMirroring(const ShapeTypeModel& rTypeModel, const Reference<XShape>& rxShape)
1110 if (!rTypeModel.maFlip.isEmpty())
1112 if (SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rxShape))
1114 if (rTypeModel.maFlip.startsWith("x"))
1115 doMirrorX(pShape);
1116 if (rTypeModel.maFlip.endsWith("y"))
1117 doMirrorY(pShape);
1122 void handleRotation(const ShapeTypeModel& rTypeModel, const Reference<XShape>& rxShape)
1124 if (!rTypeModel.maRotation.isEmpty())
1126 if (SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rxShape))
1128 // The needed factor -1 for opposite direction and factor 100 for Degree100 is
1129 // contained in method decodeRotation().
1130 Degree100 nAngle(ConversionHelper::decodeRotation(rTypeModel.maRotation));
1131 pShape->NbcRotate(pShape->GetSnapRect().Center(), nAngle);
1137 LineShape::LineShape(Drawing& rDrawing)
1138 : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
1142 Reference<XShape> LineShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
1144 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
1145 // tdf#137765
1146 handleRotation(maTypeModel, xShape);
1147 // tdf#97517 tdf#137678
1148 // The MirroredX and MirroredY properties (in the CustomShapeGeometry property) are not
1149 // supported for the LineShape by UNO, so we have to make the mirroring here.
1150 handleMirroring(maTypeModel, xShape);
1151 return xShape;
1154 awt::Rectangle LineShape::getAbsRectangle() const
1156 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1157 awt::Rectangle aShapeRect;
1158 sal_Int32 nIndex = 0;
1160 aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex), 0, true, true);
1161 aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex), 0, false, true);
1162 nIndex = 0;
1163 aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex), 0, true, true) - aShapeRect.X;
1164 aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex), 0, false, true) - aShapeRect.Y;
1165 return aShapeRect;
1168 awt::Rectangle LineShape::getRelRectangle() const
1170 awt::Rectangle aShapeRect;
1171 sal_Int32 nIndex = 0;
1173 aShapeRect.X = o3tl::toInt32(o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex));
1174 aShapeRect.Y = o3tl::toInt32(o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex));
1175 nIndex = 0;
1176 aShapeRect.Width = o3tl::toInt32(o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex)) - aShapeRect.X;
1177 aShapeRect.Height = o3tl::toInt32(o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex)) - aShapeRect.Y;
1178 return aShapeRect;
1181 BezierShape::BezierShape(Drawing& rDrawing)
1182 : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
1186 Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1188 // If we have an 'x' in the last part of the path it means it is closed...
1189 sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(',');
1190 if ( nPos != -1 && maShapeModel.maVmlPath.indexOf('x', nPos) != -1 )
1192 const_cast<BezierShape*>( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1195 awt::Rectangle aCoordSys = getCoordSystem();
1196 PolyPolygonBezierCoords aBezierCoords;
1198 if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
1200 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1202 // Bezier paths may consist of one or more sub-paths
1203 typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
1204 std::vector< ::std::vector< awt::Point > > aCoordLists;
1205 FlagsList aFlagLists;
1207 // Curve defined by to, from, control1 and control2 attributes
1208 if ( maShapeModel.maVmlPath.isEmpty() )
1210 aCoordLists.emplace_back( );
1211 aFlagLists.emplace_back( );
1212 sal_Int32 nIndex = 0;
1214 // Start point
1215 aCoordLists[ 0 ].emplace_back(
1216 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex ), 0, true, true ),
1217 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex ), 0, false, true ) );
1218 // Control point 1
1219 aCoordLists[ 0 ].emplace_back(
1220 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl1, 0, ',', nIndex ), 0, true, true ),
1221 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl1, 0, ',', nIndex ), 0, false, true ) );
1222 // Control point 2
1223 aCoordLists[ 0 ].emplace_back(
1224 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl2, 0, ',', nIndex ), 0, true, true ),
1225 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl2, 0, ',', nIndex ), 0, false, true ) );
1226 // End point
1227 aCoordLists[ 0 ].emplace_back(
1228 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex ), 0, true, true ),
1229 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex ), 0, false, true ) );
1231 // First and last points are normals, points 2 and 4 are controls
1232 aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
1233 aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
1234 aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
1236 // Curve defined by path attribute
1237 else
1239 // Parse VML path string and convert to absolute coordinates
1240 ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
1242 for (auto & coordList : aCoordLists)
1243 for (auto & point : coordList)
1245 point = lclGetAbsPoint( point, rShapeRect, aCoordSys );
1249 aBezierCoords.Coordinates.realloc( aCoordLists.size() );
1250 auto pCoordinates = aBezierCoords.Coordinates.getArray();
1251 for ( size_t i = 0; i < aCoordLists.size(); i++ )
1252 pCoordinates[i] = comphelper::containerToSequence( aCoordLists[i] );
1254 aBezierCoords.Flags.realloc( aFlagLists.size() );
1255 auto pFlags = aBezierCoords.Flags.getArray();
1256 for ( size_t i = 0; i < aFlagLists.size(); i++ )
1257 pFlags[i] = comphelper::containerToSequence( aFlagLists[i] );
1259 if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
1260 && aCoordLists.front().front().X == aCoordLists.back().back().X
1261 && aCoordLists.front().front().Y == aCoordLists.back().back().Y )
1262 { // HACK: If the shape is in fact closed, which can be found out only when the path is known,
1263 // force to closed bezier shape (otherwise e.g. fill won't work).
1264 const_cast< BezierShape* >( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1268 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1270 if( aBezierCoords.Coordinates.hasElements())
1272 PropertySet aPropSet( xShape );
1273 aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
1276 // tdf#105875 handle rotation
1277 // Note: must rotate before flip!
1278 handleRotation(maTypeModel, xShape);
1280 // Handle horizontal and vertical flip.
1281 handleMirroring(maTypeModel, xShape);
1283 return xShape;
1286 CustomShape::CustomShape( Drawing& rDrawing ) :
1287 SimpleShape( rDrawing, "com.sun.star.drawing.CustomShape" )
1291 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1293 // try to create a custom shape
1294 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1295 if( xShape.is() ) try
1297 // create the custom shape geometry
1298 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
1299 xDefaulter->createCustomShapeDefaults( OUString::number( getShapeType() ) );
1300 // convert common properties
1301 convertShapeProperties( xShape );
1303 catch( Exception& )
1306 return xShape;
1309 ComplexShape::ComplexShape( Drawing& rDrawing ) :
1310 CustomShape( rDrawing )
1314 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1316 XmlFilterBase& rFilter = mrDrawing.getFilter();
1317 sal_Int32 nShapeType = getShapeType();
1318 OUString aGraphicPath = getGraphicPath();
1320 // try to find registered OLE object info
1321 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
1323 SAL_WARN_IF(
1324 nShapeType != VML_SHAPETYPE_PICTUREFRAME, "oox",
1325 "ComplexShape::implConvertAndInsert - unexpected shape type");
1327 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
1328 if( pOleObjectInfo->mbDmlShape )
1329 return Reference< XShape >();
1331 PropertyMap aOleProps;
1332 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1333 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
1335 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.OLE2Shape", rxShapes, rShapeRect );
1336 if( xShape.is() )
1338 // set the replacement graphic
1339 if( !aGraphicPath.isEmpty() )
1341 WmfExternal aExtHeader;
1342 aExtHeader.mapMode = 8;
1343 aExtHeader.xExt = rShapeRect.Width;
1344 aExtHeader.yExt = rShapeRect.Height;
1346 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath, &aExtHeader);
1347 if (xGraphic.is())
1348 aOleProps.setProperty( PROP_Graphic, xGraphic);
1351 PropertySet aPropSet( xShape );
1352 aPropSet.setProperties( aOleProps );
1354 return xShape;
1359 // try to find registered form control info
1360 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
1361 if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
1363 if( !pControlInfo->maName.isEmpty() )
1365 // load the control properties from fragment
1366 ::oox::ole::EmbeddedControl aControl(pControlInfo->maName);
1367 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
1369 // create and return the control shape (including control model)
1370 sal_Int32 nCtrlIndex = -1;
1371 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
1373 if (pControlInfo->mbTextContentShape)
1375 PropertySet aPropertySet(xShape);
1376 lcl_SetAnchorType(aPropertySet, maTypeModel, mrDrawing.getFilter().getGraphicHelper());
1378 // on error, proceed and try to create picture from replacement image
1379 if( xShape.is() )
1380 return xShape;
1385 // host application wants to create the shape (do not try failed OLE controls again)
1386 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
1388 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
1389 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
1390 if( xShape.is() )
1391 return xShape;
1395 if( getShapeModel().mbIsSignatureLine )
1397 uno::Reference<graphic::XGraphic> xGraphic;
1398 bool bIsSigned(false);
1401 // Get the document signatures
1402 Reference<security::XDocumentDigitalSignatures> xSignatures(
1403 security::DocumentDigitalSignatures::createDefault(
1404 comphelper::getProcessComponentContext()));
1406 uno::Reference<embed::XStorage> xStorage
1407 = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
1408 ZIP_STORAGE_FORMAT_STRING, mrDrawing.getFilter().getFileUrl(),
1409 embed::ElementModes::READ);
1410 SAL_WARN_IF(!xStorage.is(), "oox.vml", "No xStorage!");
1412 const uno::Sequence<security::DocumentSignatureInformation> xSignatureInfo
1413 = xSignatures->verifyScriptingContentSignatures(xStorage,
1414 uno::Reference<io::XInputStream>());
1416 // Try to find matching signature line image - if none exists that is fine,
1417 // then the signature line is not digitally signed.
1418 auto pSignInfo = std::find_if(xSignatureInfo.begin(), xSignatureInfo.end(),
1419 [this](const security::DocumentSignatureInformation& rSigInfo) {
1420 return rSigInfo.SignatureLineId == getShapeModel().maSignatureId; });
1421 if (pSignInfo != xSignatureInfo.end())
1423 bIsSigned = true;
1424 if (pSignInfo->SignatureIsValid)
1426 // Signature is valid, use the 'valid' image
1427 SAL_WARN_IF(!pSignInfo->ValidSignatureLineImage.is(), "oox.vml",
1428 "No ValidSignatureLineImage!");
1429 xGraphic = pSignInfo->ValidSignatureLineImage;
1431 else
1433 // Signature is invalid, use the 'invalid' image
1434 SAL_WARN_IF(!pSignInfo->InvalidSignatureLineImage.is(), "oox.vml",
1435 "No InvalidSignatureLineImage!");
1436 xGraphic = pSignInfo->InvalidSignatureLineImage;
1440 catch (css::uno::Exception&)
1442 // DocumentDigitalSignatures service not available.
1443 // We continue by rendering the "unsigned" shape instead.
1446 Reference< XShape > xShape;
1447 if (xGraphic.is())
1449 // If available, use the signed image from the signature
1450 xShape = SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
1452 else
1454 // Create shape with the fallback "unsigned" image
1455 xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1458 // Store signature line properties
1459 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1460 xPropertySet->setPropertyValue("IsSignatureLine", uno::Any(true));
1461 xPropertySet->setPropertyValue("SignatureLineId",
1462 uno::Any(getShapeModel().maSignatureId));
1463 xPropertySet->setPropertyValue(
1464 "SignatureLineSuggestedSignerName",
1465 uno::Any(getShapeModel().maSignatureLineSuggestedSignerName));
1466 xPropertySet->setPropertyValue(
1467 "SignatureLineSuggestedSignerTitle",
1468 uno::Any(getShapeModel().maSignatureLineSuggestedSignerTitle));
1469 xPropertySet->setPropertyValue(
1470 "SignatureLineSuggestedSignerEmail",
1471 uno::Any(getShapeModel().maSignatureLineSuggestedSignerEmail));
1472 xPropertySet->setPropertyValue(
1473 "SignatureLineSigningInstructions",
1474 uno::Any(getShapeModel().maSignatureLineSigningInstructions));
1475 xPropertySet->setPropertyValue(
1476 "SignatureLineShowSignDate",
1477 uno::Any(getShapeModel().mbSignatureLineShowSignDate));
1478 xPropertySet->setPropertyValue(
1479 "SignatureLineCanAddComment",
1480 uno::Any(getShapeModel().mbSignatureLineCanAddComment));
1481 xPropertySet->setPropertyValue("SignatureLineIsSigned", uno::Any(bIsSigned));
1483 if (!aGraphicPath.isEmpty())
1485 xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath);
1486 xPropertySet->setPropertyValue("SignatureLineUnsignedImage", uno::Any(xGraphic));
1488 return xShape;
1491 // try to create a picture object
1492 if( !aGraphicPath.isEmpty() )
1494 Reference<XShape> xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1495 // AS_CHARACTER shape: vertical orientation default is bottom, MSO default is top.
1496 if ( maTypeModel.maPosition != "absolute" && maTypeModel.maPosition != "relative" )
1497 PropertySet( xShape ).setAnyProperty( PROP_VertOrient, Any(text::VertOrientation::TOP));
1499 // Apply stroke props from the type model.
1500 oox::drawingml::ShapePropertyMap aPropMap(mrDrawing.getFilter().getModelObjectHelper());
1501 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1502 maTypeModel.maStrokeModel.pushToPropMap(aPropMap, rGraphicHelper);
1503 // And, fill-color properties as well...
1504 maTypeModel.maFillModel.pushToPropMap(aPropMap, rGraphicHelper);
1505 PropertySet(xShape).setProperties(aPropMap);
1507 return xShape;
1510 // default: try to create a custom shape
1511 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
1514 GroupShape::GroupShape( Drawing& rDrawing ) :
1515 ShapeBase( rDrawing ),
1516 mxChildren( new ShapeContainer( rDrawing ) )
1520 GroupShape::~GroupShape()
1524 void GroupShape::finalizeFragmentImport()
1526 // basic shape processing
1527 ShapeBase::finalizeFragmentImport();
1528 // finalize all child shapes
1529 mxChildren->finalizeFragmentImport();
1532 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
1534 return mxChildren->getShapeTypeById( rShapeId );
1537 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
1539 return mxChildren->getShapeById( rShapeId );
1542 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1544 Reference< XShape > xGroupShape;
1545 // check that this shape contains children and a valid coordinate system
1546 ShapeParentAnchor aParentAnchor;
1547 aParentAnchor.maShapeRect = rShapeRect;
1548 aParentAnchor.maCoordSys = getCoordSystem();
1549 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
1551 xGroupShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GroupShape", rxShapes, rShapeRect );
1552 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
1553 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
1554 if( !xChildShapes->hasElements() )
1556 SAL_WARN("oox", "no child shape has been created - deleting the group shape");
1557 rxShapes->remove( xGroupShape );
1558 xGroupShape.clear();
1561 catch( Exception& )
1565 uno::Reference<beans::XPropertySet> xPropertySet;
1566 if (!maTypeModel.maEditAs.isEmpty())
1567 xPropertySet = uno::Reference<beans::XPropertySet>(xGroupShape, uno::UNO_QUERY);
1568 if (xPropertySet.is())
1570 uno::Sequence<beans::PropertyValue> aGrabBag;
1571 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1572 sal_Int32 nLength = aGrabBag.getLength();
1573 aGrabBag.realloc(nLength + 1);
1574 aGrabBag.getArray()[nLength] = comphelper::makePropertyValue("mso-edit-as", maTypeModel.maEditAs);
1575 xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag));
1577 // Make sure group shapes are inline as well, unless there is an explicit different style.
1578 PropertySet aPropertySet(xGroupShape);
1579 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1580 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper);
1581 if (!maTypeModel.maRotation.isEmpty())
1582 aPropertySet.setAnyProperty(PROP_RotateAngle, Any(ConversionHelper::decodeRotation(maTypeModel.maRotation).get()));
1583 return xGroupShape;
1586 } // namespace oox
1588 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */