lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / oox / source / vml / vmlshape.cxx
blobd72809a6a89527e6b2457a45c3d19646f54521cb
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>
21 #include <cassert>
23 #include <boost/optional.hpp>
25 #include <o3tl/safeint.hxx>
26 #include <oox/vml/vmlshape.hxx>
27 #include <vcl/wmf.hxx>
28 #include <vcl/virdev.hxx>
30 #include <com/sun/star/beans/PropertyValues.hpp>
31 #include <com/sun/star/beans/XPropertySet.hpp>
32 #include <com/sun/star/awt/XControlModel.hpp>
33 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
34 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
35 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
36 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
37 #include <com/sun/star/drawing/XShapes.hpp>
38 #include <com/sun/star/drawing/XControlShape.hpp>
39 #include <com/sun/star/graphic/XGraphic.hpp>
40 #include <com/sun/star/table/BorderLine2.hpp>
41 #include <com/sun/star/text/HoriOrientation.hpp>
42 #include <com/sun/star/text/RelOrientation.hpp>
43 #include <com/sun/star/text/SizeType.hpp>
44 #include <com/sun/star/text/VertOrientation.hpp>
45 #include <com/sun/star/text/WrapTextMode.hpp>
46 #include <com/sun/star/text/XTextContent.hpp>
47 #include <com/sun/star/text/XTextDocument.hpp>
48 #include <com/sun/star/text/XTextFrame.hpp>
49 #include <com/sun/star/lang/XServiceInfo.hpp>
50 #include <com/sun/star/text/TextContentAnchorType.hpp>
51 #include <com/sun/star/text/GraphicCrop.hpp>
52 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
53 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
54 #include <com/sun/star/text/WritingMode2.hpp>
55 #include <rtl/math.hxx>
56 #include <rtl/ustrbuf.hxx>
57 #include <sal/log.hxx>
58 #include <svx/svdtrans.hxx>
59 #include <oox/drawingml/shapepropertymap.hxx>
60 #include <oox/helper/graphichelper.hxx>
61 #include <oox/helper/propertyset.hxx>
62 #include <oox/ole/axcontrol.hxx>
63 #include <oox/ole/axcontrolfragment.hxx>
64 #include <oox/ole/oleobjecthelper.hxx>
65 #include <oox/token/properties.hxx>
66 #include <oox/token/tokens.hxx>
67 #include <oox/vml/vmldrawing.hxx>
68 #include <oox/vml/vmlshapecontainer.hxx>
69 #include <oox/vml/vmltextbox.hxx>
70 #include <oox/core/xmlfilterbase.hxx>
71 #include <oox/helper/containerhelper.hxx>
72 #include <svx/EnhancedCustomShapeTypeNames.hxx>
73 #include <svx/unoapi.hxx>
74 #include <svx/svdoashp.hxx>
75 #include <comphelper/sequence.hxx>
76 #include <comphelper/processfactory.hxx>
77 #include <comphelper/propertyvalue.hxx>
78 #include <comphelper/storagehelper.hxx>
79 #include <vcl/svapp.hxx>
81 using ::com::sun::star::beans::XPropertySet;
82 using ::com::sun::star::uno::Any;
84 using namespace ::com::sun::star;
85 using namespace ::com::sun::star::text;
87 namespace oox {
88 namespace vml {
90 using namespace ::com::sun::star::drawing;
91 using namespace ::com::sun::star::graphic;
92 using namespace ::com::sun::star::uno;
93 using namespace ::com::sun::star::io;
95 using ::oox::core::XmlFilterBase;
97 namespace {
99 const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75;
100 const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201;
102 awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
104 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
105 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
106 awt::Point aAbsPoint;
107 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
108 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
109 return aAbsPoint;
112 awt::Rectangle lclGetAbsRect( const awt::Rectangle& rRelRect, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
114 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
115 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
116 awt::Rectangle aAbsRect;
117 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
118 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
119 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
120 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
121 return aAbsRect;
124 /// Count the crop value based on a crop fraction and a reference size.
125 sal_Int32 lclConvertCrop(const OUString& rCrop, sal_uInt32 nSize)
127 if (rCrop.endsWith("f"))
129 // Numeric value is specified in 1/65536-ths.
130 sal_uInt32 nCrop = rCrop.copy(0, rCrop.getLength() - 1).toUInt32();
131 return (nCrop * nSize) / 65536;
134 return 0;
137 } // namespace
139 ShapeTypeModel::ShapeTypeModel():
140 mbAutoHeight( false ),
141 mbVisible( true )
145 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
147 moShapeType.assignIfUsed( rSource.moShapeType );
148 moCoordPos.assignIfUsed( rSource.moCoordPos );
149 moCoordSize.assignIfUsed( rSource.moCoordSize );
150 /* The style properties position, left, top, width, height, margin-left,
151 margin-top are not derived from shape template to shape. */
152 maStrokeModel.assignUsed( rSource.maStrokeModel );
153 maFillModel.assignUsed( rSource.maFillModel );
154 moGraphicPath.assignIfUsed( rSource.moGraphicPath );
155 moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
158 ShapeType::ShapeType( Drawing& rDrawing ) :
159 mrDrawing( rDrawing )
163 ShapeType::~ShapeType()
167 sal_Int32 ShapeType::getShapeType() const
169 return maTypeModel.moShapeType.get( 0 );
172 OUString ShapeType::getGraphicPath() const
174 return maTypeModel.moGraphicPath.get( OUString() );
177 awt::Rectangle ShapeType::getCoordSystem() const
179 Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) );
180 Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) );
181 if( aCoordSize.first == 0 )
182 aCoordSize.first = 1;
183 if( aCoordSize.second == 0 )
184 aCoordSize.second = 1;
185 return awt::Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second );
188 awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
190 return pParentAnchor ?
191 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
192 getAbsRectangle();
195 awt::Rectangle ShapeType::getAbsRectangle() const
197 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
199 sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
200 if ( nWidth == 0 )
201 nWidth = 1;
203 sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
204 if ( nHeight == 0 )
205 nHeight = 1;
207 sal_Int32 nLeft;
208 if (o3tl::checked_add<sal_Int32>(ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maLeft, 0, true, true),
209 ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true),
210 nLeft))
212 SAL_WARN("oox", "overflow in addition");
213 nLeft = 0;
215 if (nLeft == 0 && maTypeModel.maPosition == "absolute")
216 nLeft = 1;
218 return awt::Rectangle(
219 nLeft,
220 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
221 nWidth, nHeight );
224 awt::Rectangle ShapeType::getRelRectangle() const
226 sal_Int32 nWidth = maTypeModel.maWidth.toInt32();
227 if ( nWidth == 0 )
228 nWidth = 1;
230 sal_Int32 nHeight = maTypeModel.maHeight.toInt32();
231 if ( nHeight == 0 )
232 nHeight = 1;
234 return awt::Rectangle(
235 maTypeModel.maLeft.toInt32(),
236 maTypeModel.maTop.toInt32(),
237 nWidth, nHeight );
240 ClientData::ClientData() :
241 mnObjType( XML_TOKEN_INVALID ),
242 mnTextHAlign( XML_Left ),
243 mnTextVAlign( XML_Top ),
244 mnCol( -1 ),
245 mnRow( -1 ),
246 mnChecked( VML_CLIENTDATA_UNCHECKED ),
247 mnDropStyle( XML_Combo ),
248 mnDropLines( 1 ),
249 mnVal( 0 ),
250 mnMin( 0 ),
251 mnMax( 0 ),
252 mnInc( 0 ),
253 mnPage( 0 ),
254 mnSelType( XML_Single ),
255 mnVTEdit( VML_CLIENTDATA_TEXT ),
256 mbPrintObject( true ),
257 mbVisible( false ),
258 mbDde( false ),
259 mbNo3D( false ),
260 mbNo3D2( false ),
261 mbMultiLine( false ),
262 mbVScroll( false ),
263 mbSecretEdit( false )
267 ShapeModel::ShapeModel()
268 : mbIsSignatureLine(false)
269 , mbSignatureLineShowSignDate(true)
270 , mbSignatureLineCanAddComment(false)
274 ShapeModel::~ShapeModel()
278 TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
280 mxTextBox.reset( new TextBox(rModel) );
281 return *mxTextBox;
284 ClientData& ShapeModel::createClientData()
286 mxClientData.reset( new ClientData );
287 return *mxClientData;
290 ShapeBase::ShapeBase( Drawing& rDrawing ) :
291 ShapeType( rDrawing )
295 void ShapeBase::finalizeFragmentImport()
297 if( maShapeModel.maType.getLength() > 1 )
299 OUString aType = maShapeModel.maType;
300 if (aType[ 0 ] == '#')
301 aType = aType.copy(1);
302 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( aType ) )
303 maTypeModel.assignUsed( pShapeType->getTypeModel() );
304 else {
305 // Temporary fix, shapetype not found if referenced from different substream
306 // FIXME: extend scope of ShapeContainer to store all shapetypes from the document
307 const OUString sShapeTypePrefix = "shapetype_";
308 if (aType.startsWith(sShapeTypePrefix)) {
309 maTypeModel.moShapeType = aType.copy(sShapeTypePrefix.getLength()).toInt32();
315 OUString ShapeBase::getShapeName() const
317 if( !maTypeModel.maShapeName.isEmpty() )
318 return maTypeModel.maShapeName;
320 OUString aBaseName = mrDrawing.getShapeBaseName( *this );
321 if( !aBaseName.isEmpty() )
323 sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
324 if( nShapeIdx > 0 )
325 return aBaseName + OUStringLiteral1(' ') + OUString::number( nShapeIdx );
328 return OUString();
331 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
333 return nullptr;
336 const ShapeBase* ShapeBase::getChildById( const OUString& ) const
338 return nullptr;
341 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
343 Reference< XShape > xShape;
344 if( mrDrawing.isShapeSupported( *this ) )
346 /* Calculate shape rectangle. Applications may do something special
347 according to some imported shape client data (e.g. Excel cell anchor). */
348 awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
350 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
352 xShape = implConvertAndInsert( rxShapes, aShapeRect );
353 if( xShape.is() )
355 // set imported or generated shape name (not supported by form controls)
356 PropertySet aShapeProp( xShape );
357 if( aShapeProp.hasProperty( PROP_Name ) )
358 aShapeProp.setProperty( PROP_Name, getShapeName() );
359 uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
361 OUString sLinkChainName = getTypeModel().maLegacyId;
362 sal_Int32 id = 0;
363 sal_Int32 idPos = sLinkChainName.indexOf("_x");
364 sal_Int32 seq = 0;
365 if (idPos >= 0)
367 sal_Int32 seqPos = sLinkChainName.indexOf("_s",idPos);
368 if (idPos < seqPos)
370 auto idPosEnd = idPos+2;
371 id = sLinkChainName.copy(idPosEnd, seqPos - idPosEnd).toInt32();
372 seq = sLinkChainName.copy(seqPos+2).toInt32();
376 OUString s_mso_next_textbox;
377 if( getTextBox() )
378 s_mso_next_textbox = getTextBox()->msNextTextbox;
379 if( s_mso_next_textbox.startsWith("#") )
380 s_mso_next_textbox = s_mso_next_textbox.copy(1);
382 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
384 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
385 uno::Any aAny = propertySet->getPropertyValue("FrameInteropGrabBag");
386 auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >());
388 aGrabBag.push_back(comphelper::makePropertyValue("VML-Z-ORDER", maTypeModel.maZIndex.toInt32()));
390 if( !s_mso_next_textbox.isEmpty() )
391 aGrabBag.push_back(comphelper::makePropertyValue("mso-next-textbox", s_mso_next_textbox));
393 if( !sLinkChainName.isEmpty() )
395 aGrabBag.push_back(comphelper::makePropertyValue("TxbxHasLink", true));
396 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Id", id));
397 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Seq", seq));
398 aGrabBag.push_back(comphelper::makePropertyValue("LinkChainName", sLinkChainName));
401 if(!maTypeModel.maRotation.isEmpty())
402 aGrabBag.push_back(comphelper::makePropertyValue("mso-rotation-angle", ConversionHelper::decodeRotation(maTypeModel.maRotation)));
403 propertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(comphelper::containerToSequence(aGrabBag)));
404 sal_Int32 backColorTransparency = 0;
405 propertySet->getPropertyValue("BackColorTransparency")
406 >>= backColorTransparency;
407 if (propertySet->getPropertyValue("FillStyle") == FillStyle_NONE &&
408 backColorTransparency == 100)
410 // If there is no fill, the Word default is 100% transparency.
411 propertySet->setPropertyValue("FillTransparence", makeAny(sal_Int16(100)));
414 else
416 if( maTypeModel.maZIndex.toInt32() )
418 uno::Sequence<beans::PropertyValue> aGrabBag;
419 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
420 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
421 sal_Int32 length;
423 length = aGrabBag.getLength();
424 aGrabBag.realloc( length+1 );
425 aGrabBag[length].Name = "VML-Z-ORDER";
426 aGrabBag[length].Value <<= maTypeModel.maZIndex.toInt32();
428 if( !s_mso_next_textbox.isEmpty() )
430 length = aGrabBag.getLength();
431 aGrabBag.realloc( length+1 );
432 aGrabBag[length].Name = "mso-next-textbox";
433 aGrabBag[length].Value <<= s_mso_next_textbox;
436 if( !sLinkChainName.isEmpty() )
438 length = aGrabBag.getLength();
439 aGrabBag.realloc( length+4 );
440 aGrabBag[length].Name = "TxbxHasLink";
441 aGrabBag[length].Value <<= true;
442 aGrabBag[length+1].Name = "Txbx-Id";
443 aGrabBag[length+1].Value <<= id;
444 aGrabBag[length+2].Name = "Txbx-Seq";
445 aGrabBag[length+2].Value <<= seq;
446 aGrabBag[length+3].Name = "LinkChainName";
447 aGrabBag[length+3].Value <<= sLinkChainName;
449 propertySet->setPropertyValue( "InteropGrabBag", uno::makeAny(aGrabBag) );
452 Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
453 if ( xControlShape.is() && !getTypeModel().mbVisible )
455 PropertySet aControlShapeProp( xControlShape->getControl() );
456 aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( false ) );
458 /* Notify the drawing that a new shape has been inserted. For
459 convenience, pass the rectangle that contains position and
460 size of the shape. */
461 bool bGroupChild = pParentAnchor != nullptr;
462 mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
465 else
466 SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
468 return xShape;
471 void ShapeBase::convertFormatting( const Reference< XShape >& rxShape ) const
473 if( rxShape.is() )
475 /* Calculate shape rectangle. Applications may do something special
476 according to some imported shape client data (e.g. Excel cell anchor). */
477 awt::Rectangle aShapeRect = calcShapeRectangle( nullptr );
479 // convert the shape, if the calculated rectangle is not empty
480 if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
482 rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
483 rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
484 convertShapeProperties( rxShape );
489 // protected ------------------------------------------------------------------
491 awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
493 /* Calculate shape rectangle. Applications may do something special
494 according to some imported shape client data (e.g. Excel cell anchor). */
495 awt::Rectangle aShapeRect;
496 const ClientData* pClientData = getClientData();
497 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
498 aShapeRect = getRectangle( pParentAnchor );
499 return aShapeRect;
502 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
504 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
505 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
506 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
507 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
509 uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
510 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
512 // Any other service supporting the ShadowFormat property?
513 maTypeModel.maShadowModel.pushToPropMap(aPropMap, rGraphicHelper);
514 // TextFrames have BackColor, not FillColor
515 if (aPropMap.hasProperty(PROP_FillColor))
517 aPropMap.setAnyProperty(PROP_BackColor, aPropMap.getProperty(PROP_FillColor));
518 aPropMap.erase(PROP_FillColor);
520 // TextFrames have BackColorTransparency, not FillTransparence
521 if (aPropMap.hasProperty(PROP_FillTransparence))
523 aPropMap.setAnyProperty(PROP_BackColorTransparency, aPropMap.getProperty(PROP_FillTransparence));
524 aPropMap.erase(PROP_FillTransparence);
526 // And no LineColor property; individual borders can have colors and widths
527 boost::optional<sal_Int32> oLineWidth;
528 if (maTypeModel.maStrokeModel.moWeight.has())
529 oLineWidth = ConversionHelper::decodeMeasureToHmm(
530 rGraphicHelper, maTypeModel.maStrokeModel.moWeight.get(), 0, false, false);
531 if (aPropMap.hasProperty(PROP_LineColor))
533 uno::Reference<beans::XPropertySet> xPropertySet(rxShape, uno::UNO_QUERY);
534 static const sal_Int32 aBorders[] = {
535 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
537 for (sal_Int32 nBorder : aBorders)
539 table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<table::BorderLine2>();
540 aBorderLine.Color = aPropMap.getProperty(PROP_LineColor).get<sal_Int32>();
541 if (oLineWidth)
542 aBorderLine.LineWidth = *oLineWidth;
543 aPropMap.setProperty(nBorder, aBorderLine);
545 aPropMap.erase(PROP_LineColor);
548 else if (xSInfo->supportsService("com.sun.star.drawing.CustomShape"))
549 maTypeModel.maTextpathModel.pushToPropMap(aPropMap, rxShape, rGraphicHelper);
551 PropertySet( rxShape ).setProperties( aPropMap );
554 SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) :
555 ShapeBase( rDrawing ),
556 maService( rService )
560 static void lcl_setSurround(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
562 OUString aWrapType = rTypeModel.moWrapType.get();
564 // 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.
565 sal_Int32 nMarginTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, rTypeModel.maMarginTop, 0, false, true);
566 if (nMarginTop < -35277) // Less than 1000 points.
567 aWrapType.clear();
569 css::text::WrapTextMode nSurround = css::text::WrapTextMode_THROUGH;
570 if ( aWrapType == "square" || aWrapType == "tight" ||
571 aWrapType == "through" )
573 nSurround = css::text::WrapTextMode_PARALLEL;
574 if ( rTypeModel.moWrapSide.get() == "left" )
575 nSurround = css::text::WrapTextMode_LEFT;
576 else if ( rTypeModel.moWrapSide.get() == "right" )
577 nSurround = css::text::WrapTextMode_RIGHT;
579 else if ( aWrapType == "topAndBottom" )
580 nSurround = css::text::WrapTextMode_NONE;
582 rPropSet.setProperty(PROP_Surround, static_cast<sal_Int32>(nSurround));
585 static void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
587 if ( rTypeModel.maPosition == "absolute" )
589 // Word supports as-character (inline) and at-character only, absolute can't be inline.
590 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
591 // anchor is set after insertion, so reset to NONE
592 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
594 if ( rTypeModel.maPositionVerticalRelative == "page" )
596 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
598 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
600 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
602 else
604 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
607 else if( rTypeModel.maPosition == "relative" )
608 { // I'm not very sure this is correct either.
609 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
610 // anchor is set after insertion, so reset to NONE
611 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
613 else // static (is the default) means anchored inline
615 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
616 // Use top orientation, this one seems similar to what MSO uses as inline
617 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
620 if ( rTypeModel.maPositionHorizontal == "center" )
621 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::CENTER));
622 else if ( rTypeModel.maPositionHorizontal == "left" )
623 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
624 else if ( rTypeModel.maPositionHorizontal == "right" )
625 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
626 else if ( rTypeModel.maPositionHorizontal == "inside" )
628 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
629 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
631 else if ( rTypeModel.maPositionHorizontal == "outside" )
633 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
634 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
637 if ( rTypeModel.maPositionHorizontalRelative == "page" )
638 rPropSet.setAnyProperty(PROP_HoriOrientRelation, makeAny(text::RelOrientation::PAGE_FRAME));
639 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
640 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
641 else if ( rTypeModel.maPositionVerticalRelative == "text" )
642 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
644 if ( rTypeModel.maPositionVertical == "center" )
645 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::CENTER));
646 else if ( rTypeModel.maPositionVertical == "top" )
647 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
648 else if ( rTypeModel.maPositionVertical == "bottom" )
649 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::BOTTOM));
650 else if ( rTypeModel.maPositionVertical == "inside" )
651 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_TOP));
652 else if ( rTypeModel.maPositionVertical == "outside" )
653 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_BOTTOM));
655 lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper );
658 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
660 awt::Rectangle aShapeRect(rShapeRect);
661 boost::optional<sal_Int32> oRotation;
662 bool bFlipX = false, bFlipY = false;
663 if (!maTypeModel.maRotation.isEmpty())
664 oRotation = ConversionHelper::decodeRotation(maTypeModel.maRotation);
665 if (!maTypeModel.maFlip.isEmpty())
667 if (maTypeModel.maFlip == "x")
669 bFlipX = true;
671 else if (maTypeModel.maFlip == "y")
673 bFlipY = true;
677 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
678 SdrObject* pShape = GetSdrObjectFromXShape( xShape );
679 if( pShape && getShapeType() >= 0 )
681 OUString aShapeType;
682 aShapeType = EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT >(getShapeType()) );
683 //The resize autoshape to fit text attr of FontWork/Word-Art should always be false
684 //for the fallback geometry.
685 if(aShapeType.startsWith("fontwork"))
687 pShape->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
688 pShape->SetMergedItem(makeSdrTextAutoGrowWidthItem(false));
691 convertShapeProperties( xShape );
693 // Handle left/right/top/bottom wrap distance.
694 // Default value of mso-wrap-distance-left/right is supposed to be 0 (see
695 // 19.1.2.19 of the VML spec), but Word implements a non-zero value.
696 // [MS-ODRAW] says the below default value in 2.3.4.9.
697 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
698 OUString aWrapDistanceLeft = OUString::number(0x0001BE7C);
699 if (!maTypeModel.maWrapDistanceLeft.isEmpty())
700 aWrapDistanceLeft = maTypeModel.maWrapDistanceLeft;
701 sal_Int32 nWrapDistanceLeft = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceLeft, 0, true, false);
702 PropertySet(xShape).setAnyProperty(PROP_LeftMargin, uno::makeAny(nWrapDistanceLeft));
703 OUString aWrapDistanceRight = OUString::number(0x0001BE7C);
704 if (!maTypeModel.maWrapDistanceRight.isEmpty())
705 aWrapDistanceRight = maTypeModel.maWrapDistanceRight;
706 sal_Int32 nWrapDistanceRight = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceRight, 0, true, false);
707 PropertySet(xShape).setAnyProperty(PROP_RightMargin, uno::makeAny(nWrapDistanceRight));
708 sal_Int32 nWrapDistanceTop = 0;
709 if (!maTypeModel.maWrapDistanceTop.isEmpty())
710 nWrapDistanceTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceTop, 0, false, true);
711 PropertySet(xShape).setAnyProperty(PROP_TopMargin, uno::makeAny(nWrapDistanceTop));
712 sal_Int32 nWrapDistanceBottom = 0;
713 if (!maTypeModel.maWrapDistanceBottom.isEmpty())
714 nWrapDistanceBottom = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceBottom, 0, false, true);
715 PropertySet(xShape).setAnyProperty(PROP_BottomMargin, uno::makeAny(nWrapDistanceBottom));
717 if ( maService == "com.sun.star.text.TextFrame" )
719 PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, makeAny( maTypeModel.mbAutoHeight ) );
720 PropertySet( xShape ).setAnyProperty( PROP_SizeType, makeAny( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
721 if( getTextBox()->borderDistanceSet )
723 PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceLeft )));
724 PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceTop )));
725 PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceRight )));
726 PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceBottom )));
729 if (getTextBox()->maLayoutFlow == "vertical")
731 sal_Int16 nWritingMode = text::WritingMode2::TB_RL;
732 if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
734 nWritingMode = text::WritingMode2::BT_LR;
736 PropertySet(xShape).setAnyProperty(PROP_WritingMode, uno::makeAny(nWritingMode));
739 else
741 // FIXME Setting the relative width/height only for everything but text frames as
742 // TextFrames already have relative width/height feature... but currently not working
743 // in the way we need.
745 // Set the relative width / height if any
746 if ( !maTypeModel.maWidthPercent.isEmpty( ) )
748 // Only page-relative width is supported ATM
749 if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
751 sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
752 // Only apply if nWidth != 0
753 if ( nWidth )
754 PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, makeAny( nWidth ) );
757 if ( !maTypeModel.maHeightPercent.isEmpty( ) )
759 // Only page-relative height is supported ATM
760 if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
762 sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
763 // Only apply if nHeight != 0
764 if ( nHeight )
765 PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
769 // drawinglayer default is center, MSO default is top.
770 drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP;
771 if (maTypeModel.maVTextAnchor == "middle")
772 eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER;
773 else if (maTypeModel.maVTextAnchor == "bottom")
774 eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
775 PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, makeAny(eTextVerticalAdjust));
777 if (getTextBox())
779 getTextBox()->convert(xShape);
780 if (getTextBox()->borderDistanceSet)
782 awt::Size aSize = xShape->getSize();
783 PropertySet(xShape).setAnyProperty(PROP_TextLeftDistance, makeAny(sal_Int32(getTextBox()->borderDistanceLeft)));
784 PropertySet(xShape).setAnyProperty(PROP_TextUpperDistance, makeAny(sal_Int32(getTextBox()->borderDistanceTop)));
785 PropertySet(xShape).setAnyProperty(PROP_TextRightDistance, makeAny(sal_Int32(getTextBox()->borderDistanceRight)));
786 PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, makeAny(sal_Int32(getTextBox()->borderDistanceBottom)));
787 xShape->setSize(aSize);
792 // Import Legacy Fragments (if any)
793 if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
795 Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
796 if( xInStrm.is() )
797 PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
800 PropertySet aPropertySet(xShape);
801 if (xShape.is())
803 if (oRotation)
805 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(*oRotation));
806 uno::Reference<lang::XServiceInfo> xServiceInfo(rxShapes, uno::UNO_QUERY);
807 if (!xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
809 // If rotation is used, simple setPosition() is not enough.
810 aPropertySet.setAnyProperty(PROP_HoriOrientPosition, makeAny(aShapeRect.X));
811 aPropertySet.setAnyProperty(PROP_VertOrientPosition, makeAny(aShapeRect.Y));
815 // custom shape geometry attributes
816 std::vector<css::beans::PropertyValue> aPropVec;
818 // When flip has 'x' or 'y', the associated ShapeRect will be changed but direction change doesn't occur.
819 // It might occur internally in SdrObject of "sw" module, not here.
820 // The associated properties "PROP_MirroredX" and "PROP_MirroredY" have to be set here so that direction change will occur internally.
821 if (bFlipX || bFlipY)
823 assert(!(bFlipX && bFlipY));
824 css::beans::PropertyValue aProp;
825 if (bFlipX)
826 aProp.Name = "MirroredX";
827 else
828 aProp.Name = "MirroredY";
829 aProp.Value <<= true;
830 aPropVec.push_back(aProp);
833 if (!maTypeModel.maAdjustments.isEmpty())
835 std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
836 sal_Int32 nIndex = 0;
839 OUString aToken = maTypeModel.maAdjustments.getToken(0, ',', nIndex);
840 drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue;
841 if (aToken.isEmpty())
842 aAdjustmentValue.State = css::beans::PropertyState::PropertyState_DEFAULT_VALUE;
843 else
844 aAdjustmentValue.Value <<= aToken.toInt32();
845 aAdjustmentValues.push_back(aAdjustmentValue);
846 } while (nIndex >= 0);
848 css::beans::PropertyValue aProp;
849 aProp.Name = "AdjustmentValues";
850 aProp.Value <<= comphelper::containerToSequence(aAdjustmentValues);
851 aPropVec.push_back(aProp);
854 if (!aPropVec.empty())
855 aPropertySet.setAnyProperty(PROP_CustomShapeGeometry, makeAny(comphelper::containerToSequence(aPropVec)));
858 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper );
860 return xShape;
863 Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
865 Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath);
866 return SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
869 Reference< XShape > SimpleShape::createPictureObject(const Reference< XShapes >& rxShapes,
870 const awt::Rectangle& rShapeRect,
871 uno::Reference<graphic::XGraphic> const & rxGraphic) const
873 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
874 if( xShape.is() )
876 PropertySet aPropSet(xShape);
877 if (rxGraphic.is())
879 aPropSet.setProperty(PROP_Graphic, rxGraphic);
881 uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
882 // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
883 if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
885 aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
886 aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
887 aPropSet.setProperty(PROP_Opaque, false);
889 // fdo#70457: preserve rotation information
890 if ( !maTypeModel.maRotation.isEmpty() )
891 aPropSet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
893 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
894 lcl_SetAnchorType(aPropSet, maTypeModel, rGraphicHelper);
896 if (maTypeModel.moCropBottom.has() || maTypeModel.moCropLeft.has() || maTypeModel.moCropRight.has() || maTypeModel.moCropTop.has())
898 text::GraphicCrop aGraphicCrop;
899 awt::Size aOriginalSize = rGraphicHelper.getOriginalSize(rxGraphic);
901 if (maTypeModel.moCropBottom.has())
902 aGraphicCrop.Bottom = lclConvertCrop(maTypeModel.moCropBottom.get(), aOriginalSize.Height);
903 if (maTypeModel.moCropLeft.has())
904 aGraphicCrop.Left = lclConvertCrop(maTypeModel.moCropLeft.get(), aOriginalSize.Width);
905 if (maTypeModel.moCropRight.has())
906 aGraphicCrop.Right = lclConvertCrop(maTypeModel.moCropRight.get(), aOriginalSize.Width);
907 if (maTypeModel.moCropTop.has())
908 aGraphicCrop.Top = lclConvertCrop(maTypeModel.moCropTop.get(), aOriginalSize.Height);
910 aPropSet.setProperty(PROP_GraphicCrop, aGraphicCrop);
913 return xShape;
916 RectangleShape::RectangleShape( Drawing& rDrawing ) :
917 SimpleShape( rDrawing, "com.sun.star.drawing.RectangleShape" )
921 Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
923 OUString aGraphicPath = getGraphicPath();
925 // try to create a picture object
926 if(!aGraphicPath.isEmpty())
927 return SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
929 // default: try to create a rectangle shape
930 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
931 OUString sArcsize = maTypeModel.maArcsize;
932 if ( !sArcsize.isEmpty( ) )
934 sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
935 sal_Int32 nValue = sArcsize.copy( 0, sArcsize.getLength() - 1 ).toInt32( );
936 // Get the smallest half-side
937 double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
938 sal_Int32 nRadius = 0;
939 if ( cLastChar == 'f' )
940 nRadius = size * nValue / 65536;
941 else if ( cLastChar == '%' )
942 nRadius = size * nValue / 100;
943 PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, makeAny( nRadius ) );
945 return xShape;
948 EllipseShape::EllipseShape( Drawing& rDrawing ) :
949 SimpleShape( rDrawing, "com.sun.star.drawing.EllipseShape" )
953 PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
954 SimpleShape( rDrawing, "com.sun.star.drawing.PolyLineShape" )
958 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
960 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
961 // polygon path
962 awt::Rectangle aCoordSys = getCoordSystem();
963 if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
965 ::std::vector< awt::Point > aAbsPoints;
966 for (auto const& point : maShapeModel.maPoints)
967 aAbsPoints.push_back( lclGetAbsPoint( point, rShapeRect, aCoordSys ) );
968 PointSequenceSequence aPointSeq( 1 );
969 aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
970 PropertySet aPropSet( xShape );
971 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
973 return xShape;
976 LineShape::LineShape(Drawing& rDrawing)
977 : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
981 awt::Rectangle LineShape::getAbsRectangle() const
983 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
984 awt::Rectangle aShapeRect;
985 sal_Int32 nIndex = 0;
987 aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, true, true);
988 aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, false, true);
989 nIndex = 0;
990 aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, true, true) - aShapeRect.X;
991 aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, false, true) - aShapeRect.Y;
992 return aShapeRect;
995 awt::Rectangle LineShape::getRelRectangle() const
997 awt::Rectangle aShapeRect;
998 sal_Int32 nIndex = 0;
1000 aShapeRect.X = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1001 aShapeRect.Y = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1002 nIndex = 0;
1003 aShapeRect.Width = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.X;
1004 aShapeRect.Height = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.Y;
1005 return aShapeRect;
1008 BezierShape::BezierShape(Drawing& rDrawing)
1009 : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
1013 Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1015 // If we have an 'x' in the last part of the path it means it is closed...
1016 sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(',');
1017 if ( nPos != -1 && maShapeModel.maVmlPath.indexOf('x', nPos) != -1 )
1019 const_cast<BezierShape*>( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1022 awt::Rectangle aCoordSys = getCoordSystem();
1023 PolyPolygonBezierCoords aBezierCoords;
1025 if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
1027 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1029 // Bezier paths may consist of one or more sub-paths
1030 typedef ::std::vector< ::std::vector< awt::Point > > SubPathList;
1031 typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
1032 SubPathList aCoordLists;
1033 FlagsList aFlagLists;
1034 sal_Int32 nIndex = 0;
1036 // Curve defined by to, from, control1 and control2 attributes
1037 if ( maShapeModel.maVmlPath.isEmpty() )
1039 aCoordLists.emplace_back( );
1040 aFlagLists.emplace_back( );
1042 // Start point
1043 aCoordLists[ 0 ].emplace_back(
1044 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ),
1045 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) );
1046 // Control point 1
1047 aCoordLists[ 0 ].emplace_back(
1048 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ),
1049 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) );
1050 // Control point 2
1051 aCoordLists[ 0 ].emplace_back(
1052 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ),
1053 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) );
1054 // End point
1055 aCoordLists[ 0 ].emplace_back(
1056 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ),
1057 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) );
1059 // First and last points are normals, points 2 and 4 are controls
1060 aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
1061 aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
1062 aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
1064 // Curve defined by path attribute
1065 else
1067 // Parse VML path string and convert to absolute coordinates
1068 ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
1070 for (auto & coordList : aCoordLists)
1071 for (auto & point : coordList)
1073 point = lclGetAbsPoint( point, rShapeRect, aCoordSys );
1077 aBezierCoords.Coordinates.realloc( aCoordLists.size() );
1078 for ( size_t i = 0; i < aCoordLists.size(); i++ )
1079 aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] );
1081 aBezierCoords.Flags.realloc( aFlagLists.size() );
1082 for ( size_t i = 0; i < aFlagLists.size(); i++ )
1083 aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] );
1085 if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
1086 && aCoordLists.front().front().X == aCoordLists.back().back().X
1087 && aCoordLists.front().front().Y == aCoordLists.back().back().Y )
1088 { // HACK: If the shape is in fact closed, which can be found out only when the path is known,
1089 // force to closed bezier shape (otherwise e.g. fill won't work).
1090 const_cast< BezierShape* >( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1094 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1096 if( aBezierCoords.Coordinates.hasElements())
1098 PropertySet aPropSet( xShape );
1099 aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
1102 // Handle horizontal and vertical flip.
1103 if (!maTypeModel.maFlip.isEmpty())
1105 if (SdrObject* pShape = GetSdrObjectFromXShape(xShape))
1107 if (maTypeModel.maFlip.startsWith("x"))
1109 Point aCenter(pShape->GetSnapRect().Center());
1110 Point aPoint2(aCenter);
1111 aPoint2.setY(aPoint2.getY() + 1);
1112 pShape->NbcMirror(aCenter, aPoint2);
1114 if (maTypeModel.maFlip.endsWith("y"))
1116 Point aCenter(pShape->GetSnapRect().Center());
1117 Point aPoint2(aCenter);
1118 aPoint2.setX(aPoint2.getX() + 1);
1119 pShape->NbcMirror(aCenter, aPoint2);
1124 // Hacky way of ensuring the shape is correctly sized/positioned
1127 // E.g. SwXFrame::setPosition() unconditionally throws
1128 xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
1129 xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
1131 catch (const ::css::uno::Exception&)
1133 // TODO: try some other way to ensure size/position
1135 return xShape;
1138 CustomShape::CustomShape( Drawing& rDrawing ) :
1139 SimpleShape( rDrawing, "com.sun.star.drawing.CustomShape" )
1143 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1145 // try to create a custom shape
1146 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1147 if( xShape.is() ) try
1149 // create the custom shape geometry
1150 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
1151 xDefaulter->createCustomShapeDefaults( OUString::number( getShapeType() ) );
1152 // convert common properties
1153 convertShapeProperties( xShape );
1155 catch( Exception& )
1158 return xShape;
1161 ComplexShape::ComplexShape( Drawing& rDrawing ) :
1162 CustomShape( rDrawing )
1166 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1168 XmlFilterBase& rFilter = mrDrawing.getFilter();
1169 sal_Int32 nShapeType = getShapeType();
1170 OUString aGraphicPath = getGraphicPath();
1172 // try to find registered OLE object info
1173 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
1175 SAL_WARN_IF(
1176 nShapeType != VML_SHAPETYPE_PICTUREFRAME, "oox",
1177 "ComplexShape::implConvertAndInsert - unexpected shape type");
1179 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
1180 if( pOleObjectInfo->mbDmlShape )
1181 return Reference< XShape >();
1183 PropertyMap aOleProps;
1184 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1185 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
1187 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.OLE2Shape", rxShapes, rShapeRect );
1188 if( xShape.is() )
1190 // set the replacement graphic
1191 if( !aGraphicPath.isEmpty() )
1193 WmfExternal aExtHeader;
1194 aExtHeader.mapMode = 8;
1195 aExtHeader.xExt = rShapeRect.Width;
1196 aExtHeader.yExt = rShapeRect.Height;
1198 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath, &aExtHeader);
1199 if (xGraphic.is())
1200 aOleProps.setProperty( PROP_Graphic, xGraphic);
1203 PropertySet aPropSet( xShape );
1204 aPropSet.setProperties( aOleProps );
1206 return xShape;
1211 // try to find registered form control info
1212 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
1213 if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
1215 if( !pControlInfo->maName.isEmpty() )
1217 // load the control properties from fragment
1218 ::oox::ole::EmbeddedControl aControl(pControlInfo->maName);
1219 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
1221 // create and return the control shape (including control model)
1222 sal_Int32 nCtrlIndex = -1;
1223 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
1225 if (pControlInfo->mbTextContentShape)
1227 PropertySet aPropertySet(xShape);
1228 lcl_SetAnchorType(aPropertySet, maTypeModel, mrDrawing.getFilter().getGraphicHelper());
1230 // on error, proceed and try to create picture from replacement image
1231 if( xShape.is() )
1232 return xShape;
1237 // host application wants to create the shape (do not try failed OLE controls again)
1238 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
1240 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
1241 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
1242 if( xShape.is() )
1243 return xShape;
1247 if( getShapeModel().mbIsSignatureLine )
1249 uno::Reference<graphic::XGraphic> xGraphic;
1250 bool bIsSigned(false);
1253 // Get the document signatures
1254 Reference<security::XDocumentDigitalSignatures> xSignatures(
1255 security::DocumentDigitalSignatures::createWithVersion(
1256 comphelper::getProcessComponentContext(), "1.2"));
1258 uno::Reference<embed::XStorage> xStorage
1259 = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
1260 ZIP_STORAGE_FORMAT_STRING, mrDrawing.getFilter().getFileUrl(),
1261 embed::ElementModes::READ);
1262 SAL_WARN_IF(!xStorage.is(), "oox.vml", "No xStorage!");
1264 uno::Sequence<security::DocumentSignatureInformation> xSignatureInfo
1265 = xSignatures->verifyScriptingContentSignatures(xStorage,
1266 uno::Reference<io::XInputStream>());
1268 for (int i = 0; i < xSignatureInfo.getLength(); i++)
1270 // Try to find matching signature line image - if none exists that is fine,
1271 // then the signature line is not digitally signed.
1272 if (xSignatureInfo[i].SignatureLineId == getShapeModel().maSignatureId)
1274 bIsSigned = true;
1275 if (xSignatureInfo[i].SignatureIsValid)
1277 // Signature is valid, use the 'valid' image
1278 SAL_WARN_IF(!xSignatureInfo[i].ValidSignatureLineImage.is(), "oox.vml",
1279 "No ValidSignatureLineImage!");
1280 xGraphic = xSignatureInfo[i].ValidSignatureLineImage;
1282 else
1284 // Signature is invalid, use the 'invalid' image
1285 SAL_WARN_IF(!xSignatureInfo[i].InvalidSignatureLineImage.is(), "oox.vml",
1286 "No InvalidSignatureLineImage!");
1287 xGraphic = xSignatureInfo[i].InvalidSignatureLineImage;
1289 break;
1293 catch (css::uno::Exception&)
1295 // DocumentDigitalSignatures service not available.
1296 // We continue by rendering the "unsigned" shape instead.
1299 Reference< XShape > xShape;
1300 if (xGraphic.is())
1302 // If available, use the signed image from the signature
1303 xShape = SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
1305 else
1307 // Create shape with the fallback "unsigned" image
1308 xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1311 // Store signature line properties
1312 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1313 xPropertySet->setPropertyValue("IsSignatureLine", uno::makeAny(true));
1314 xPropertySet->setPropertyValue("SignatureLineId",
1315 uno::makeAny(getShapeModel().maSignatureId));
1316 xPropertySet->setPropertyValue(
1317 "SignatureLineSuggestedSignerName",
1318 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerName));
1319 xPropertySet->setPropertyValue(
1320 "SignatureLineSuggestedSignerTitle",
1321 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerTitle));
1322 xPropertySet->setPropertyValue(
1323 "SignatureLineSuggestedSignerEmail",
1324 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerEmail));
1325 xPropertySet->setPropertyValue(
1326 "SignatureLineSigningInstructions",
1327 uno::makeAny(getShapeModel().maSignatureLineSigningInstructions));
1328 xPropertySet->setPropertyValue(
1329 "SignatureLineShowSignDate",
1330 uno::makeAny(getShapeModel().mbSignatureLineShowSignDate));
1331 xPropertySet->setPropertyValue(
1332 "SignatureLineCanAddComment",
1333 uno::makeAny(getShapeModel().mbSignatureLineCanAddComment));
1334 xPropertySet->setPropertyValue("SignatureLineIsSigned", uno::makeAny(bIsSigned));
1336 if (!aGraphicPath.isEmpty())
1338 xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath);
1339 xPropertySet->setPropertyValue("SignatureLineUnsignedImage", uno::makeAny(xGraphic));
1341 return xShape;
1344 // try to create a picture object
1345 if( !aGraphicPath.isEmpty() )
1347 Reference<XShape> xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1348 // AS_CHARACTER shape: vertical orientation default is bottom, MSO default is top.
1349 if ( maTypeModel.maPosition != "absolute" && maTypeModel.maPosition != "relative" )
1350 PropertySet( xShape ).setAnyProperty( PROP_VertOrient, makeAny(text::VertOrientation::TOP));
1351 return xShape;
1354 // default: try to create a custom shape
1355 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
1358 GroupShape::GroupShape( Drawing& rDrawing ) :
1359 ShapeBase( rDrawing ),
1360 mxChildren( new ShapeContainer( rDrawing ) )
1364 GroupShape::~GroupShape()
1368 void GroupShape::finalizeFragmentImport()
1370 // basic shape processing
1371 ShapeBase::finalizeFragmentImport();
1372 // finalize all child shapes
1373 mxChildren->finalizeFragmentImport();
1376 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
1378 return mxChildren->getShapeTypeById( rShapeId );
1381 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
1383 return mxChildren->getShapeById( rShapeId );
1386 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1388 Reference< XShape > xGroupShape;
1389 // check that this shape contains children and a valid coordinate system
1390 ShapeParentAnchor aParentAnchor;
1391 aParentAnchor.maShapeRect = rShapeRect;
1392 aParentAnchor.maCoordSys = getCoordSystem();
1393 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
1395 xGroupShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GroupShape", rxShapes, rShapeRect );
1396 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
1397 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
1398 if( !xChildShapes->hasElements() )
1400 SAL_WARN("oox", "no child shape has been created - deleting the group shape");
1401 rxShapes->remove( xGroupShape );
1402 xGroupShape.clear();
1405 catch( Exception& )
1409 uno::Reference<beans::XPropertySet> xPropertySet;
1410 if (!maTypeModel.maEditAs.isEmpty())
1411 xPropertySet = uno::Reference<beans::XPropertySet>(xGroupShape, uno::UNO_QUERY);
1412 if (xPropertySet.is())
1414 uno::Sequence<beans::PropertyValue> aGrabBag;
1415 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1416 beans::PropertyValue aPair;
1417 aPair.Name = "mso-edit-as";
1418 aPair.Value <<= maTypeModel.maEditAs;
1419 if (aGrabBag.hasElements())
1421 sal_Int32 nLength = aGrabBag.getLength();
1422 aGrabBag.realloc(nLength + 1);
1423 aGrabBag[nLength] = aPair;
1425 else
1427 aGrabBag.realloc(1);
1428 aGrabBag[0] = aPair;
1430 xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aGrabBag));
1432 // Make sure group shapes are inline as well, unless there is an explicit different style.
1433 PropertySet aPropertySet(xGroupShape);
1434 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1435 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper);
1436 if (!maTypeModel.maRotation.isEmpty())
1437 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
1438 return xGroupShape;
1441 } // namespace vml
1442 } // namespace oox
1444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */