Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / oox / source / vml / vmlshape.cxx
blobbdbea0c86fc42ef947b5eb22616702a0bb7b786c
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 const OUStringLiteral sShapeTypePrefix = u"shapetype_";
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 void ShapeBase::convertFormatting( const Reference< XShape >& rxShape ) const
489 if( !rxShape.is() )
490 return;
492 /* Calculate shape rectangle. Applications may do something special
493 according to some imported shape client data (e.g. Excel cell anchor). */
494 awt::Rectangle aShapeRect = calcShapeRectangle( nullptr );
496 // convert the shape, if the calculated rectangle is not empty
497 if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
499 rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
500 rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
501 convertShapeProperties( rxShape );
505 void ShapeBase::setContainer(ShapeContainer* pContainer) { mpContainer = pContainer; }
507 ShapeContainer* ShapeBase::getContainer() const { return mpContainer; }
509 // protected ------------------------------------------------------------------
511 awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
513 /* Calculate shape rectangle. Applications may do something special
514 according to some imported shape client data (e.g. Excel cell anchor). */
515 awt::Rectangle aShapeRect;
516 const ClientData* pClientData = getClientData();
517 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
518 aShapeRect = getRectangle( pParentAnchor );
519 return aShapeRect;
522 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
524 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
525 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
526 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
527 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
529 uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
530 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
532 // Any other service supporting the ShadowFormat property?
533 maTypeModel.maShadowModel.pushToPropMap(aPropMap, rGraphicHelper);
534 // TextFrames have BackColor, not FillColor
535 if (aPropMap.hasProperty(PROP_FillColor))
537 aPropMap.setAnyProperty(PROP_BackColor, aPropMap.getProperty(PROP_FillColor));
538 aPropMap.erase(PROP_FillColor);
540 // TextFrames have BackColorTransparency, not FillTransparence
541 if (aPropMap.hasProperty(PROP_FillTransparence))
543 aPropMap.setAnyProperty(PROP_BackColorTransparency, aPropMap.getProperty(PROP_FillTransparence));
544 aPropMap.erase(PROP_FillTransparence);
546 // And no LineColor property; individual borders can have colors and widths
547 std::optional<sal_Int32> oLineWidth;
548 if (maTypeModel.maStrokeModel.moWeight.has_value())
549 oLineWidth = ConversionHelper::decodeMeasureToHmm(
550 rGraphicHelper, maTypeModel.maStrokeModel.moWeight.value(), 0, false, false);
551 if (aPropMap.hasProperty(PROP_LineColor))
553 uno::Reference<beans::XPropertySet> xPropertySet(rxShape, uno::UNO_QUERY);
554 static const sal_Int32 aBorders[] = {
555 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
557 for (sal_Int32 nBorder : aBorders)
559 table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<table::BorderLine2>();
560 aBorderLine.Color = aPropMap.getProperty(PROP_LineColor).get<sal_Int32>();
561 if (oLineWidth)
562 aBorderLine.LineWidth = *oLineWidth;
563 aPropMap.setProperty(nBorder, aBorderLine);
565 aPropMap.erase(PROP_LineColor);
568 else if (xSInfo->supportsService("com.sun.star.drawing.CustomShape"))
569 maTypeModel.maTextpathModel.pushToPropMap(aPropMap, rxShape, rGraphicHelper);
571 PropertySet( rxShape ).setProperties( aPropMap );
574 SimpleShape::SimpleShape( Drawing& rDrawing, OUString aService ) :
575 ShapeBase( rDrawing ),
576 maService(std::move( aService ))
580 static void lcl_setSurround(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
582 OUString aWrapType = rTypeModel.moWrapType.value_or("");
584 // 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.
585 sal_Int32 nMarginTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, rTypeModel.maMarginTop, 0, false, true);
586 if (nMarginTop < -35277) // Less than 1000 points.
587 aWrapType.clear();
589 css::text::WrapTextMode nSurround = css::text::WrapTextMode_THROUGH;
590 if ( aWrapType == "square" || aWrapType == "tight" ||
591 aWrapType == "through" )
593 nSurround = css::text::WrapTextMode_PARALLEL;
594 if ( !rTypeModel.moWrapSide.has_value() )
595 ; // leave as PARALLEL
596 else if ( rTypeModel.moWrapSide.value() == "left" )
597 nSurround = css::text::WrapTextMode_LEFT;
598 else if ( rTypeModel.moWrapSide.value() == "right" )
599 nSurround = css::text::WrapTextMode_RIGHT;
601 else if ( aWrapType == "topAndBottom" )
602 nSurround = css::text::WrapTextMode_NONE;
604 rPropSet.setProperty(PROP_Surround, static_cast<sal_Int32>(nSurround));
605 rPropSet.setProperty(PROP_SurroundContour, aWrapType == "tight");
608 static void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
610 if ( rTypeModel.maPosition == "absolute" )
612 // Word supports as-character (inline) and at-character only, absolute can't be inline.
613 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
614 // anchor is set after insertion, so reset to NONE
615 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::NONE));
617 if ( rTypeModel.maPositionVerticalRelative == "page" )
619 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
621 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
623 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
625 else if (rTypeModel.maPositionVerticalRelative == "top-margin-area")
627 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA_TOP);
629 else if (rTypeModel.maPositionVerticalRelative == "bottom-margin-area")
631 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA_BOTTOM);
633 else
635 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
638 else if( rTypeModel.maPosition == "relative" )
639 { // I'm not very sure this is correct either.
640 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
641 // anchor is set after insertion, so reset to NONE
642 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::NONE));
644 else // static (is the default) means anchored inline
646 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
647 // Use top orientation, this one seems similar to what MSO uses as inline
648 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::TOP));
651 if ( rTypeModel.maPositionHorizontal == "center" )
652 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::CENTER));
653 else if ( rTypeModel.maPositionHorizontal == "left" )
654 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::LEFT));
655 else if ( rTypeModel.maPositionHorizontal == "right" )
656 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::RIGHT));
657 else if ( rTypeModel.maPositionHorizontal == "inside" )
659 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::LEFT));
660 rPropSet.setAnyProperty(PROP_PageToggle, Any(true));
662 else if ( rTypeModel.maPositionHorizontal == "outside" )
664 rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::RIGHT));
665 rPropSet.setAnyProperty(PROP_PageToggle, Any(true));
668 if ( rTypeModel.maPositionHorizontalRelative == "page" )
669 rPropSet.setAnyProperty(PROP_HoriOrientRelation, Any(text::RelOrientation::PAGE_FRAME));
670 else if ( rTypeModel.maPositionHorizontalRelative == "margin" )
671 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
672 else if (rTypeModel.maPositionHorizontalRelative == "right-margin-area" ||
673 rTypeModel.maPositionHorizontalRelative == "inner-margin-area")
674 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::PAGE_RIGHT);
675 else if (rTypeModel.maPositionHorizontalRelative == "left-margin-area" ||
676 rTypeModel.maPositionHorizontalRelative == "outer-margin-area")
677 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::PAGE_LEFT);
678 else if ( rTypeModel.maPositionHorizontalRelative == "text" )
679 rPropSet.setProperty(PROP_HoriOrientRelation, text::RelOrientation::FRAME);
681 if ( rTypeModel.maPositionVertical == "center" )
682 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::CENTER));
683 else if ( rTypeModel.maPositionVertical == "top" )
684 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::TOP));
685 else if ( rTypeModel.maPositionVertical == "bottom" )
686 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::BOTTOM));
687 else if ( rTypeModel.maPositionVertical == "inside" )
688 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::TOP));
689 else if ( rTypeModel.maPositionVertical == "outside" )
690 rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::BOTTOM));
692 lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper );
695 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
697 awt::Rectangle aShapeRect(rShapeRect);
698 std::optional<Degree100> oRotation;
699 bool bFlipX = false, bFlipY = false;
700 // tdf#137765: skip this rotation for line shapes
701 if (!maTypeModel.maRotation.isEmpty() && maService != "com.sun.star.drawing.LineShape")
702 oRotation = ConversionHelper::decodeRotation(maTypeModel.maRotation);
703 if (!maTypeModel.maFlip.isEmpty())
705 if (maTypeModel.maFlip.startsWith("x"))
707 bFlipX = true;
709 if (maTypeModel.maFlip.endsWith("y"))
711 bFlipY = true;
715 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
716 SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
717 if( pShape && getShapeType() >= 0 )
719 //The resize autoshape to fit text attr of FontWork/Word-Art should always be false
720 //for the fallback geometry.
721 sal_Int32 nType = getShapeType();
722 if((mso_sptTextSimple <= nType && nType <= mso_sptTextOnRing)
723 || (mso_sptTextPlainText <= nType && nType <= mso_sptTextCanDown))
725 pShape->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
726 pShape->SetMergedItem(makeSdrTextAutoGrowWidthItem(false));
729 convertShapeProperties( xShape );
731 // Handle left/right/top/bottom wrap distance.
732 // Default value of mso-wrap-distance-left/right is supposed to be 0 (see
733 // 19.1.2.19 of the VML spec), but Word implements a non-zero value.
734 // [MS-ODRAW] says the below default value in 2.3.4.9.
735 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
736 OUString aWrapDistanceLeft = OUString::number(0x0001BE7C);
737 if (!maTypeModel.maWrapDistanceLeft.isEmpty())
738 aWrapDistanceLeft = maTypeModel.maWrapDistanceLeft;
739 sal_Int32 nWrapDistanceLeft = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceLeft, 0, true, false);
740 PropertySet(xShape).setAnyProperty(PROP_LeftMargin, uno::Any(nWrapDistanceLeft));
741 OUString aWrapDistanceRight = OUString::number(0x0001BE7C);
742 if (!maTypeModel.maWrapDistanceRight.isEmpty())
743 aWrapDistanceRight = maTypeModel.maWrapDistanceRight;
744 sal_Int32 nWrapDistanceRight = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceRight, 0, true, false);
745 PropertySet(xShape).setAnyProperty(PROP_RightMargin, uno::Any(nWrapDistanceRight));
746 sal_Int32 nWrapDistanceTop = 0;
747 if (!maTypeModel.maWrapDistanceTop.isEmpty())
748 nWrapDistanceTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceTop, 0, false, true);
749 PropertySet(xShape).setAnyProperty(PROP_TopMargin, uno::Any(nWrapDistanceTop));
750 sal_Int32 nWrapDistanceBottom = 0;
751 if (!maTypeModel.maWrapDistanceBottom.isEmpty())
752 nWrapDistanceBottom = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceBottom, 0, false, true);
753 PropertySet(xShape).setAnyProperty(PROP_BottomMargin, uno::Any(nWrapDistanceBottom));
755 if ( maService == "com.sun.star.text.TextFrame" )
757 PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, Any( maTypeModel.mbAutoHeight ) );
758 PropertySet( xShape ).setAnyProperty( PROP_SizeType, Any( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
759 if( getTextBox()->borderDistanceSet )
761 PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceLeft )));
762 PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceTop )));
763 PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceRight )));
764 PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, Any( sal_Int32( getTextBox()->borderDistanceBottom )));
767 sal_Int16 nWritingMode = text::WritingMode2::LR_TB;
768 if (getTextBox()->maLayoutFlow == "vertical" && maTypeModel.maLayoutFlowAlt.isEmpty())
770 nWritingMode = text::WritingMode2::TB_RL;
772 else if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
774 nWritingMode = text::WritingMode2::BT_LR;
776 if (nWritingMode != text::WritingMode2::LR_TB)
778 PropertySet(xShape).setAnyProperty(PROP_WritingMode, uno::Any(nWritingMode));
780 // tdf#123626
781 if (!maShapeModel.maHyperlink.isEmpty())
782 PropertySet(xShape).setAnyProperty(PROP_HyperLinkURL, Any(maShapeModel.maHyperlink));
784 else
786 // FIXME Setting the relative width/height only for everything but text frames as
787 // TextFrames already have relative width/height feature... but currently not working
788 // in the way we need.
790 // Set the relative width / height if any
791 if ( !maTypeModel.maWidthPercent.isEmpty( ) )
793 // Only page-relative width is supported ATM
794 if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
796 sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
797 // Only apply if nWidth != 0
798 if ( nWidth )
799 PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, Any( nWidth ) );
802 if ( !maTypeModel.maHeightPercent.isEmpty( ) )
804 // Only page-relative height is supported ATM
805 if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
807 sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
808 // Only apply if nHeight != 0
809 if ( nHeight )
810 PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, Any( nHeight ) );
814 // drawinglayer default is center, MSO default is top.
815 drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP;
816 if (maTypeModel.maVTextAnchor == "middle")
817 eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER;
818 else if (maTypeModel.maVTextAnchor == "bottom")
819 eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
820 PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, Any(eTextVerticalAdjust));
822 // tdf#97618
823 if(!maTypeModel.maWrapStyle.isEmpty())
824 PropertySet(xShape).setAnyProperty(PROP_TextWordWrap, Any(maTypeModel.maWrapStyle == "square"));
826 // tdf#123626
827 if (!maShapeModel.maHyperlink.isEmpty())
828 PropertySet(xShape).setAnyProperty(PROP_Hyperlink, Any(maShapeModel.maHyperlink));
830 PropertySet(xShape).setAnyProperty(PROP_TextAutoGrowHeight,
831 Any(maTypeModel.mbAutoHeight));
833 if (getTextBox())
835 getTextBox()->convert(xShape);
836 if (getTextBox()->borderDistanceSet)
838 awt::Size aSize = xShape->getSize();
839 PropertySet(xShape).setAnyProperty(PROP_TextLeftDistance, Any(sal_Int32(getTextBox()->borderDistanceLeft)));
840 PropertySet(xShape).setAnyProperty(PROP_TextUpperDistance, Any(sal_Int32(getTextBox()->borderDistanceTop)));
841 PropertySet(xShape).setAnyProperty(PROP_TextRightDistance, Any(sal_Int32(getTextBox()->borderDistanceRight)));
842 PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, Any(sal_Int32(getTextBox()->borderDistanceBottom)));
843 xShape->setSize(aSize);
848 // Import Legacy Fragments (if any)
849 if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
851 Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
852 if( xInStrm.is() )
853 PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
856 PropertySet aPropertySet(xShape);
857 if (xShape.is())
859 if (oRotation)
861 aPropertySet.setAnyProperty(PROP_RotateAngle, Any((*oRotation).get()));
862 uno::Reference<lang::XServiceInfo> xServiceInfo(rxShapes, uno::UNO_QUERY);
863 if (!xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
865 // If rotation is used, simple setPosition() is not enough.
866 aPropertySet.setAnyProperty(PROP_HoriOrientPosition, Any(aShapeRect.X));
867 aPropertySet.setAnyProperty(PROP_VertOrientPosition, Any(aShapeRect.Y));
871 // custom shape geometry attributes
872 std::vector<css::beans::PropertyValue> aPropVec;
874 // When flip has 'x' or 'y', the associated ShapeRect will be changed but direction change doesn't occur.
875 // It might occur internally in SdrObject of "sw" module, not here.
876 // The associated properties "PROP_MirroredX" and "PROP_MirroredY" have to be set here so that direction change will occur internally.
877 if (bFlipX)
878 aPropVec.push_back(comphelper::makePropertyValue("MirroredX", true));
879 if (bFlipY)
880 aPropVec.push_back(comphelper::makePropertyValue("MirroredY", true));
882 if (!maTypeModel.maAdjustments.isEmpty())
884 std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
885 sal_Int32 nIndex = 0;
888 std::u16string_view aToken = o3tl::getToken(maTypeModel.maAdjustments, 0, ',', nIndex);
889 drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue;
890 if (aToken.empty())
891 aAdjustmentValue.State = css::beans::PropertyState::PropertyState_DEFAULT_VALUE;
892 else
893 aAdjustmentValue.Value <<= o3tl::toInt32(aToken);
894 aAdjustmentValues.push_back(aAdjustmentValue);
895 } while (nIndex >= 0);
897 css::beans::PropertyValue aProp;
898 aProp.Name = "AdjustmentValues";
899 aProp.Value <<= comphelper::containerToSequence(aAdjustmentValues);
900 aPropVec.push_back(aProp);
903 if (!aPropVec.empty())
904 aPropertySet.setAnyProperty(PROP_CustomShapeGeometry, Any(comphelper::containerToSequence(aPropVec)));
907 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper );
909 return xShape;
912 Reference<XShape> SimpleShape::finalImplConvertAndInsert(const css::uno::Reference<css::drawing::XShape>& rxShape) const
914 // tdf#41466 This setting must be done here, because the position of textbox will be set as an
915 // effect of the PROP_TextBox property setting, and if we do this setting earlier (setting of
916 // properties of position and size) then the position of textbox will be set with wrong data.
917 // TODO: TextShape is set if we have rect shape in group; we should use the shape-with-textbox
918 // mechanism to handle this situation
919 if (getTextBox() && maService != "com.sun.star.text.TextFrame" && maService != "com.sun.star.drawing.TextShape"
920 && !maShapeModel.mbInGroup)
922 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
923 const auto& nLeft = ConversionHelper::decodeMeasureToHmm(
924 rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true);
925 PropertySet aPropertySet(rxShape);
926 aPropertySet.setProperty(PROP_HoriOrientPosition, nLeft);
927 const auto& nTop = ConversionHelper::decodeMeasureToHmm(
928 rGraphicHelper, maTypeModel.maMarginTop, 0, true, true);
929 aPropertySet.setProperty(PROP_VertOrientPosition, nTop);
930 aPropertySet.setProperty(PROP_TextBox, true);
932 // And these properties must be set after textbox creation (set PROP_Textbox property).
933 // Note: if you set a new property then you have to handle it in the proper
934 // SwTextBoxHelper::syncProperty function.
935 if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
936 aPropertySet.setAnyProperty(PROP_TextWritingMode, uno::Any(text::WritingMode2::BT_LR));
938 return ShapeBase::finalImplConvertAndInsert(rxShape);
940 Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
942 Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath);
943 return SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
946 Reference< XShape > SimpleShape::createPictureObject(const Reference< XShapes >& rxShapes,
947 const awt::Rectangle& rShapeRect,
948 uno::Reference<graphic::XGraphic> const & rxGraphic) const
950 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
951 if( xShape.is() )
953 PropertySet aPropSet(xShape);
954 if (rxGraphic.is())
956 aPropSet.setProperty(PROP_Graphic, rxGraphic);
958 uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
959 // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
960 if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
962 aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
963 aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
964 aPropSet.setProperty(PROP_Opaque, false);
966 // fdo#70457: preserve rotation information
967 if ( !maTypeModel.maRotation.isEmpty() )
968 aPropSet.setAnyProperty(PROP_RotateAngle, Any(ConversionHelper::decodeRotation(maTypeModel.maRotation).get()));
970 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
971 lcl_SetAnchorType(aPropSet, maTypeModel, rGraphicHelper);
973 const sal_Int32 nWrapDistanceLeft = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceLeft, 0, true, true);
974 const sal_Int32 nWrapDistanceRight = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceRight, 0, true, true);
975 const sal_Int32 nWrapDistanceTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceTop, 0, false, true);
976 const sal_Int32 nWrapDistanceBottom = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceBottom, 0, false, true);
977 aPropSet.setProperty(PROP_LeftMargin, uno::Any(nWrapDistanceLeft));
978 aPropSet.setProperty(PROP_RightMargin, uno::Any(nWrapDistanceRight));
979 aPropSet.setProperty(PROP_TopMargin, uno::Any(nWrapDistanceTop));
980 aPropSet.setProperty(PROP_BottomMargin, uno::Any(nWrapDistanceBottom));
982 if (maTypeModel.moCropBottom.has_value() || maTypeModel.moCropLeft.has_value() || maTypeModel.moCropRight.has_value() || maTypeModel.moCropTop.has_value())
984 text::GraphicCrop aGraphicCrop;
985 awt::Size aOriginalSize = rGraphicHelper.getOriginalSize(rxGraphic);
987 if (maTypeModel.moCropBottom.has_value())
988 aGraphicCrop.Bottom = lclConvertCrop(maTypeModel.moCropBottom.value(), aOriginalSize.Height);
989 if (maTypeModel.moCropLeft.has_value())
990 aGraphicCrop.Left = lclConvertCrop(maTypeModel.moCropLeft.value(), aOriginalSize.Width);
991 if (maTypeModel.moCropRight.has_value())
992 aGraphicCrop.Right = lclConvertCrop(maTypeModel.moCropRight.value(), aOriginalSize.Width);
993 if (maTypeModel.moCropTop.has_value())
994 aGraphicCrop.Top = lclConvertCrop(maTypeModel.moCropTop.value(), aOriginalSize.Height);
996 aPropSet.setProperty(PROP_GraphicCrop, aGraphicCrop);
999 if (maTypeModel.mnGain == -70 && maTypeModel.mnBlacklevel == 70)
1001 // Map MSO 'washout' to our watermark colormode.
1002 aPropSet.setProperty(PROP_GraphicColorMode, uno::Any(drawing::ColorMode_WATERMARK));
1005 return xShape;
1008 RectangleShape::RectangleShape( Drawing& rDrawing ) :
1009 SimpleShape( rDrawing, "com.sun.star.drawing.RectangleShape" )
1013 Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
1015 OUString aGraphicPath = getGraphicPath();
1017 // try to create a picture object
1018 if(!aGraphicPath.isEmpty())
1019 return SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1021 // default: try to create a rectangle shape
1022 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
1023 OUString sArcsize = maTypeModel.maArcsize;
1024 if ( !sArcsize.isEmpty( ) )
1026 sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
1027 sal_Int32 nValue = o3tl::toInt32(sArcsize.subView( 0, sArcsize.getLength() - 1 ));
1028 // Get the smallest half-side
1029 double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
1030 sal_Int32 nRadius = 0;
1031 if ( cLastChar == 'f' )
1032 nRadius = size * nValue / 65536;
1033 else if ( cLastChar == '%' )
1034 nRadius = size * nValue / 100;
1035 PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, Any( nRadius ) );
1037 return xShape;
1040 EllipseShape::EllipseShape( Drawing& rDrawing ) :
1041 SimpleShape( rDrawing, "com.sun.star.drawing.EllipseShape" )
1045 PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
1046 SimpleShape( rDrawing, "com.sun.star.drawing.PolyLineShape" )
1050 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1052 ::std::vector<awt::Point> aAbsPoints;
1053 awt::Rectangle aCoordSys = getCoordSystem();
1054 if (!maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0))
1056 for (auto const& point : maShapeModel.maPoints)
1057 aAbsPoints.push_back(lclGetAbsPoint(point, rShapeRect, aCoordSys));
1058 // A polyline cannot be filled but only a polygon. We treat first point == last point as
1059 // indicator for being closed. In that case we force to type PolyPolygonShape.
1060 if (aAbsPoints.size() > 2 && aAbsPoints.front().X == aAbsPoints.back().X
1061 && aAbsPoints.front().Y == aAbsPoints.back().Y)
1063 const_cast<PolyLineShape*>(this)->setService("com.sun.star.drawing.PolyPolygonShape");
1067 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
1069 // polygon path
1071 if (!aAbsPoints.empty())
1073 PointSequenceSequence aPointSeq{ comphelper::containerToSequence( aAbsPoints ) };
1074 PropertySet aPropSet( xShape );
1075 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
1077 return xShape;
1080 namespace
1082 void doMirrorX(SdrObject* pShape)
1084 Point aCenter(pShape->GetSnapRect().Center());
1085 Point aPoint2(aCenter);
1086 aPoint2.setY(aPoint2.getY() + 1);
1087 pShape->NbcMirror(aCenter, aPoint2);
1090 void doMirrorY(SdrObject* pShape)
1092 Point aCenter(pShape->GetSnapRect().Center());
1093 Point aPoint2(aCenter);
1094 aPoint2.setX(aPoint2.getX() + 1);
1095 pShape->NbcMirror(aCenter, aPoint2);
1098 void handleMirroring(const ShapeTypeModel& rTypeModel, const Reference<XShape>& rxShape)
1100 if (!rTypeModel.maFlip.isEmpty())
1102 if (SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rxShape))
1104 if (rTypeModel.maFlip.startsWith("x"))
1105 doMirrorX(pShape);
1106 if (rTypeModel.maFlip.endsWith("y"))
1107 doMirrorY(pShape);
1112 void handleRotation(const ShapeTypeModel& rTypeModel, const Reference<XShape>& rxShape)
1114 if (!rTypeModel.maRotation.isEmpty())
1116 if (SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rxShape))
1118 // The needed factor -1 for opposite direction and factor 100 for Degree100 is
1119 // contained in method decodeRotation().
1120 Degree100 nAngle(ConversionHelper::decodeRotation(rTypeModel.maRotation));
1121 pShape->NbcRotate(pShape->GetSnapRect().Center(), nAngle);
1127 LineShape::LineShape(Drawing& rDrawing)
1128 : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
1132 Reference<XShape> LineShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
1134 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
1135 // tdf#137765
1136 handleRotation(maTypeModel, xShape);
1137 // tdf#97517 tdf#137678
1138 // The MirroredX and MirroredY properties (in the CustomShapeGeometry property) are not
1139 // supported for the LineShape by UNO, so we have to make the mirroring here.
1140 handleMirroring(maTypeModel, xShape);
1141 return xShape;
1144 awt::Rectangle LineShape::getAbsRectangle() const
1146 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1147 awt::Rectangle aShapeRect;
1148 sal_Int32 nIndex = 0;
1150 aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex), 0, true, true);
1151 aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex), 0, false, true);
1152 nIndex = 0;
1153 aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex), 0, true, true) - aShapeRect.X;
1154 aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex), 0, false, true) - aShapeRect.Y;
1155 return aShapeRect;
1158 awt::Rectangle LineShape::getRelRectangle() const
1160 awt::Rectangle aShapeRect;
1161 sal_Int32 nIndex = 0;
1163 aShapeRect.X = o3tl::toInt32(o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex));
1164 aShapeRect.Y = o3tl::toInt32(o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex));
1165 nIndex = 0;
1166 aShapeRect.Width = o3tl::toInt32(o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex)) - aShapeRect.X;
1167 aShapeRect.Height = o3tl::toInt32(o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex)) - aShapeRect.Y;
1168 return aShapeRect;
1171 BezierShape::BezierShape(Drawing& rDrawing)
1172 : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
1176 Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1178 // If we have an 'x' in the last part of the path it means it is closed...
1179 sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(',');
1180 if ( nPos != -1 && maShapeModel.maVmlPath.indexOf('x', nPos) != -1 )
1182 const_cast<BezierShape*>( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1185 awt::Rectangle aCoordSys = getCoordSystem();
1186 PolyPolygonBezierCoords aBezierCoords;
1188 if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
1190 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1192 // Bezier paths may consist of one or more sub-paths
1193 typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
1194 std::vector< ::std::vector< awt::Point > > aCoordLists;
1195 FlagsList aFlagLists;
1197 // Curve defined by to, from, control1 and control2 attributes
1198 if ( maShapeModel.maVmlPath.isEmpty() )
1200 aCoordLists.emplace_back( );
1201 aFlagLists.emplace_back( );
1202 sal_Int32 nIndex = 0;
1204 // Start point
1205 aCoordLists[ 0 ].emplace_back(
1206 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex ), 0, true, true ),
1207 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maFrom, 0, ',', nIndex ), 0, false, true ) );
1208 // Control point 1
1209 aCoordLists[ 0 ].emplace_back(
1210 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl1, 0, ',', nIndex ), 0, true, true ),
1211 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl1, 0, ',', nIndex ), 0, false, true ) );
1212 // Control point 2
1213 aCoordLists[ 0 ].emplace_back(
1214 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl2, 0, ',', nIndex ), 0, true, true ),
1215 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maControl2, 0, ',', nIndex ), 0, false, true ) );
1216 // End point
1217 aCoordLists[ 0 ].emplace_back(
1218 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex ), 0, true, true ),
1219 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, o3tl::getToken(maShapeModel.maTo, 0, ',', nIndex ), 0, false, true ) );
1221 // First and last points are normals, points 2 and 4 are controls
1222 aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
1223 aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
1224 aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
1226 // Curve defined by path attribute
1227 else
1229 // Parse VML path string and convert to absolute coordinates
1230 ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
1232 for (auto & coordList : aCoordLists)
1233 for (auto & point : coordList)
1235 point = lclGetAbsPoint( point, rShapeRect, aCoordSys );
1239 aBezierCoords.Coordinates.realloc( aCoordLists.size() );
1240 auto pCoordinates = aBezierCoords.Coordinates.getArray();
1241 for ( size_t i = 0; i < aCoordLists.size(); i++ )
1242 pCoordinates[i] = comphelper::containerToSequence( aCoordLists[i] );
1244 aBezierCoords.Flags.realloc( aFlagLists.size() );
1245 auto pFlags = aBezierCoords.Flags.getArray();
1246 for ( size_t i = 0; i < aFlagLists.size(); i++ )
1247 pFlags[i] = comphelper::containerToSequence( aFlagLists[i] );
1249 if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
1250 && aCoordLists.front().front().X == aCoordLists.back().back().X
1251 && aCoordLists.front().front().Y == aCoordLists.back().back().Y )
1252 { // HACK: If the shape is in fact closed, which can be found out only when the path is known,
1253 // force to closed bezier shape (otherwise e.g. fill won't work).
1254 const_cast< BezierShape* >( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1258 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1260 if( aBezierCoords.Coordinates.hasElements())
1262 PropertySet aPropSet( xShape );
1263 aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
1266 // tdf#105875 handle rotation
1267 // Note: must rotate before flip!
1268 handleRotation(maTypeModel, xShape);
1270 // Handle horizontal and vertical flip.
1271 handleMirroring(maTypeModel, xShape);
1273 return xShape;
1276 CustomShape::CustomShape( Drawing& rDrawing ) :
1277 SimpleShape( rDrawing, "com.sun.star.drawing.CustomShape" )
1281 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1283 // try to create a custom shape
1284 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1285 if( xShape.is() ) try
1287 // create the custom shape geometry
1288 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
1289 xDefaulter->createCustomShapeDefaults( OUString::number( getShapeType() ) );
1290 // convert common properties
1291 convertShapeProperties( xShape );
1293 catch( Exception& )
1296 return xShape;
1299 ComplexShape::ComplexShape( Drawing& rDrawing ) :
1300 CustomShape( rDrawing )
1304 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1306 XmlFilterBase& rFilter = mrDrawing.getFilter();
1307 sal_Int32 nShapeType = getShapeType();
1308 OUString aGraphicPath = getGraphicPath();
1310 // try to find registered OLE object info
1311 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
1313 SAL_WARN_IF(
1314 nShapeType != VML_SHAPETYPE_PICTUREFRAME, "oox",
1315 "ComplexShape::implConvertAndInsert - unexpected shape type");
1317 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
1318 if( pOleObjectInfo->mbDmlShape )
1319 return Reference< XShape >();
1321 PropertyMap aOleProps;
1322 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1323 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
1325 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.OLE2Shape", rxShapes, rShapeRect );
1326 if( xShape.is() )
1328 // set the replacement graphic
1329 if( !aGraphicPath.isEmpty() )
1331 WmfExternal aExtHeader;
1332 aExtHeader.mapMode = 8;
1333 aExtHeader.xExt = rShapeRect.Width;
1334 aExtHeader.yExt = rShapeRect.Height;
1336 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath, &aExtHeader);
1337 if (xGraphic.is())
1338 aOleProps.setProperty( PROP_Graphic, xGraphic);
1341 PropertySet aPropSet( xShape );
1342 aPropSet.setProperties( aOleProps );
1344 return xShape;
1349 // try to find registered form control info
1350 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
1351 if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
1353 if( !pControlInfo->maName.isEmpty() )
1355 // load the control properties from fragment
1356 ::oox::ole::EmbeddedControl aControl(pControlInfo->maName);
1357 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
1359 // create and return the control shape (including control model)
1360 sal_Int32 nCtrlIndex = -1;
1361 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
1363 if (pControlInfo->mbTextContentShape)
1365 PropertySet aPropertySet(xShape);
1366 lcl_SetAnchorType(aPropertySet, maTypeModel, mrDrawing.getFilter().getGraphicHelper());
1368 // on error, proceed and try to create picture from replacement image
1369 if( xShape.is() )
1370 return xShape;
1375 // host application wants to create the shape (do not try failed OLE controls again)
1376 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
1378 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
1379 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
1380 if( xShape.is() )
1381 return xShape;
1385 if( getShapeModel().mbIsSignatureLine )
1387 uno::Reference<graphic::XGraphic> xGraphic;
1388 bool bIsSigned(false);
1391 // Get the document signatures
1392 Reference<security::XDocumentDigitalSignatures> xSignatures(
1393 security::DocumentDigitalSignatures::createDefault(
1394 comphelper::getProcessComponentContext()));
1396 uno::Reference<embed::XStorage> xStorage
1397 = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
1398 ZIP_STORAGE_FORMAT_STRING, mrDrawing.getFilter().getFileUrl(),
1399 embed::ElementModes::READ);
1400 SAL_WARN_IF(!xStorage.is(), "oox.vml", "No xStorage!");
1402 const uno::Sequence<security::DocumentSignatureInformation> xSignatureInfo
1403 = xSignatures->verifyScriptingContentSignatures(xStorage,
1404 uno::Reference<io::XInputStream>());
1406 // Try to find matching signature line image - if none exists that is fine,
1407 // then the signature line is not digitally signed.
1408 auto pSignInfo = std::find_if(xSignatureInfo.begin(), xSignatureInfo.end(),
1409 [this](const security::DocumentSignatureInformation& rSigInfo) {
1410 return rSigInfo.SignatureLineId == getShapeModel().maSignatureId; });
1411 if (pSignInfo != xSignatureInfo.end())
1413 bIsSigned = true;
1414 if (pSignInfo->SignatureIsValid)
1416 // Signature is valid, use the 'valid' image
1417 SAL_WARN_IF(!pSignInfo->ValidSignatureLineImage.is(), "oox.vml",
1418 "No ValidSignatureLineImage!");
1419 xGraphic = pSignInfo->ValidSignatureLineImage;
1421 else
1423 // Signature is invalid, use the 'invalid' image
1424 SAL_WARN_IF(!pSignInfo->InvalidSignatureLineImage.is(), "oox.vml",
1425 "No InvalidSignatureLineImage!");
1426 xGraphic = pSignInfo->InvalidSignatureLineImage;
1430 catch (css::uno::Exception&)
1432 // DocumentDigitalSignatures service not available.
1433 // We continue by rendering the "unsigned" shape instead.
1436 Reference< XShape > xShape;
1437 if (xGraphic.is())
1439 // If available, use the signed image from the signature
1440 xShape = SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
1442 else
1444 // Create shape with the fallback "unsigned" image
1445 xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1448 // Store signature line properties
1449 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1450 xPropertySet->setPropertyValue("IsSignatureLine", uno::Any(true));
1451 xPropertySet->setPropertyValue("SignatureLineId",
1452 uno::Any(getShapeModel().maSignatureId));
1453 xPropertySet->setPropertyValue(
1454 "SignatureLineSuggestedSignerName",
1455 uno::Any(getShapeModel().maSignatureLineSuggestedSignerName));
1456 xPropertySet->setPropertyValue(
1457 "SignatureLineSuggestedSignerTitle",
1458 uno::Any(getShapeModel().maSignatureLineSuggestedSignerTitle));
1459 xPropertySet->setPropertyValue(
1460 "SignatureLineSuggestedSignerEmail",
1461 uno::Any(getShapeModel().maSignatureLineSuggestedSignerEmail));
1462 xPropertySet->setPropertyValue(
1463 "SignatureLineSigningInstructions",
1464 uno::Any(getShapeModel().maSignatureLineSigningInstructions));
1465 xPropertySet->setPropertyValue(
1466 "SignatureLineShowSignDate",
1467 uno::Any(getShapeModel().mbSignatureLineShowSignDate));
1468 xPropertySet->setPropertyValue(
1469 "SignatureLineCanAddComment",
1470 uno::Any(getShapeModel().mbSignatureLineCanAddComment));
1471 xPropertySet->setPropertyValue("SignatureLineIsSigned", uno::Any(bIsSigned));
1473 if (!aGraphicPath.isEmpty())
1475 xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath);
1476 xPropertySet->setPropertyValue("SignatureLineUnsignedImage", uno::Any(xGraphic));
1478 return xShape;
1481 // try to create a picture object
1482 if( !aGraphicPath.isEmpty() )
1484 Reference<XShape> xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1485 // AS_CHARACTER shape: vertical orientation default is bottom, MSO default is top.
1486 if ( maTypeModel.maPosition != "absolute" && maTypeModel.maPosition != "relative" )
1487 PropertySet( xShape ).setAnyProperty( PROP_VertOrient, Any(text::VertOrientation::TOP));
1489 // Apply stroke props from the type model.
1490 oox::drawingml::ShapePropertyMap aPropMap(mrDrawing.getFilter().getModelObjectHelper());
1491 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1492 maTypeModel.maStrokeModel.pushToPropMap(aPropMap, rGraphicHelper);
1493 // And, fill-color properties as well...
1494 maTypeModel.maFillModel.pushToPropMap(aPropMap, rGraphicHelper);
1495 PropertySet(xShape).setProperties(aPropMap);
1497 return xShape;
1500 // default: try to create a custom shape
1501 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
1504 GroupShape::GroupShape( Drawing& rDrawing ) :
1505 ShapeBase( rDrawing ),
1506 mxChildren( new ShapeContainer( rDrawing ) )
1510 GroupShape::~GroupShape()
1514 void GroupShape::finalizeFragmentImport()
1516 // basic shape processing
1517 ShapeBase::finalizeFragmentImport();
1518 // finalize all child shapes
1519 mxChildren->finalizeFragmentImport();
1522 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
1524 return mxChildren->getShapeTypeById( rShapeId );
1527 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
1529 return mxChildren->getShapeById( rShapeId );
1532 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1534 Reference< XShape > xGroupShape;
1535 // check that this shape contains children and a valid coordinate system
1536 ShapeParentAnchor aParentAnchor;
1537 aParentAnchor.maShapeRect = rShapeRect;
1538 aParentAnchor.maCoordSys = getCoordSystem();
1539 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
1541 xGroupShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GroupShape", rxShapes, rShapeRect );
1542 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
1543 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
1544 if( !xChildShapes->hasElements() )
1546 SAL_WARN("oox", "no child shape has been created - deleting the group shape");
1547 rxShapes->remove( xGroupShape );
1548 xGroupShape.clear();
1551 catch( Exception& )
1555 uno::Reference<beans::XPropertySet> xPropertySet;
1556 if (!maTypeModel.maEditAs.isEmpty())
1557 xPropertySet = uno::Reference<beans::XPropertySet>(xGroupShape, uno::UNO_QUERY);
1558 if (xPropertySet.is())
1560 uno::Sequence<beans::PropertyValue> aGrabBag;
1561 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1562 sal_Int32 nLength = aGrabBag.getLength();
1563 aGrabBag.realloc(nLength + 1);
1564 aGrabBag.getArray()[nLength] = comphelper::makePropertyValue("mso-edit-as", maTypeModel.maEditAs);
1565 xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag));
1567 // Make sure group shapes are inline as well, unless there is an explicit different style.
1568 PropertySet aPropertySet(xGroupShape);
1569 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1570 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper);
1571 if (!maTypeModel.maRotation.isEmpty())
1572 aPropertySet.setAnyProperty(PROP_RotateAngle, Any(ConversionHelper::decodeRotation(maTypeModel.maRotation).get()));
1573 return xGroupShape;
1576 } // namespace oox
1578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */