Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / oox / source / vml / vmlshape.cxx
blobe27700fec895afd8529a841ef02b4ba546ce902b
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/wmfexternal.hxx>
29 #include <vcl/virdev.hxx>
31 #include <com/sun/star/beans/PropertyValues.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/awt/XControlModel.hpp>
34 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
35 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
36 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
37 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
38 #include <com/sun/star/drawing/XShapes.hpp>
39 #include <com/sun/star/drawing/XControlShape.hpp>
40 #include <com/sun/star/graphic/XGraphic.hpp>
41 #include <com/sun/star/table/BorderLine2.hpp>
42 #include <com/sun/star/text/HoriOrientation.hpp>
43 #include <com/sun/star/text/RelOrientation.hpp>
44 #include <com/sun/star/text/SizeType.hpp>
45 #include <com/sun/star/text/VertOrientation.hpp>
46 #include <com/sun/star/text/WrapTextMode.hpp>
47 #include <com/sun/star/text/XTextContent.hpp>
48 #include <com/sun/star/text/XTextDocument.hpp>
49 #include <com/sun/star/text/XTextFrame.hpp>
50 #include <com/sun/star/lang/XServiceInfo.hpp>
51 #include <com/sun/star/text/TextContentAnchorType.hpp>
52 #include <com/sun/star/text/GraphicCrop.hpp>
53 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
54 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
55 #include <com/sun/star/text/WritingMode2.hpp>
56 #include <rtl/math.hxx>
57 #include <rtl/ustrbuf.hxx>
58 #include <sal/log.hxx>
59 #include <svx/svdtrans.hxx>
60 #include <oox/drawingml/shapepropertymap.hxx>
61 #include <oox/helper/graphichelper.hxx>
62 #include <oox/helper/propertyset.hxx>
63 #include <oox/ole/axcontrol.hxx>
64 #include <oox/ole/axcontrolfragment.hxx>
65 #include <oox/ole/oleobjecthelper.hxx>
66 #include <oox/token/properties.hxx>
67 #include <oox/token/tokens.hxx>
68 #include <oox/vml/vmldrawing.hxx>
69 #include <oox/vml/vmlshapecontainer.hxx>
70 #include <oox/vml/vmltextbox.hxx>
71 #include <oox/core/xmlfilterbase.hxx>
72 #include <oox/helper/containerhelper.hxx>
73 #include <svx/EnhancedCustomShapeTypeNames.hxx>
74 #include <svx/unoapi.hxx>
75 #include <svx/svdoashp.hxx>
76 #include <svx/sdtagitm.hxx>
77 #include <svx/xfillit0.hxx>
78 #include <comphelper/sequence.hxx>
79 #include <comphelper/processfactory.hxx>
80 #include <comphelper/propertyvalue.hxx>
81 #include <comphelper/storagehelper.hxx>
82 #include <vcl/svapp.hxx>
84 using ::com::sun::star::beans::XPropertySet;
85 using ::com::sun::star::uno::Any;
87 using namespace ::com::sun::star;
88 using namespace ::com::sun::star::text;
90 namespace oox {
91 namespace vml {
93 using namespace ::com::sun::star::drawing;
94 using namespace ::com::sun::star::graphic;
95 using namespace ::com::sun::star::uno;
96 using namespace ::com::sun::star::io;
98 using ::oox::core::XmlFilterBase;
100 namespace {
102 const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75;
103 const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201;
105 awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, 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::Point aAbsPoint;
110 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
111 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
112 return aAbsPoint;
115 awt::Rectangle lclGetAbsRect( const awt::Rectangle& rRelRect, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
117 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
118 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
119 awt::Rectangle aAbsRect;
120 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
121 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
122 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
123 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
124 return aAbsRect;
127 /// Count the crop value based on a crop fraction and a reference size.
128 sal_Int32 lclConvertCrop(const OUString& rCrop, sal_uInt32 nSize)
130 if (rCrop.endsWith("f"))
132 // Numeric value is specified in 1/65536-ths.
133 sal_uInt32 nCrop = rCrop.copy(0, rCrop.getLength() - 1).toUInt32();
134 return (nCrop * nSize) / 65536;
137 return 0;
140 } // namespace
142 ShapeTypeModel::ShapeTypeModel():
143 mbAutoHeight( false ),
144 mbVisible( true )
148 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
150 moShapeType.assignIfUsed( rSource.moShapeType );
151 moCoordPos.assignIfUsed( rSource.moCoordPos );
152 moCoordSize.assignIfUsed( rSource.moCoordSize );
153 /* The style properties position, left, top, width, height, margin-left,
154 margin-top are not derived from shape template to shape. */
155 maStrokeModel.assignUsed( rSource.maStrokeModel );
156 maFillModel.assignUsed( rSource.maFillModel );
157 moGraphicPath.assignIfUsed( rSource.moGraphicPath );
158 moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
161 ShapeType::ShapeType( Drawing& rDrawing ) :
162 mrDrawing( rDrawing )
166 ShapeType::~ShapeType()
170 sal_Int32 ShapeType::getShapeType() const
172 return maTypeModel.moShapeType.get( 0 );
175 OUString ShapeType::getGraphicPath() const
177 return maTypeModel.moGraphicPath.get( OUString() );
180 awt::Rectangle ShapeType::getCoordSystem() const
182 Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) );
183 Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) );
184 if( aCoordSize.first == 0 )
185 aCoordSize.first = 1;
186 if( aCoordSize.second == 0 )
187 aCoordSize.second = 1;
188 return awt::Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second );
191 awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
193 return pParentAnchor ?
194 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
195 getAbsRectangle();
198 awt::Rectangle ShapeType::getAbsRectangle() const
200 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
202 sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
203 if ( nWidth == 0 )
204 nWidth = 1;
206 sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
207 if ( nHeight == 0 )
208 nHeight = 1;
210 sal_Int32 nLeft;
211 if (o3tl::checked_add<sal_Int32>(ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maLeft, 0, true, true),
212 ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true),
213 nLeft))
215 SAL_WARN("oox", "overflow in addition");
216 nLeft = 0;
218 if (nLeft == 0 && maTypeModel.maPosition == "absolute")
219 nLeft = 1;
221 return awt::Rectangle(
222 nLeft,
223 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
224 nWidth, nHeight );
227 awt::Rectangle ShapeType::getRelRectangle() const
229 sal_Int32 nWidth = maTypeModel.maWidth.toInt32();
230 if ( nWidth == 0 )
231 nWidth = 1;
233 sal_Int32 nHeight = maTypeModel.maHeight.toInt32();
234 if ( nHeight == 0 )
235 nHeight = 1;
237 return awt::Rectangle(
238 maTypeModel.maLeft.toInt32(),
239 maTypeModel.maTop.toInt32(),
240 nWidth, nHeight );
243 ClientData::ClientData() :
244 mnObjType( XML_TOKEN_INVALID ),
245 mnTextHAlign( XML_Left ),
246 mnTextVAlign( XML_Top ),
247 mnCol( -1 ),
248 mnRow( -1 ),
249 mnChecked( VML_CLIENTDATA_UNCHECKED ),
250 mnDropStyle( XML_Combo ),
251 mnDropLines( 1 ),
252 mnVal( 0 ),
253 mnMin( 0 ),
254 mnMax( 0 ),
255 mnInc( 0 ),
256 mnPage( 0 ),
257 mnSelType( XML_Single ),
258 mnVTEdit( VML_CLIENTDATA_TEXT ),
259 mbPrintObject( true ),
260 mbVisible( false ),
261 mbDde( false ),
262 mbNo3D( false ),
263 mbNo3D2( false ),
264 mbMultiLine( false ),
265 mbVScroll( false ),
266 mbSecretEdit( false )
270 ShapeModel::ShapeModel()
271 : mbIsSignatureLine(false)
272 , mbSignatureLineShowSignDate(true)
273 , mbSignatureLineCanAddComment(false)
277 ShapeModel::~ShapeModel()
281 TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
283 mxTextBox.reset( new TextBox(rModel) );
284 return *mxTextBox;
287 ClientData& ShapeModel::createClientData()
289 mxClientData.reset( new ClientData );
290 return *mxClientData;
293 ShapeBase::ShapeBase( Drawing& rDrawing ) :
294 ShapeType( rDrawing )
298 void ShapeBase::finalizeFragmentImport()
300 if( maShapeModel.maType.getLength() > 1 )
302 OUString aType = maShapeModel.maType;
303 if (aType[ 0 ] == '#')
304 aType = aType.copy(1);
305 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( aType ) )
306 maTypeModel.assignUsed( pShapeType->getTypeModel() );
307 else {
308 // Temporary fix, shapetype not found if referenced from different substream
309 // FIXME: extend scope of ShapeContainer to store all shapetypes from the document
310 const OUString sShapeTypePrefix = "shapetype_";
311 if (aType.startsWith(sShapeTypePrefix)) {
312 maTypeModel.moShapeType = aType.copy(sShapeTypePrefix.getLength()).toInt32();
318 OUString ShapeBase::getShapeName() const
320 if( !maTypeModel.maShapeName.isEmpty() )
321 return maTypeModel.maShapeName;
323 OUString aBaseName = mrDrawing.getShapeBaseName( *this );
324 if( !aBaseName.isEmpty() )
326 sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
327 if( nShapeIdx > 0 )
328 return aBaseName + OUStringChar(' ') + OUString::number( nShapeIdx );
331 return OUString();
334 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
336 return nullptr;
339 const ShapeBase* ShapeBase::getChildById( const OUString& ) const
341 return nullptr;
344 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
346 Reference< XShape > xShape;
347 if( mrDrawing.isShapeSupported( *this ) )
349 /* Calculate shape rectangle. Applications may do something special
350 according to some imported shape client data (e.g. Excel cell anchor). */
351 awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
353 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
355 xShape = implConvertAndInsert( rxShapes, aShapeRect );
356 if( xShape.is() )
358 // set imported or generated shape name (not supported by form controls)
359 PropertySet aShapeProp( xShape );
360 if( aShapeProp.hasProperty( PROP_Name ) )
361 aShapeProp.setProperty( PROP_Name, getShapeName() );
362 uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
364 OUString sLinkChainName = getTypeModel().maLegacyId;
365 sal_Int32 id = 0;
366 sal_Int32 idPos = sLinkChainName.indexOf("_x");
367 sal_Int32 seq = 0;
368 if (idPos >= 0)
370 sal_Int32 seqPos = sLinkChainName.indexOf("_s",idPos);
371 if (idPos < seqPos)
373 auto idPosEnd = idPos+2;
374 id = sLinkChainName.copy(idPosEnd, seqPos - idPosEnd).toInt32();
375 seq = sLinkChainName.copy(seqPos+2).toInt32();
379 OUString s_mso_next_textbox;
380 if( getTextBox() )
381 s_mso_next_textbox = getTextBox()->msNextTextbox;
382 if( s_mso_next_textbox.startsWith("#") )
383 s_mso_next_textbox = s_mso_next_textbox.copy(1);
385 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
387 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
388 uno::Any aAny = propertySet->getPropertyValue("FrameInteropGrabBag");
389 auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >());
391 aGrabBag.push_back(comphelper::makePropertyValue("VML-Z-ORDER", maTypeModel.maZIndex.toInt32()));
393 if( !s_mso_next_textbox.isEmpty() )
394 aGrabBag.push_back(comphelper::makePropertyValue("mso-next-textbox", s_mso_next_textbox));
396 if( !sLinkChainName.isEmpty() )
398 aGrabBag.push_back(comphelper::makePropertyValue("TxbxHasLink", true));
399 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Id", id));
400 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Seq", seq));
401 aGrabBag.push_back(comphelper::makePropertyValue("LinkChainName", sLinkChainName));
404 if(!maTypeModel.maRotation.isEmpty())
405 aGrabBag.push_back(comphelper::makePropertyValue("mso-rotation-angle", ConversionHelper::decodeRotation(maTypeModel.maRotation)));
406 propertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(comphelper::containerToSequence(aGrabBag)));
407 sal_Int32 backColorTransparency = 0;
408 propertySet->getPropertyValue("BackColorTransparency")
409 >>= backColorTransparency;
410 if (propertySet->getPropertyValue("FillStyle") == FillStyle_NONE &&
411 backColorTransparency == 100)
413 // If there is no fill, the Word default is 100% transparency.
414 propertySet->setPropertyValue("FillTransparence", makeAny(sal_Int16(100)));
417 else
419 if( maTypeModel.maZIndex.toInt32() )
421 uno::Sequence<beans::PropertyValue> aGrabBag;
422 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
423 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
424 sal_Int32 length;
426 length = aGrabBag.getLength();
427 aGrabBag.realloc( length+1 );
428 aGrabBag[length].Name = "VML-Z-ORDER";
429 aGrabBag[length].Value <<= maTypeModel.maZIndex.toInt32();
431 if( !s_mso_next_textbox.isEmpty() )
433 length = aGrabBag.getLength();
434 aGrabBag.realloc( length+1 );
435 aGrabBag[length].Name = "mso-next-textbox";
436 aGrabBag[length].Value <<= s_mso_next_textbox;
439 if( !sLinkChainName.isEmpty() )
441 length = aGrabBag.getLength();
442 aGrabBag.realloc( length+4 );
443 aGrabBag[length].Name = "TxbxHasLink";
444 aGrabBag[length].Value <<= true;
445 aGrabBag[length+1].Name = "Txbx-Id";
446 aGrabBag[length+1].Value <<= id;
447 aGrabBag[length+2].Name = "Txbx-Seq";
448 aGrabBag[length+2].Value <<= seq;
449 aGrabBag[length+3].Name = "LinkChainName";
450 aGrabBag[length+3].Value <<= sLinkChainName;
452 propertySet->setPropertyValue( "InteropGrabBag", uno::makeAny(aGrabBag) );
455 Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
456 if ( xControlShape.is() && !getTypeModel().mbVisible )
458 PropertySet aControlShapeProp( xControlShape->getControl() );
459 aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( false ) );
461 /* Notify the drawing that a new shape has been inserted. For
462 convenience, pass the rectangle that contains position and
463 size of the shape. */
464 bool bGroupChild = pParentAnchor != nullptr;
465 mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
468 else
469 SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
471 return xShape;
474 void ShapeBase::convertFormatting( const Reference< XShape >& rxShape ) const
476 if( rxShape.is() )
478 /* Calculate shape rectangle. Applications may do something special
479 according to some imported shape client data (e.g. Excel cell anchor). */
480 awt::Rectangle aShapeRect = calcShapeRectangle( nullptr );
482 // convert the shape, if the calculated rectangle is not empty
483 if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
485 rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
486 rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
487 convertShapeProperties( rxShape );
492 // protected ------------------------------------------------------------------
494 awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
496 /* Calculate shape rectangle. Applications may do something special
497 according to some imported shape client data (e.g. Excel cell anchor). */
498 awt::Rectangle aShapeRect;
499 const ClientData* pClientData = getClientData();
500 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
501 aShapeRect = getRectangle( pParentAnchor );
502 return aShapeRect;
505 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
507 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
508 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
509 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
510 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
512 uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
513 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
515 // Any other service supporting the ShadowFormat property?
516 maTypeModel.maShadowModel.pushToPropMap(aPropMap, rGraphicHelper);
517 // TextFrames have BackColor, not FillColor
518 if (aPropMap.hasProperty(PROP_FillColor))
520 aPropMap.setAnyProperty(PROP_BackColor, aPropMap.getProperty(PROP_FillColor));
521 aPropMap.erase(PROP_FillColor);
523 // TextFrames have BackColorTransparency, not FillTransparence
524 if (aPropMap.hasProperty(PROP_FillTransparence))
526 aPropMap.setAnyProperty(PROP_BackColorTransparency, aPropMap.getProperty(PROP_FillTransparence));
527 aPropMap.erase(PROP_FillTransparence);
529 // And no LineColor property; individual borders can have colors and widths
530 boost::optional<sal_Int32> oLineWidth;
531 if (maTypeModel.maStrokeModel.moWeight.has())
532 oLineWidth = ConversionHelper::decodeMeasureToHmm(
533 rGraphicHelper, maTypeModel.maStrokeModel.moWeight.get(), 0, false, false);
534 if (aPropMap.hasProperty(PROP_LineColor))
536 uno::Reference<beans::XPropertySet> xPropertySet(rxShape, uno::UNO_QUERY);
537 static const sal_Int32 aBorders[] = {
538 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
540 for (sal_Int32 nBorder : aBorders)
542 table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<table::BorderLine2>();
543 aBorderLine.Color = aPropMap.getProperty(PROP_LineColor).get<sal_Int32>();
544 if (oLineWidth)
545 aBorderLine.LineWidth = *oLineWidth;
546 aPropMap.setProperty(nBorder, aBorderLine);
548 aPropMap.erase(PROP_LineColor);
551 else if (xSInfo->supportsService("com.sun.star.drawing.CustomShape"))
552 maTypeModel.maTextpathModel.pushToPropMap(aPropMap, rxShape, rGraphicHelper);
554 PropertySet( rxShape ).setProperties( aPropMap );
557 SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) :
558 ShapeBase( rDrawing ),
559 maService( rService )
563 static void lcl_setSurround(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
565 OUString aWrapType = rTypeModel.moWrapType.get();
567 // 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.
568 sal_Int32 nMarginTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, rTypeModel.maMarginTop, 0, false, true);
569 if (nMarginTop < -35277) // Less than 1000 points.
570 aWrapType.clear();
572 css::text::WrapTextMode nSurround = css::text::WrapTextMode_THROUGH;
573 if ( aWrapType == "square" || aWrapType == "tight" ||
574 aWrapType == "through" )
576 nSurround = css::text::WrapTextMode_PARALLEL;
577 if ( rTypeModel.moWrapSide.get() == "left" )
578 nSurround = css::text::WrapTextMode_LEFT;
579 else if ( rTypeModel.moWrapSide.get() == "right" )
580 nSurround = css::text::WrapTextMode_RIGHT;
582 else if ( aWrapType == "topAndBottom" )
583 nSurround = css::text::WrapTextMode_NONE;
585 rPropSet.setProperty(PROP_Surround, static_cast<sal_Int32>(nSurround));
588 static void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
590 if ( rTypeModel.maPosition == "absolute" )
592 // Word supports as-character (inline) and at-character only, absolute can't be inline.
593 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
594 // anchor is set after insertion, so reset to NONE
595 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
597 if ( rTypeModel.maPositionVerticalRelative == "page" )
599 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
601 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
603 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
605 else
607 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
610 else if( rTypeModel.maPosition == "relative" )
611 { // I'm not very sure this is correct either.
612 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
613 // anchor is set after insertion, so reset to NONE
614 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
616 else // static (is the default) means anchored inline
618 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
619 // Use top orientation, this one seems similar to what MSO uses as inline
620 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
623 if ( rTypeModel.maPositionHorizontal == "center" )
624 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::CENTER));
625 else if ( rTypeModel.maPositionHorizontal == "left" )
626 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
627 else if ( rTypeModel.maPositionHorizontal == "right" )
628 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
629 else if ( rTypeModel.maPositionHorizontal == "inside" )
631 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
632 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
634 else if ( rTypeModel.maPositionHorizontal == "outside" )
636 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
637 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
640 if ( rTypeModel.maPositionHorizontalRelative == "page" )
641 rPropSet.setAnyProperty(PROP_HoriOrientRelation, makeAny(text::RelOrientation::PAGE_FRAME));
642 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
643 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
644 else if ( rTypeModel.maPositionVerticalRelative == "text" )
645 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
647 if ( rTypeModel.maPositionVertical == "center" )
648 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::CENTER));
649 else if ( rTypeModel.maPositionVertical == "top" )
650 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
651 else if ( rTypeModel.maPositionVertical == "bottom" )
652 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::BOTTOM));
653 else if ( rTypeModel.maPositionVertical == "inside" )
654 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_TOP));
655 else if ( rTypeModel.maPositionVertical == "outside" )
656 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_BOTTOM));
658 lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper );
661 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
663 awt::Rectangle aShapeRect(rShapeRect);
664 boost::optional<sal_Int32> oRotation;
665 bool bFlipX = false, bFlipY = false;
666 if (!maTypeModel.maRotation.isEmpty())
667 oRotation = ConversionHelper::decodeRotation(maTypeModel.maRotation);
668 if (!maTypeModel.maFlip.isEmpty())
670 if (maTypeModel.maFlip == "x")
672 bFlipX = true;
674 else if (maTypeModel.maFlip == "y")
676 bFlipY = true;
680 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
681 SdrObject* pShape = GetSdrObjectFromXShape( xShape );
682 if( pShape && getShapeType() >= 0 )
684 OUString aShapeType = EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT >(getShapeType()) );
685 //The resize autoshape to fit text attr of FontWork/Word-Art should always be false
686 //for the fallback geometry.
687 if(aShapeType.startsWith("fontwork"))
689 pShape->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
690 pShape->SetMergedItem(makeSdrTextAutoGrowWidthItem(false));
693 convertShapeProperties( xShape );
695 // Handle left/right/top/bottom wrap distance.
696 // Default value of mso-wrap-distance-left/right is supposed to be 0 (see
697 // 19.1.2.19 of the VML spec), but Word implements a non-zero value.
698 // [MS-ODRAW] says the below default value in 2.3.4.9.
699 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
700 OUString aWrapDistanceLeft = OUString::number(0x0001BE7C);
701 if (!maTypeModel.maWrapDistanceLeft.isEmpty())
702 aWrapDistanceLeft = maTypeModel.maWrapDistanceLeft;
703 sal_Int32 nWrapDistanceLeft = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceLeft, 0, true, false);
704 PropertySet(xShape).setAnyProperty(PROP_LeftMargin, uno::makeAny(nWrapDistanceLeft));
705 OUString aWrapDistanceRight = OUString::number(0x0001BE7C);
706 if (!maTypeModel.maWrapDistanceRight.isEmpty())
707 aWrapDistanceRight = maTypeModel.maWrapDistanceRight;
708 sal_Int32 nWrapDistanceRight = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceRight, 0, true, false);
709 PropertySet(xShape).setAnyProperty(PROP_RightMargin, uno::makeAny(nWrapDistanceRight));
710 sal_Int32 nWrapDistanceTop = 0;
711 if (!maTypeModel.maWrapDistanceTop.isEmpty())
712 nWrapDistanceTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceTop, 0, false, true);
713 PropertySet(xShape).setAnyProperty(PROP_TopMargin, uno::makeAny(nWrapDistanceTop));
714 sal_Int32 nWrapDistanceBottom = 0;
715 if (!maTypeModel.maWrapDistanceBottom.isEmpty())
716 nWrapDistanceBottom = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceBottom, 0, false, true);
717 PropertySet(xShape).setAnyProperty(PROP_BottomMargin, uno::makeAny(nWrapDistanceBottom));
719 if ( maService == "com.sun.star.text.TextFrame" )
721 PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, makeAny( maTypeModel.mbAutoHeight ) );
722 PropertySet( xShape ).setAnyProperty( PROP_SizeType, makeAny( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
723 if( getTextBox()->borderDistanceSet )
725 PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceLeft )));
726 PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceTop )));
727 PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceRight )));
728 PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceBottom )));
731 if (getTextBox()->maLayoutFlow == "vertical")
733 sal_Int16 nWritingMode = text::WritingMode2::TB_RL;
734 if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
736 nWritingMode = text::WritingMode2::BT_LR;
738 PropertySet(xShape).setAnyProperty(PROP_WritingMode, uno::makeAny(nWritingMode));
741 else
743 // FIXME Setting the relative width/height only for everything but text frames as
744 // TextFrames already have relative width/height feature... but currently not working
745 // in the way we need.
747 // Set the relative width / height if any
748 if ( !maTypeModel.maWidthPercent.isEmpty( ) )
750 // Only page-relative width is supported ATM
751 if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
753 sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
754 // Only apply if nWidth != 0
755 if ( nWidth )
756 PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, makeAny( nWidth ) );
759 if ( !maTypeModel.maHeightPercent.isEmpty( ) )
761 // Only page-relative height is supported ATM
762 if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
764 sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
765 // Only apply if nHeight != 0
766 if ( nHeight )
767 PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
771 // drawinglayer default is center, MSO default is top.
772 drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP;
773 if (maTypeModel.maVTextAnchor == "middle")
774 eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER;
775 else if (maTypeModel.maVTextAnchor == "bottom")
776 eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
777 PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, makeAny(eTextVerticalAdjust));
779 if (getTextBox())
781 getTextBox()->convert(xShape);
782 if (getTextBox()->borderDistanceSet)
784 awt::Size aSize = xShape->getSize();
785 PropertySet(xShape).setAnyProperty(PROP_TextLeftDistance, makeAny(sal_Int32(getTextBox()->borderDistanceLeft)));
786 PropertySet(xShape).setAnyProperty(PROP_TextUpperDistance, makeAny(sal_Int32(getTextBox()->borderDistanceTop)));
787 PropertySet(xShape).setAnyProperty(PROP_TextRightDistance, makeAny(sal_Int32(getTextBox()->borderDistanceRight)));
788 PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, makeAny(sal_Int32(getTextBox()->borderDistanceBottom)));
789 xShape->setSize(aSize);
794 // Import Legacy Fragments (if any)
795 if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
797 Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
798 if( xInStrm.is() )
799 PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
802 PropertySet aPropertySet(xShape);
803 if (xShape.is())
805 if (oRotation)
807 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(*oRotation));
808 uno::Reference<lang::XServiceInfo> xServiceInfo(rxShapes, uno::UNO_QUERY);
809 if (!xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
811 // If rotation is used, simple setPosition() is not enough.
812 aPropertySet.setAnyProperty(PROP_HoriOrientPosition, makeAny(aShapeRect.X));
813 aPropertySet.setAnyProperty(PROP_VertOrientPosition, makeAny(aShapeRect.Y));
817 // custom shape geometry attributes
818 std::vector<css::beans::PropertyValue> aPropVec;
820 // When flip has 'x' or 'y', the associated ShapeRect will be changed but direction change doesn't occur.
821 // It might occur internally in SdrObject of "sw" module, not here.
822 // The associated properties "PROP_MirroredX" and "PROP_MirroredY" have to be set here so that direction change will occur internally.
823 if (bFlipX || bFlipY)
825 assert(!(bFlipX && bFlipY));
826 css::beans::PropertyValue aProp;
827 if (bFlipX)
828 aProp.Name = "MirroredX";
829 else
830 aProp.Name = "MirroredY";
831 aProp.Value <<= true;
832 aPropVec.push_back(aProp);
835 if (!maTypeModel.maAdjustments.isEmpty())
837 std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
838 sal_Int32 nIndex = 0;
841 OUString aToken = maTypeModel.maAdjustments.getToken(0, ',', nIndex);
842 drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue;
843 if (aToken.isEmpty())
844 aAdjustmentValue.State = css::beans::PropertyState::PropertyState_DEFAULT_VALUE;
845 else
846 aAdjustmentValue.Value <<= aToken.toInt32();
847 aAdjustmentValues.push_back(aAdjustmentValue);
848 } while (nIndex >= 0);
850 css::beans::PropertyValue aProp;
851 aProp.Name = "AdjustmentValues";
852 aProp.Value <<= comphelper::containerToSequence(aAdjustmentValues);
853 aPropVec.push_back(aProp);
856 if (!aPropVec.empty())
857 aPropertySet.setAnyProperty(PROP_CustomShapeGeometry, makeAny(comphelper::containerToSequence(aPropVec)));
860 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper );
862 return xShape;
865 Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
867 Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath);
868 return SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
871 Reference< XShape > SimpleShape::createPictureObject(const Reference< XShapes >& rxShapes,
872 const awt::Rectangle& rShapeRect,
873 uno::Reference<graphic::XGraphic> const & rxGraphic) const
875 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
876 if( xShape.is() )
878 PropertySet aPropSet(xShape);
879 if (rxGraphic.is())
881 aPropSet.setProperty(PROP_Graphic, rxGraphic);
883 uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
884 // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
885 if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
887 aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
888 aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
889 aPropSet.setProperty(PROP_Opaque, false);
891 // fdo#70457: preserve rotation information
892 if ( !maTypeModel.maRotation.isEmpty() )
893 aPropSet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
895 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
896 lcl_SetAnchorType(aPropSet, maTypeModel, rGraphicHelper);
898 if (maTypeModel.moCropBottom.has() || maTypeModel.moCropLeft.has() || maTypeModel.moCropRight.has() || maTypeModel.moCropTop.has())
900 text::GraphicCrop aGraphicCrop;
901 awt::Size aOriginalSize = rGraphicHelper.getOriginalSize(rxGraphic);
903 if (maTypeModel.moCropBottom.has())
904 aGraphicCrop.Bottom = lclConvertCrop(maTypeModel.moCropBottom.get(), aOriginalSize.Height);
905 if (maTypeModel.moCropLeft.has())
906 aGraphicCrop.Left = lclConvertCrop(maTypeModel.moCropLeft.get(), aOriginalSize.Width);
907 if (maTypeModel.moCropRight.has())
908 aGraphicCrop.Right = lclConvertCrop(maTypeModel.moCropRight.get(), aOriginalSize.Width);
909 if (maTypeModel.moCropTop.has())
910 aGraphicCrop.Top = lclConvertCrop(maTypeModel.moCropTop.get(), aOriginalSize.Height);
912 aPropSet.setProperty(PROP_GraphicCrop, aGraphicCrop);
915 return xShape;
918 RectangleShape::RectangleShape( Drawing& rDrawing ) :
919 SimpleShape( rDrawing, "com.sun.star.drawing.RectangleShape" )
923 Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
925 OUString aGraphicPath = getGraphicPath();
927 // try to create a picture object
928 if(!aGraphicPath.isEmpty())
929 return SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
931 // default: try to create a rectangle shape
932 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
933 OUString sArcsize = maTypeModel.maArcsize;
934 if ( !sArcsize.isEmpty( ) )
936 sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
937 sal_Int32 nValue = sArcsize.copy( 0, sArcsize.getLength() - 1 ).toInt32( );
938 // Get the smallest half-side
939 double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
940 sal_Int32 nRadius = 0;
941 if ( cLastChar == 'f' )
942 nRadius = size * nValue / 65536;
943 else if ( cLastChar == '%' )
944 nRadius = size * nValue / 100;
945 PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, makeAny( nRadius ) );
947 return xShape;
950 EllipseShape::EllipseShape( Drawing& rDrawing ) :
951 SimpleShape( rDrawing, "com.sun.star.drawing.EllipseShape" )
955 PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
956 SimpleShape( rDrawing, "com.sun.star.drawing.PolyLineShape" )
960 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
962 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
963 // polygon path
964 awt::Rectangle aCoordSys = getCoordSystem();
965 if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
967 ::std::vector< awt::Point > aAbsPoints;
968 for (auto const& point : maShapeModel.maPoints)
969 aAbsPoints.push_back( lclGetAbsPoint( point, rShapeRect, aCoordSys ) );
970 PointSequenceSequence aPointSeq( 1 );
971 aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
972 PropertySet aPropSet( xShape );
973 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
975 return xShape;
978 LineShape::LineShape(Drawing& rDrawing)
979 : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
983 awt::Rectangle LineShape::getAbsRectangle() const
985 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
986 awt::Rectangle aShapeRect;
987 sal_Int32 nIndex = 0;
989 aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, true, true);
990 aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, false, true);
991 nIndex = 0;
992 aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, true, true) - aShapeRect.X;
993 aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, false, true) - aShapeRect.Y;
994 return aShapeRect;
997 awt::Rectangle LineShape::getRelRectangle() const
999 awt::Rectangle aShapeRect;
1000 sal_Int32 nIndex = 0;
1002 aShapeRect.X = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1003 aShapeRect.Y = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1004 nIndex = 0;
1005 aShapeRect.Width = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.X;
1006 aShapeRect.Height = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.Y;
1007 return aShapeRect;
1010 BezierShape::BezierShape(Drawing& rDrawing)
1011 : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
1015 Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1017 // If we have an 'x' in the last part of the path it means it is closed...
1018 sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(',');
1019 if ( nPos != -1 && maShapeModel.maVmlPath.indexOf('x', nPos) != -1 )
1021 const_cast<BezierShape*>( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1024 awt::Rectangle aCoordSys = getCoordSystem();
1025 PolyPolygonBezierCoords aBezierCoords;
1027 if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
1029 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1031 // Bezier paths may consist of one or more sub-paths
1032 typedef ::std::vector< ::std::vector< awt::Point > > SubPathList;
1033 typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
1034 SubPathList aCoordLists;
1035 FlagsList aFlagLists;
1036 sal_Int32 nIndex = 0;
1038 // Curve defined by to, from, control1 and control2 attributes
1039 if ( maShapeModel.maVmlPath.isEmpty() )
1041 aCoordLists.emplace_back( );
1042 aFlagLists.emplace_back( );
1044 // Start point
1045 aCoordLists[ 0 ].emplace_back(
1046 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ),
1047 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) );
1048 // Control point 1
1049 aCoordLists[ 0 ].emplace_back(
1050 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ),
1051 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) );
1052 // Control point 2
1053 aCoordLists[ 0 ].emplace_back(
1054 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ),
1055 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) );
1056 // End point
1057 aCoordLists[ 0 ].emplace_back(
1058 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ),
1059 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) );
1061 // First and last points are normals, points 2 and 4 are controls
1062 aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
1063 aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
1064 aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
1066 // Curve defined by path attribute
1067 else
1069 // Parse VML path string and convert to absolute coordinates
1070 ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
1072 for (auto & coordList : aCoordLists)
1073 for (auto & point : coordList)
1075 point = lclGetAbsPoint( point, rShapeRect, aCoordSys );
1079 aBezierCoords.Coordinates.realloc( aCoordLists.size() );
1080 for ( size_t i = 0; i < aCoordLists.size(); i++ )
1081 aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] );
1083 aBezierCoords.Flags.realloc( aFlagLists.size() );
1084 for ( size_t i = 0; i < aFlagLists.size(); i++ )
1085 aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] );
1087 if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
1088 && aCoordLists.front().front().X == aCoordLists.back().back().X
1089 && aCoordLists.front().front().Y == aCoordLists.back().back().Y )
1090 { // HACK: If the shape is in fact closed, which can be found out only when the path is known,
1091 // force to closed bezier shape (otherwise e.g. fill won't work).
1092 const_cast< BezierShape* >( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1096 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1098 if( aBezierCoords.Coordinates.hasElements())
1100 PropertySet aPropSet( xShape );
1101 aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
1104 // Handle horizontal and vertical flip.
1105 if (!maTypeModel.maFlip.isEmpty())
1107 if (SdrObject* pShape = GetSdrObjectFromXShape(xShape))
1109 if (maTypeModel.maFlip.startsWith("x"))
1111 Point aCenter(pShape->GetSnapRect().Center());
1112 Point aPoint2(aCenter);
1113 aPoint2.setY(aPoint2.getY() + 1);
1114 pShape->NbcMirror(aCenter, aPoint2);
1116 if (maTypeModel.maFlip.endsWith("y"))
1118 Point aCenter(pShape->GetSnapRect().Center());
1119 Point aPoint2(aCenter);
1120 aPoint2.setX(aPoint2.getX() + 1);
1121 pShape->NbcMirror(aCenter, aPoint2);
1126 // Hacky way of ensuring the shape is correctly sized/positioned
1129 // E.g. SwXFrame::setPosition() unconditionally throws
1130 xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
1131 xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
1133 catch (const ::css::uno::Exception&)
1135 // TODO: try some other way to ensure size/position
1137 return xShape;
1140 CustomShape::CustomShape( Drawing& rDrawing ) :
1141 SimpleShape( rDrawing, "com.sun.star.drawing.CustomShape" )
1145 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1147 // try to create a custom shape
1148 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1149 if( xShape.is() ) try
1151 // create the custom shape geometry
1152 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
1153 xDefaulter->createCustomShapeDefaults( OUString::number( getShapeType() ) );
1154 // convert common properties
1155 convertShapeProperties( xShape );
1157 catch( Exception& )
1160 return xShape;
1163 ComplexShape::ComplexShape( Drawing& rDrawing ) :
1164 CustomShape( rDrawing )
1168 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1170 XmlFilterBase& rFilter = mrDrawing.getFilter();
1171 sal_Int32 nShapeType = getShapeType();
1172 OUString aGraphicPath = getGraphicPath();
1174 // try to find registered OLE object info
1175 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
1177 SAL_WARN_IF(
1178 nShapeType != VML_SHAPETYPE_PICTUREFRAME, "oox",
1179 "ComplexShape::implConvertAndInsert - unexpected shape type");
1181 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
1182 if( pOleObjectInfo->mbDmlShape )
1183 return Reference< XShape >();
1185 PropertyMap aOleProps;
1186 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1187 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
1189 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.OLE2Shape", rxShapes, rShapeRect );
1190 if( xShape.is() )
1192 // set the replacement graphic
1193 if( !aGraphicPath.isEmpty() )
1195 WmfExternal aExtHeader;
1196 aExtHeader.mapMode = 8;
1197 aExtHeader.xExt = rShapeRect.Width;
1198 aExtHeader.yExt = rShapeRect.Height;
1200 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath, &aExtHeader);
1201 if (xGraphic.is())
1202 aOleProps.setProperty( PROP_Graphic, xGraphic);
1205 PropertySet aPropSet( xShape );
1206 aPropSet.setProperties( aOleProps );
1208 return xShape;
1213 // try to find registered form control info
1214 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
1215 if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
1217 if( !pControlInfo->maName.isEmpty() )
1219 // load the control properties from fragment
1220 ::oox::ole::EmbeddedControl aControl(pControlInfo->maName);
1221 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
1223 // create and return the control shape (including control model)
1224 sal_Int32 nCtrlIndex = -1;
1225 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
1227 if (pControlInfo->mbTextContentShape)
1229 PropertySet aPropertySet(xShape);
1230 lcl_SetAnchorType(aPropertySet, maTypeModel, mrDrawing.getFilter().getGraphicHelper());
1232 // on error, proceed and try to create picture from replacement image
1233 if( xShape.is() )
1234 return xShape;
1239 // host application wants to create the shape (do not try failed OLE controls again)
1240 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
1242 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
1243 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
1244 if( xShape.is() )
1245 return xShape;
1249 if( getShapeModel().mbIsSignatureLine )
1251 uno::Reference<graphic::XGraphic> xGraphic;
1252 bool bIsSigned(false);
1255 // Get the document signatures
1256 Reference<security::XDocumentDigitalSignatures> xSignatures(
1257 security::DocumentDigitalSignatures::createWithVersion(
1258 comphelper::getProcessComponentContext(), "1.2"));
1260 uno::Reference<embed::XStorage> xStorage
1261 = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
1262 ZIP_STORAGE_FORMAT_STRING, mrDrawing.getFilter().getFileUrl(),
1263 embed::ElementModes::READ);
1264 SAL_WARN_IF(!xStorage.is(), "oox.vml", "No xStorage!");
1266 const uno::Sequence<security::DocumentSignatureInformation> xSignatureInfo
1267 = xSignatures->verifyScriptingContentSignatures(xStorage,
1268 uno::Reference<io::XInputStream>());
1270 // Try to find matching signature line image - if none exists that is fine,
1271 // then the signature line is not digitally signed.
1272 auto pSignInfo = std::find_if(xSignatureInfo.begin(), xSignatureInfo.end(),
1273 [this](const security::DocumentSignatureInformation& rSigInfo) {
1274 return rSigInfo.SignatureLineId == getShapeModel().maSignatureId; });
1275 if (pSignInfo != xSignatureInfo.end())
1277 bIsSigned = true;
1278 if (pSignInfo->SignatureIsValid)
1280 // Signature is valid, use the 'valid' image
1281 SAL_WARN_IF(!pSignInfo->ValidSignatureLineImage.is(), "oox.vml",
1282 "No ValidSignatureLineImage!");
1283 xGraphic = pSignInfo->ValidSignatureLineImage;
1285 else
1287 // Signature is invalid, use the 'invalid' image
1288 SAL_WARN_IF(!pSignInfo->InvalidSignatureLineImage.is(), "oox.vml",
1289 "No InvalidSignatureLineImage!");
1290 xGraphic = pSignInfo->InvalidSignatureLineImage;
1294 catch (css::uno::Exception&)
1296 // DocumentDigitalSignatures service not available.
1297 // We continue by rendering the "unsigned" shape instead.
1300 Reference< XShape > xShape;
1301 if (xGraphic.is())
1303 // If available, use the signed image from the signature
1304 xShape = SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
1306 else
1308 // Create shape with the fallback "unsigned" image
1309 xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1312 // Store signature line properties
1313 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1314 xPropertySet->setPropertyValue("IsSignatureLine", uno::makeAny(true));
1315 xPropertySet->setPropertyValue("SignatureLineId",
1316 uno::makeAny(getShapeModel().maSignatureId));
1317 xPropertySet->setPropertyValue(
1318 "SignatureLineSuggestedSignerName",
1319 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerName));
1320 xPropertySet->setPropertyValue(
1321 "SignatureLineSuggestedSignerTitle",
1322 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerTitle));
1323 xPropertySet->setPropertyValue(
1324 "SignatureLineSuggestedSignerEmail",
1325 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerEmail));
1326 xPropertySet->setPropertyValue(
1327 "SignatureLineSigningInstructions",
1328 uno::makeAny(getShapeModel().maSignatureLineSigningInstructions));
1329 xPropertySet->setPropertyValue(
1330 "SignatureLineShowSignDate",
1331 uno::makeAny(getShapeModel().mbSignatureLineShowSignDate));
1332 xPropertySet->setPropertyValue(
1333 "SignatureLineCanAddComment",
1334 uno::makeAny(getShapeModel().mbSignatureLineCanAddComment));
1335 xPropertySet->setPropertyValue("SignatureLineIsSigned", uno::makeAny(bIsSigned));
1337 if (!aGraphicPath.isEmpty())
1339 xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath);
1340 xPropertySet->setPropertyValue("SignatureLineUnsignedImage", uno::makeAny(xGraphic));
1342 return xShape;
1345 // try to create a picture object
1346 if( !aGraphicPath.isEmpty() )
1348 Reference<XShape> xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1349 // AS_CHARACTER shape: vertical orientation default is bottom, MSO default is top.
1350 if ( maTypeModel.maPosition != "absolute" && maTypeModel.maPosition != "relative" )
1351 PropertySet( xShape ).setAnyProperty( PROP_VertOrient, makeAny(text::VertOrientation::TOP));
1352 return xShape;
1355 // default: try to create a custom shape
1356 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
1359 GroupShape::GroupShape( Drawing& rDrawing ) :
1360 ShapeBase( rDrawing ),
1361 mxChildren( new ShapeContainer( rDrawing ) )
1365 GroupShape::~GroupShape()
1369 void GroupShape::finalizeFragmentImport()
1371 // basic shape processing
1372 ShapeBase::finalizeFragmentImport();
1373 // finalize all child shapes
1374 mxChildren->finalizeFragmentImport();
1377 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
1379 return mxChildren->getShapeTypeById( rShapeId );
1382 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
1384 return mxChildren->getShapeById( rShapeId );
1387 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1389 Reference< XShape > xGroupShape;
1390 // check that this shape contains children and a valid coordinate system
1391 ShapeParentAnchor aParentAnchor;
1392 aParentAnchor.maShapeRect = rShapeRect;
1393 aParentAnchor.maCoordSys = getCoordSystem();
1394 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
1396 xGroupShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GroupShape", rxShapes, rShapeRect );
1397 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
1398 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
1399 if( !xChildShapes->hasElements() )
1401 SAL_WARN("oox", "no child shape has been created - deleting the group shape");
1402 rxShapes->remove( xGroupShape );
1403 xGroupShape.clear();
1406 catch( Exception& )
1410 uno::Reference<beans::XPropertySet> xPropertySet;
1411 if (!maTypeModel.maEditAs.isEmpty())
1412 xPropertySet = uno::Reference<beans::XPropertySet>(xGroupShape, uno::UNO_QUERY);
1413 if (xPropertySet.is())
1415 uno::Sequence<beans::PropertyValue> aGrabBag;
1416 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1417 beans::PropertyValue aPair;
1418 aPair.Name = "mso-edit-as";
1419 aPair.Value <<= maTypeModel.maEditAs;
1420 sal_Int32 nLength = aGrabBag.getLength();
1421 aGrabBag.realloc(nLength + 1);
1422 aGrabBag[nLength] = aPair;
1423 xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aGrabBag));
1425 // Make sure group shapes are inline as well, unless there is an explicit different style.
1426 PropertySet aPropertySet(xGroupShape);
1427 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1428 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper);
1429 if (!maTypeModel.maRotation.isEmpty())
1430 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
1431 return xGroupShape;
1434 } // namespace vml
1435 } // namespace oox
1437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */