bump product version to 6.3.0.0.beta1
[LibreOffice.git] / oox / source / vml / vmlshape.cxx
blobc12b8b9025c50587ff74da69e9e6376639365aba
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 <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 <svx/sdtagitm.hxx>
76 #include <comphelper/sequence.hxx>
77 #include <comphelper/processfactory.hxx>
78 #include <comphelper/propertyvalue.hxx>
79 #include <comphelper/storagehelper.hxx>
80 #include <vcl/svapp.hxx>
82 using ::com::sun::star::beans::XPropertySet;
83 using ::com::sun::star::uno::Any;
85 using namespace ::com::sun::star;
86 using namespace ::com::sun::star::text;
88 namespace oox {
89 namespace vml {
91 using namespace ::com::sun::star::drawing;
92 using namespace ::com::sun::star::graphic;
93 using namespace ::com::sun::star::uno;
94 using namespace ::com::sun::star::io;
96 using ::oox::core::XmlFilterBase;
98 namespace {
100 const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75;
101 const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201;
103 awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
105 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
106 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
107 awt::Point aAbsPoint;
108 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
109 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
110 return aAbsPoint;
113 awt::Rectangle lclGetAbsRect( const awt::Rectangle& rRelRect, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
115 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
116 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
117 awt::Rectangle aAbsRect;
118 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
119 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
120 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
121 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
122 return aAbsRect;
125 /// Count the crop value based on a crop fraction and a reference size.
126 sal_Int32 lclConvertCrop(const OUString& rCrop, sal_uInt32 nSize)
128 if (rCrop.endsWith("f"))
130 // Numeric value is specified in 1/65536-ths.
131 sal_uInt32 nCrop = rCrop.copy(0, rCrop.getLength() - 1).toUInt32();
132 return (nCrop * nSize) / 65536;
135 return 0;
138 } // namespace
140 ShapeTypeModel::ShapeTypeModel():
141 mbAutoHeight( false ),
142 mbVisible( true )
146 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
148 moShapeType.assignIfUsed( rSource.moShapeType );
149 moCoordPos.assignIfUsed( rSource.moCoordPos );
150 moCoordSize.assignIfUsed( rSource.moCoordSize );
151 /* The style properties position, left, top, width, height, margin-left,
152 margin-top are not derived from shape template to shape. */
153 maStrokeModel.assignUsed( rSource.maStrokeModel );
154 maFillModel.assignUsed( rSource.maFillModel );
155 moGraphicPath.assignIfUsed( rSource.moGraphicPath );
156 moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
159 ShapeType::ShapeType( Drawing& rDrawing ) :
160 mrDrawing( rDrawing )
164 ShapeType::~ShapeType()
168 sal_Int32 ShapeType::getShapeType() const
170 return maTypeModel.moShapeType.get( 0 );
173 OUString ShapeType::getGraphicPath() const
175 return maTypeModel.moGraphicPath.get( OUString() );
178 awt::Rectangle ShapeType::getCoordSystem() const
180 Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) );
181 Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) );
182 if( aCoordSize.first == 0 )
183 aCoordSize.first = 1;
184 if( aCoordSize.second == 0 )
185 aCoordSize.second = 1;
186 return awt::Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second );
189 awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
191 return pParentAnchor ?
192 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
193 getAbsRectangle();
196 awt::Rectangle ShapeType::getAbsRectangle() const
198 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
200 sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
201 if ( nWidth == 0 )
202 nWidth = 1;
204 sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
205 if ( nHeight == 0 )
206 nHeight = 1;
208 sal_Int32 nLeft;
209 if (o3tl::checked_add<sal_Int32>(ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maLeft, 0, true, true),
210 ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true),
211 nLeft))
213 SAL_WARN("oox", "overflow in addition");
214 nLeft = 0;
216 if (nLeft == 0 && maTypeModel.maPosition == "absolute")
217 nLeft = 1;
219 return awt::Rectangle(
220 nLeft,
221 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
222 nWidth, nHeight );
225 awt::Rectangle ShapeType::getRelRectangle() const
227 sal_Int32 nWidth = maTypeModel.maWidth.toInt32();
228 if ( nWidth == 0 )
229 nWidth = 1;
231 sal_Int32 nHeight = maTypeModel.maHeight.toInt32();
232 if ( nHeight == 0 )
233 nHeight = 1;
235 return awt::Rectangle(
236 maTypeModel.maLeft.toInt32(),
237 maTypeModel.maTop.toInt32(),
238 nWidth, nHeight );
241 ClientData::ClientData() :
242 mnObjType( XML_TOKEN_INVALID ),
243 mnTextHAlign( XML_Left ),
244 mnTextVAlign( XML_Top ),
245 mnCol( -1 ),
246 mnRow( -1 ),
247 mnChecked( VML_CLIENTDATA_UNCHECKED ),
248 mnDropStyle( XML_Combo ),
249 mnDropLines( 1 ),
250 mnVal( 0 ),
251 mnMin( 0 ),
252 mnMax( 0 ),
253 mnInc( 0 ),
254 mnPage( 0 ),
255 mnSelType( XML_Single ),
256 mnVTEdit( VML_CLIENTDATA_TEXT ),
257 mbPrintObject( true ),
258 mbVisible( false ),
259 mbDde( false ),
260 mbNo3D( false ),
261 mbNo3D2( false ),
262 mbMultiLine( false ),
263 mbVScroll( false ),
264 mbSecretEdit( false )
268 ShapeModel::ShapeModel()
269 : mbIsSignatureLine(false)
270 , mbSignatureLineShowSignDate(true)
271 , mbSignatureLineCanAddComment(false)
275 ShapeModel::~ShapeModel()
279 TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
281 mxTextBox.reset( new TextBox(rModel) );
282 return *mxTextBox;
285 ClientData& ShapeModel::createClientData()
287 mxClientData.reset( new ClientData );
288 return *mxClientData;
291 ShapeBase::ShapeBase( Drawing& rDrawing ) :
292 ShapeType( rDrawing )
296 void ShapeBase::finalizeFragmentImport()
298 if( maShapeModel.maType.getLength() > 1 )
300 OUString aType = maShapeModel.maType;
301 if (aType[ 0 ] == '#')
302 aType = aType.copy(1);
303 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( aType ) )
304 maTypeModel.assignUsed( pShapeType->getTypeModel() );
305 else {
306 // Temporary fix, shapetype not found if referenced from different substream
307 // FIXME: extend scope of ShapeContainer to store all shapetypes from the document
308 const OUString sShapeTypePrefix = "shapetype_";
309 if (aType.startsWith(sShapeTypePrefix)) {
310 maTypeModel.moShapeType = aType.copy(sShapeTypePrefix.getLength()).toInt32();
316 OUString ShapeBase::getShapeName() const
318 if( !maTypeModel.maShapeName.isEmpty() )
319 return maTypeModel.maShapeName;
321 OUString aBaseName = mrDrawing.getShapeBaseName( *this );
322 if( !aBaseName.isEmpty() )
324 sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
325 if( nShapeIdx > 0 )
326 return aBaseName + OUStringLiteral1(' ') + OUString::number( nShapeIdx );
329 return OUString();
332 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
334 return nullptr;
337 const ShapeBase* ShapeBase::getChildById( const OUString& ) const
339 return nullptr;
342 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
344 Reference< XShape > xShape;
345 if( mrDrawing.isShapeSupported( *this ) )
347 /* Calculate shape rectangle. Applications may do something special
348 according to some imported shape client data (e.g. Excel cell anchor). */
349 awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
351 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
353 xShape = implConvertAndInsert( rxShapes, aShapeRect );
354 if( xShape.is() )
356 // set imported or generated shape name (not supported by form controls)
357 PropertySet aShapeProp( xShape );
358 if( aShapeProp.hasProperty( PROP_Name ) )
359 aShapeProp.setProperty( PROP_Name, getShapeName() );
360 uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
362 OUString sLinkChainName = getTypeModel().maLegacyId;
363 sal_Int32 id = 0;
364 sal_Int32 idPos = sLinkChainName.indexOf("_x");
365 sal_Int32 seq = 0;
366 if (idPos >= 0)
368 sal_Int32 seqPos = sLinkChainName.indexOf("_s",idPos);
369 if (idPos < seqPos)
371 auto idPosEnd = idPos+2;
372 id = sLinkChainName.copy(idPosEnd, seqPos - idPosEnd).toInt32();
373 seq = sLinkChainName.copy(seqPos+2).toInt32();
377 OUString s_mso_next_textbox;
378 if( getTextBox() )
379 s_mso_next_textbox = getTextBox()->msNextTextbox;
380 if( s_mso_next_textbox.startsWith("#") )
381 s_mso_next_textbox = s_mso_next_textbox.copy(1);
383 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
385 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
386 uno::Any aAny = propertySet->getPropertyValue("FrameInteropGrabBag");
387 auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >());
389 aGrabBag.push_back(comphelper::makePropertyValue("VML-Z-ORDER", maTypeModel.maZIndex.toInt32()));
391 if( !s_mso_next_textbox.isEmpty() )
392 aGrabBag.push_back(comphelper::makePropertyValue("mso-next-textbox", s_mso_next_textbox));
394 if( !sLinkChainName.isEmpty() )
396 aGrabBag.push_back(comphelper::makePropertyValue("TxbxHasLink", true));
397 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Id", id));
398 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Seq", seq));
399 aGrabBag.push_back(comphelper::makePropertyValue("LinkChainName", sLinkChainName));
402 if(!maTypeModel.maRotation.isEmpty())
403 aGrabBag.push_back(comphelper::makePropertyValue("mso-rotation-angle", ConversionHelper::decodeRotation(maTypeModel.maRotation)));
404 propertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(comphelper::containerToSequence(aGrabBag)));
405 sal_Int32 backColorTransparency = 0;
406 propertySet->getPropertyValue("BackColorTransparency")
407 >>= backColorTransparency;
408 if (propertySet->getPropertyValue("FillStyle") == FillStyle_NONE &&
409 backColorTransparency == 100)
411 // If there is no fill, the Word default is 100% transparency.
412 propertySet->setPropertyValue("FillTransparence", makeAny(sal_Int16(100)));
415 else
417 if( maTypeModel.maZIndex.toInt32() )
419 uno::Sequence<beans::PropertyValue> aGrabBag;
420 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
421 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
422 sal_Int32 length;
424 length = aGrabBag.getLength();
425 aGrabBag.realloc( length+1 );
426 aGrabBag[length].Name = "VML-Z-ORDER";
427 aGrabBag[length].Value <<= maTypeModel.maZIndex.toInt32();
429 if( !s_mso_next_textbox.isEmpty() )
431 length = aGrabBag.getLength();
432 aGrabBag.realloc( length+1 );
433 aGrabBag[length].Name = "mso-next-textbox";
434 aGrabBag[length].Value <<= s_mso_next_textbox;
437 if( !sLinkChainName.isEmpty() )
439 length = aGrabBag.getLength();
440 aGrabBag.realloc( length+4 );
441 aGrabBag[length].Name = "TxbxHasLink";
442 aGrabBag[length].Value <<= true;
443 aGrabBag[length+1].Name = "Txbx-Id";
444 aGrabBag[length+1].Value <<= id;
445 aGrabBag[length+2].Name = "Txbx-Seq";
446 aGrabBag[length+2].Value <<= seq;
447 aGrabBag[length+3].Name = "LinkChainName";
448 aGrabBag[length+3].Value <<= sLinkChainName;
450 propertySet->setPropertyValue( "InteropGrabBag", uno::makeAny(aGrabBag) );
453 Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
454 if ( xControlShape.is() && !getTypeModel().mbVisible )
456 PropertySet aControlShapeProp( xControlShape->getControl() );
457 aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( false ) );
459 /* Notify the drawing that a new shape has been inserted. For
460 convenience, pass the rectangle that contains position and
461 size of the shape. */
462 bool bGroupChild = pParentAnchor != nullptr;
463 mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
466 else
467 SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
469 return xShape;
472 void ShapeBase::convertFormatting( const Reference< XShape >& rxShape ) const
474 if( rxShape.is() )
476 /* Calculate shape rectangle. Applications may do something special
477 according to some imported shape client data (e.g. Excel cell anchor). */
478 awt::Rectangle aShapeRect = calcShapeRectangle( nullptr );
480 // convert the shape, if the calculated rectangle is not empty
481 if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
483 rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
484 rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
485 convertShapeProperties( rxShape );
490 // protected ------------------------------------------------------------------
492 awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
494 /* Calculate shape rectangle. Applications may do something special
495 according to some imported shape client data (e.g. Excel cell anchor). */
496 awt::Rectangle aShapeRect;
497 const ClientData* pClientData = getClientData();
498 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
499 aShapeRect = getRectangle( pParentAnchor );
500 return aShapeRect;
503 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
505 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
506 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
507 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
508 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
510 uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
511 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
513 // Any other service supporting the ShadowFormat property?
514 maTypeModel.maShadowModel.pushToPropMap(aPropMap, rGraphicHelper);
515 // TextFrames have BackColor, not FillColor
516 if (aPropMap.hasProperty(PROP_FillColor))
518 aPropMap.setAnyProperty(PROP_BackColor, aPropMap.getProperty(PROP_FillColor));
519 aPropMap.erase(PROP_FillColor);
521 // TextFrames have BackColorTransparency, not FillTransparence
522 if (aPropMap.hasProperty(PROP_FillTransparence))
524 aPropMap.setAnyProperty(PROP_BackColorTransparency, aPropMap.getProperty(PROP_FillTransparence));
525 aPropMap.erase(PROP_FillTransparence);
527 // And no LineColor property; individual borders can have colors and widths
528 boost::optional<sal_Int32> oLineWidth;
529 if (maTypeModel.maStrokeModel.moWeight.has())
530 oLineWidth = ConversionHelper::decodeMeasureToHmm(
531 rGraphicHelper, maTypeModel.maStrokeModel.moWeight.get(), 0, false, false);
532 if (aPropMap.hasProperty(PROP_LineColor))
534 uno::Reference<beans::XPropertySet> xPropertySet(rxShape, uno::UNO_QUERY);
535 static const sal_Int32 aBorders[] = {
536 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
538 for (sal_Int32 nBorder : aBorders)
540 table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<table::BorderLine2>();
541 aBorderLine.Color = aPropMap.getProperty(PROP_LineColor).get<sal_Int32>();
542 if (oLineWidth)
543 aBorderLine.LineWidth = *oLineWidth;
544 aPropMap.setProperty(nBorder, aBorderLine);
546 aPropMap.erase(PROP_LineColor);
549 else if (xSInfo->supportsService("com.sun.star.drawing.CustomShape"))
550 maTypeModel.maTextpathModel.pushToPropMap(aPropMap, rxShape, rGraphicHelper);
552 PropertySet( rxShape ).setProperties( aPropMap );
555 SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) :
556 ShapeBase( rDrawing ),
557 maService( rService )
561 static void lcl_setSurround(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
563 OUString aWrapType = rTypeModel.moWrapType.get();
565 // 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.
566 sal_Int32 nMarginTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, rTypeModel.maMarginTop, 0, false, true);
567 if (nMarginTop < -35277) // Less than 1000 points.
568 aWrapType.clear();
570 css::text::WrapTextMode nSurround = css::text::WrapTextMode_THROUGH;
571 if ( aWrapType == "square" || aWrapType == "tight" ||
572 aWrapType == "through" )
574 nSurround = css::text::WrapTextMode_PARALLEL;
575 if ( rTypeModel.moWrapSide.get() == "left" )
576 nSurround = css::text::WrapTextMode_LEFT;
577 else if ( rTypeModel.moWrapSide.get() == "right" )
578 nSurround = css::text::WrapTextMode_RIGHT;
580 else if ( aWrapType == "topAndBottom" )
581 nSurround = css::text::WrapTextMode_NONE;
583 rPropSet.setProperty(PROP_Surround, static_cast<sal_Int32>(nSurround));
586 static void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
588 if ( rTypeModel.maPosition == "absolute" )
590 // Word supports as-character (inline) and at-character only, absolute can't be inline.
591 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
592 // anchor is set after insertion, so reset to NONE
593 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
595 if ( rTypeModel.maPositionVerticalRelative == "page" )
597 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
599 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
601 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
603 else
605 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
608 else if( rTypeModel.maPosition == "relative" )
609 { // I'm not very sure this is correct either.
610 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
611 // anchor is set after insertion, so reset to NONE
612 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
614 else // static (is the default) means anchored inline
616 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
617 // Use top orientation, this one seems similar to what MSO uses as inline
618 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
621 if ( rTypeModel.maPositionHorizontal == "center" )
622 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::CENTER));
623 else if ( rTypeModel.maPositionHorizontal == "left" )
624 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
625 else if ( rTypeModel.maPositionHorizontal == "right" )
626 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
627 else if ( rTypeModel.maPositionHorizontal == "inside" )
629 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
630 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
632 else if ( rTypeModel.maPositionHorizontal == "outside" )
634 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
635 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
638 if ( rTypeModel.maPositionHorizontalRelative == "page" )
639 rPropSet.setAnyProperty(PROP_HoriOrientRelation, makeAny(text::RelOrientation::PAGE_FRAME));
640 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
641 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
642 else if ( rTypeModel.maPositionVerticalRelative == "text" )
643 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
645 if ( rTypeModel.maPositionVertical == "center" )
646 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::CENTER));
647 else if ( rTypeModel.maPositionVertical == "top" )
648 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
649 else if ( rTypeModel.maPositionVertical == "bottom" )
650 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::BOTTOM));
651 else if ( rTypeModel.maPositionVertical == "inside" )
652 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_TOP));
653 else if ( rTypeModel.maPositionVertical == "outside" )
654 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_BOTTOM));
656 lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper );
659 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
661 awt::Rectangle aShapeRect(rShapeRect);
662 boost::optional<sal_Int32> oRotation;
663 bool bFlipX = false, bFlipY = false;
664 if (!maTypeModel.maRotation.isEmpty())
665 oRotation = ConversionHelper::decodeRotation(maTypeModel.maRotation);
666 if (!maTypeModel.maFlip.isEmpty())
668 if (maTypeModel.maFlip == "x")
670 bFlipX = true;
672 else if (maTypeModel.maFlip == "y")
674 bFlipY = true;
678 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
679 SdrObject* pShape = GetSdrObjectFromXShape( xShape );
680 if( pShape && getShapeType() >= 0 )
682 OUString 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 )));
728 if (!maTypeModel.maLayoutFlowAlt.isEmpty())
730 // Can't handle this property here, as the frame is not attached yet: pass it to writerfilter.
731 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
732 uno::Sequence<beans::PropertyValue> aGrabBag;
733 xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
734 beans::PropertyValue aPair;
735 aPair.Name = "mso-layout-flow-alt";
736 aPair.Value <<= maTypeModel.maLayoutFlowAlt;
737 if (aGrabBag.hasElements())
739 sal_Int32 nLength = aGrabBag.getLength();
740 aGrabBag.realloc(nLength + 1);
741 aGrabBag[nLength] = aPair;
743 else
745 aGrabBag.realloc(1);
746 aGrabBag[0] = aPair;
748 xPropertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(aGrabBag));
751 else
753 // FIXME Setting the relative width/height only for everything but text frames as
754 // TextFrames already have relative width/height feature... but currently not working
755 // in the way we need.
757 // Set the relative width / height if any
758 if ( !maTypeModel.maWidthPercent.isEmpty( ) )
760 // Only page-relative width is supported ATM
761 if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
763 sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
764 // Only apply if nWidth != 0
765 if ( nWidth )
766 PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, makeAny( nWidth ) );
769 if ( !maTypeModel.maHeightPercent.isEmpty( ) )
771 // Only page-relative height is supported ATM
772 if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
774 sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
775 // Only apply if nHeight != 0
776 if ( nHeight )
777 PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
781 // drawinglayer default is center, MSO default is top.
782 drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP;
783 if (maTypeModel.maVTextAnchor == "middle")
784 eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER;
785 else if (maTypeModel.maVTextAnchor == "bottom")
786 eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
787 PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, makeAny(eTextVerticalAdjust));
789 if (getTextBox())
791 getTextBox()->convert(xShape);
792 if (getTextBox()->borderDistanceSet)
794 awt::Size aSize = xShape->getSize();
795 PropertySet(xShape).setAnyProperty(PROP_TextLeftDistance, makeAny(sal_Int32(getTextBox()->borderDistanceLeft)));
796 PropertySet(xShape).setAnyProperty(PROP_TextUpperDistance, makeAny(sal_Int32(getTextBox()->borderDistanceTop)));
797 PropertySet(xShape).setAnyProperty(PROP_TextRightDistance, makeAny(sal_Int32(getTextBox()->borderDistanceRight)));
798 PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, makeAny(sal_Int32(getTextBox()->borderDistanceBottom)));
799 xShape->setSize(aSize);
804 // Import Legacy Fragments (if any)
805 if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
807 Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
808 if( xInStrm.is() )
809 PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
812 PropertySet aPropertySet(xShape);
813 if (xShape.is())
815 if (oRotation)
817 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(*oRotation));
818 uno::Reference<lang::XServiceInfo> xServiceInfo(rxShapes, uno::UNO_QUERY);
819 if (!xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
821 // If rotation is used, simple setPosition() is not enough.
822 aPropertySet.setAnyProperty(PROP_HoriOrientPosition, makeAny(aShapeRect.X));
823 aPropertySet.setAnyProperty(PROP_VertOrientPosition, makeAny(aShapeRect.Y));
827 // custom shape geometry attributes
828 std::vector<css::beans::PropertyValue> aPropVec;
830 // When flip has 'x' or 'y', the associated ShapeRect will be changed but direction change doesn't occur.
831 // It might occur internally in SdrObject of "sw" module, not here.
832 // The associated properties "PROP_MirroredX" and "PROP_MirroredY" have to be set here so that direction change will occur internally.
833 if (bFlipX || bFlipY)
835 assert(!(bFlipX && bFlipY));
836 css::beans::PropertyValue aProp;
837 if (bFlipX)
838 aProp.Name = "MirroredX";
839 else
840 aProp.Name = "MirroredY";
841 aProp.Value <<= true;
842 aPropVec.push_back(aProp);
845 if (!maTypeModel.maAdjustments.isEmpty())
847 std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
848 sal_Int32 nIndex = 0;
851 OUString aToken = maTypeModel.maAdjustments.getToken(0, ',', nIndex);
852 drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue;
853 if (aToken.isEmpty())
854 aAdjustmentValue.State = css::beans::PropertyState::PropertyState_DEFAULT_VALUE;
855 else
856 aAdjustmentValue.Value <<= aToken.toInt32();
857 aAdjustmentValues.push_back(aAdjustmentValue);
858 } while (nIndex >= 0);
860 css::beans::PropertyValue aProp;
861 aProp.Name = "AdjustmentValues";
862 aProp.Value <<= comphelper::containerToSequence(aAdjustmentValues);
863 aPropVec.push_back(aProp);
866 if (!aPropVec.empty())
867 aPropertySet.setAnyProperty(PROP_CustomShapeGeometry, makeAny(comphelper::containerToSequence(aPropVec)));
870 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper );
872 return xShape;
875 Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
877 Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath);
878 return SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
881 Reference< XShape > SimpleShape::createPictureObject(const Reference< XShapes >& rxShapes,
882 const awt::Rectangle& rShapeRect,
883 uno::Reference<graphic::XGraphic> const & rxGraphic) const
885 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
886 if( xShape.is() )
888 PropertySet aPropSet(xShape);
889 if (rxGraphic.is())
891 aPropSet.setProperty(PROP_Graphic, rxGraphic);
893 uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
894 // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
895 if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
897 aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
898 aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
899 aPropSet.setProperty(PROP_Opaque, false);
901 // fdo#70457: preserve rotation information
902 if ( !maTypeModel.maRotation.isEmpty() )
903 aPropSet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
905 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
906 lcl_SetAnchorType(aPropSet, maTypeModel, rGraphicHelper);
908 if (maTypeModel.moCropBottom.has() || maTypeModel.moCropLeft.has() || maTypeModel.moCropRight.has() || maTypeModel.moCropTop.has())
910 text::GraphicCrop aGraphicCrop;
911 awt::Size aOriginalSize = rGraphicHelper.getOriginalSize(rxGraphic);
913 if (maTypeModel.moCropBottom.has())
914 aGraphicCrop.Bottom = lclConvertCrop(maTypeModel.moCropBottom.get(), aOriginalSize.Height);
915 if (maTypeModel.moCropLeft.has())
916 aGraphicCrop.Left = lclConvertCrop(maTypeModel.moCropLeft.get(), aOriginalSize.Width);
917 if (maTypeModel.moCropRight.has())
918 aGraphicCrop.Right = lclConvertCrop(maTypeModel.moCropRight.get(), aOriginalSize.Width);
919 if (maTypeModel.moCropTop.has())
920 aGraphicCrop.Top = lclConvertCrop(maTypeModel.moCropTop.get(), aOriginalSize.Height);
922 aPropSet.setProperty(PROP_GraphicCrop, aGraphicCrop);
925 return xShape;
928 RectangleShape::RectangleShape( Drawing& rDrawing ) :
929 SimpleShape( rDrawing, "com.sun.star.drawing.RectangleShape" )
933 Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
935 OUString aGraphicPath = getGraphicPath();
937 // try to create a picture object
938 if(!aGraphicPath.isEmpty())
939 return SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
941 // default: try to create a rectangle shape
942 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
943 OUString sArcsize = maTypeModel.maArcsize;
944 if ( !sArcsize.isEmpty( ) )
946 sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
947 sal_Int32 nValue = sArcsize.copy( 0, sArcsize.getLength() - 1 ).toInt32( );
948 // Get the smallest half-side
949 double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
950 sal_Int32 nRadius = 0;
951 if ( cLastChar == 'f' )
952 nRadius = size * nValue / 65536;
953 else if ( cLastChar == '%' )
954 nRadius = size * nValue / 100;
955 PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, makeAny( nRadius ) );
957 return xShape;
960 EllipseShape::EllipseShape( Drawing& rDrawing ) :
961 SimpleShape( rDrawing, "com.sun.star.drawing.EllipseShape" )
965 PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
966 SimpleShape( rDrawing, "com.sun.star.drawing.PolyLineShape" )
970 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
972 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
973 // polygon path
974 awt::Rectangle aCoordSys = getCoordSystem();
975 if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
977 ::std::vector< awt::Point > aAbsPoints;
978 for (auto const& point : maShapeModel.maPoints)
979 aAbsPoints.push_back( lclGetAbsPoint( point, rShapeRect, aCoordSys ) );
980 PointSequenceSequence aPointSeq( 1 );
981 aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
982 PropertySet aPropSet( xShape );
983 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
985 return xShape;
988 LineShape::LineShape(Drawing& rDrawing)
989 : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
993 awt::Rectangle LineShape::getAbsRectangle() const
995 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
996 awt::Rectangle aShapeRect;
997 sal_Int32 nIndex = 0;
999 aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, true, true);
1000 aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, false, true);
1001 nIndex = 0;
1002 aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, true, true) - aShapeRect.X;
1003 aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, false, true) - aShapeRect.Y;
1004 return aShapeRect;
1007 awt::Rectangle LineShape::getRelRectangle() const
1009 awt::Rectangle aShapeRect;
1010 sal_Int32 nIndex = 0;
1012 aShapeRect.X = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1013 aShapeRect.Y = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1014 nIndex = 0;
1015 aShapeRect.Width = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.X;
1016 aShapeRect.Height = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.Y;
1017 return aShapeRect;
1020 BezierShape::BezierShape(Drawing& rDrawing)
1021 : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
1025 Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1027 // If we have an 'x' in the last part of the path it means it is closed...
1028 sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(',');
1029 if ( nPos != -1 && maShapeModel.maVmlPath.indexOf('x', nPos) != -1 )
1031 const_cast<BezierShape*>( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1034 awt::Rectangle aCoordSys = getCoordSystem();
1035 PolyPolygonBezierCoords aBezierCoords;
1037 if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
1039 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1041 // Bezier paths may consist of one or more sub-paths
1042 typedef ::std::vector< ::std::vector< awt::Point > > SubPathList;
1043 typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
1044 SubPathList aCoordLists;
1045 FlagsList aFlagLists;
1046 sal_Int32 nIndex = 0;
1048 // Curve defined by to, from, control1 and control2 attributes
1049 if ( maShapeModel.maVmlPath.isEmpty() )
1051 aCoordLists.emplace_back( );
1052 aFlagLists.emplace_back( );
1054 // Start point
1055 aCoordLists[ 0 ].emplace_back(
1056 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ),
1057 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) );
1058 // Control point 1
1059 aCoordLists[ 0 ].emplace_back(
1060 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ),
1061 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) );
1062 // Control point 2
1063 aCoordLists[ 0 ].emplace_back(
1064 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ),
1065 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) );
1066 // End point
1067 aCoordLists[ 0 ].emplace_back(
1068 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ),
1069 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) );
1071 // First and last points are normals, points 2 and 4 are controls
1072 aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
1073 aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
1074 aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
1076 // Curve defined by path attribute
1077 else
1079 // Parse VML path string and convert to absolute coordinates
1080 ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
1082 for (auto & coordList : aCoordLists)
1083 for (auto & point : coordList)
1085 point = lclGetAbsPoint( point, rShapeRect, aCoordSys );
1089 aBezierCoords.Coordinates.realloc( aCoordLists.size() );
1090 for ( size_t i = 0; i < aCoordLists.size(); i++ )
1091 aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] );
1093 aBezierCoords.Flags.realloc( aFlagLists.size() );
1094 for ( size_t i = 0; i < aFlagLists.size(); i++ )
1095 aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] );
1097 if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
1098 && aCoordLists.front().front().X == aCoordLists.back().back().X
1099 && aCoordLists.front().front().Y == aCoordLists.back().back().Y )
1100 { // HACK: If the shape is in fact closed, which can be found out only when the path is known,
1101 // force to closed bezier shape (otherwise e.g. fill won't work).
1102 const_cast< BezierShape* >( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1106 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1108 if( aBezierCoords.Coordinates.hasElements())
1110 PropertySet aPropSet( xShape );
1111 aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
1114 // Handle horizontal and vertical flip.
1115 if (!maTypeModel.maFlip.isEmpty())
1117 if (SdrObject* pShape = GetSdrObjectFromXShape(xShape))
1119 if (maTypeModel.maFlip.startsWith("x"))
1121 Point aCenter(pShape->GetSnapRect().Center());
1122 Point aPoint2(aCenter);
1123 aPoint2.setY(aPoint2.getY() + 1);
1124 pShape->NbcMirror(aCenter, aPoint2);
1126 if (maTypeModel.maFlip.endsWith("y"))
1128 Point aCenter(pShape->GetSnapRect().Center());
1129 Point aPoint2(aCenter);
1130 aPoint2.setX(aPoint2.getX() + 1);
1131 pShape->NbcMirror(aCenter, aPoint2);
1136 // Hacky way of ensuring the shape is correctly sized/positioned
1139 // E.g. SwXFrame::setPosition() unconditionally throws
1140 xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
1141 xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
1143 catch (const ::css::uno::Exception&)
1145 // TODO: try some other way to ensure size/position
1147 return xShape;
1150 CustomShape::CustomShape( Drawing& rDrawing ) :
1151 SimpleShape( rDrawing, "com.sun.star.drawing.CustomShape" )
1155 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1157 // try to create a custom shape
1158 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1159 if( xShape.is() ) try
1161 // create the custom shape geometry
1162 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
1163 xDefaulter->createCustomShapeDefaults( OUString::number( getShapeType() ) );
1164 // convert common properties
1165 convertShapeProperties( xShape );
1167 catch( Exception& )
1170 return xShape;
1173 ComplexShape::ComplexShape( Drawing& rDrawing ) :
1174 CustomShape( rDrawing )
1178 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1180 XmlFilterBase& rFilter = mrDrawing.getFilter();
1181 sal_Int32 nShapeType = getShapeType();
1182 OUString aGraphicPath = getGraphicPath();
1184 // try to find registered OLE object info
1185 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
1187 SAL_WARN_IF(
1188 nShapeType != VML_SHAPETYPE_PICTUREFRAME, "oox",
1189 "ComplexShape::implConvertAndInsert - unexpected shape type");
1191 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
1192 if( pOleObjectInfo->mbDmlShape )
1193 return Reference< XShape >();
1195 PropertyMap aOleProps;
1196 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1197 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
1199 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.OLE2Shape", rxShapes, rShapeRect );
1200 if( xShape.is() )
1202 // set the replacement graphic
1203 if( !aGraphicPath.isEmpty() )
1205 WmfExternal aExtHeader;
1206 aExtHeader.mapMode = 8;
1207 aExtHeader.xExt = rShapeRect.Width;
1208 aExtHeader.yExt = rShapeRect.Height;
1210 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath, &aExtHeader);
1211 if (xGraphic.is())
1212 aOleProps.setProperty( PROP_Graphic, xGraphic);
1215 PropertySet aPropSet( xShape );
1216 aPropSet.setProperties( aOleProps );
1218 return xShape;
1223 // try to find registered form control info
1224 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
1225 if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
1227 if( !pControlInfo->maName.isEmpty() )
1229 // load the control properties from fragment
1230 ::oox::ole::EmbeddedControl aControl(pControlInfo->maName);
1231 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
1233 // create and return the control shape (including control model)
1234 sal_Int32 nCtrlIndex = -1;
1235 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
1237 if (pControlInfo->mbTextContentShape)
1239 PropertySet aPropertySet(xShape);
1240 lcl_SetAnchorType(aPropertySet, maTypeModel, mrDrawing.getFilter().getGraphicHelper());
1242 // on error, proceed and try to create picture from replacement image
1243 if( xShape.is() )
1244 return xShape;
1249 // host application wants to create the shape (do not try failed OLE controls again)
1250 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
1252 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
1253 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
1254 if( xShape.is() )
1255 return xShape;
1259 if( getShapeModel().mbIsSignatureLine )
1261 uno::Reference<graphic::XGraphic> xGraphic;
1262 bool bIsSigned(false);
1265 // Get the document signatures
1266 Reference<security::XDocumentDigitalSignatures> xSignatures(
1267 security::DocumentDigitalSignatures::createWithVersion(
1268 comphelper::getProcessComponentContext(), "1.2"));
1270 uno::Reference<embed::XStorage> xStorage
1271 = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
1272 ZIP_STORAGE_FORMAT_STRING, mrDrawing.getFilter().getFileUrl(),
1273 embed::ElementModes::READ);
1274 SAL_WARN_IF(!xStorage.is(), "oox.vml", "No xStorage!");
1276 uno::Sequence<security::DocumentSignatureInformation> xSignatureInfo
1277 = xSignatures->verifyScriptingContentSignatures(xStorage,
1278 uno::Reference<io::XInputStream>());
1280 for (int i = 0; i < xSignatureInfo.getLength(); i++)
1282 // Try to find matching signature line image - if none exists that is fine,
1283 // then the signature line is not digitally signed.
1284 if (xSignatureInfo[i].SignatureLineId == getShapeModel().maSignatureId)
1286 bIsSigned = true;
1287 if (xSignatureInfo[i].SignatureIsValid)
1289 // Signature is valid, use the 'valid' image
1290 SAL_WARN_IF(!xSignatureInfo[i].ValidSignatureLineImage.is(), "oox.vml",
1291 "No ValidSignatureLineImage!");
1292 xGraphic = xSignatureInfo[i].ValidSignatureLineImage;
1294 else
1296 // Signature is invalid, use the 'invalid' image
1297 SAL_WARN_IF(!xSignatureInfo[i].InvalidSignatureLineImage.is(), "oox.vml",
1298 "No InvalidSignatureLineImage!");
1299 xGraphic = xSignatureInfo[i].InvalidSignatureLineImage;
1301 break;
1305 catch (css::uno::Exception&)
1307 // DocumentDigitalSignatures service not available.
1308 // We continue by rendering the "unsigned" shape instead.
1311 Reference< XShape > xShape;
1312 if (xGraphic.is())
1314 // If available, use the signed image from the signature
1315 xShape = SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
1317 else
1319 // Create shape with the fallback "unsigned" image
1320 xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1323 // Store signature line properties
1324 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1325 xPropertySet->setPropertyValue("IsSignatureLine", uno::makeAny(true));
1326 xPropertySet->setPropertyValue("SignatureLineId",
1327 uno::makeAny(getShapeModel().maSignatureId));
1328 xPropertySet->setPropertyValue(
1329 "SignatureLineSuggestedSignerName",
1330 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerName));
1331 xPropertySet->setPropertyValue(
1332 "SignatureLineSuggestedSignerTitle",
1333 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerTitle));
1334 xPropertySet->setPropertyValue(
1335 "SignatureLineSuggestedSignerEmail",
1336 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerEmail));
1337 xPropertySet->setPropertyValue(
1338 "SignatureLineSigningInstructions",
1339 uno::makeAny(getShapeModel().maSignatureLineSigningInstructions));
1340 xPropertySet->setPropertyValue(
1341 "SignatureLineShowSignDate",
1342 uno::makeAny(getShapeModel().mbSignatureLineShowSignDate));
1343 xPropertySet->setPropertyValue(
1344 "SignatureLineCanAddComment",
1345 uno::makeAny(getShapeModel().mbSignatureLineCanAddComment));
1346 xPropertySet->setPropertyValue("SignatureLineIsSigned", uno::makeAny(bIsSigned));
1348 if (!aGraphicPath.isEmpty())
1350 xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath);
1351 xPropertySet->setPropertyValue("SignatureLineUnsignedImage", uno::makeAny(xGraphic));
1353 return xShape;
1356 // try to create a picture object
1357 if( !aGraphicPath.isEmpty() )
1359 Reference<XShape> xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1360 // AS_CHARACTER shape: vertical orientation default is bottom, MSO default is top.
1361 if ( maTypeModel.maPosition != "absolute" && maTypeModel.maPosition != "relative" )
1362 PropertySet( xShape ).setAnyProperty( PROP_VertOrient, makeAny(text::VertOrientation::TOP));
1363 return xShape;
1366 // default: try to create a custom shape
1367 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
1370 GroupShape::GroupShape( Drawing& rDrawing ) :
1371 ShapeBase( rDrawing ),
1372 mxChildren( new ShapeContainer( rDrawing ) )
1376 GroupShape::~GroupShape()
1380 void GroupShape::finalizeFragmentImport()
1382 // basic shape processing
1383 ShapeBase::finalizeFragmentImport();
1384 // finalize all child shapes
1385 mxChildren->finalizeFragmentImport();
1388 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
1390 return mxChildren->getShapeTypeById( rShapeId );
1393 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
1395 return mxChildren->getShapeById( rShapeId );
1398 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1400 Reference< XShape > xGroupShape;
1401 // check that this shape contains children and a valid coordinate system
1402 ShapeParentAnchor aParentAnchor;
1403 aParentAnchor.maShapeRect = rShapeRect;
1404 aParentAnchor.maCoordSys = getCoordSystem();
1405 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
1407 xGroupShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GroupShape", rxShapes, rShapeRect );
1408 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
1409 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
1410 if( !xChildShapes->hasElements() )
1412 SAL_WARN("oox", "no child shape has been created - deleting the group shape");
1413 rxShapes->remove( xGroupShape );
1414 xGroupShape.clear();
1417 catch( Exception& )
1421 uno::Reference<beans::XPropertySet> xPropertySet;
1422 if (!maTypeModel.maEditAs.isEmpty())
1423 xPropertySet = uno::Reference<beans::XPropertySet>(xGroupShape, uno::UNO_QUERY);
1424 if (xPropertySet.is())
1426 uno::Sequence<beans::PropertyValue> aGrabBag;
1427 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1428 beans::PropertyValue aPair;
1429 aPair.Name = "mso-edit-as";
1430 aPair.Value <<= maTypeModel.maEditAs;
1431 if (aGrabBag.hasElements())
1433 sal_Int32 nLength = aGrabBag.getLength();
1434 aGrabBag.realloc(nLength + 1);
1435 aGrabBag[nLength] = aPair;
1437 else
1439 aGrabBag.realloc(1);
1440 aGrabBag[0] = aPair;
1442 xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aGrabBag));
1444 // Make sure group shapes are inline as well, unless there is an explicit different style.
1445 PropertySet aPropertySet(xGroupShape);
1446 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1447 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper);
1448 if (!maTypeModel.maRotation.isEmpty())
1449 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
1450 return xGroupShape;
1453 } // namespace vml
1454 } // namespace oox
1456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */