Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / oox / source / vml / vmlshape.cxx
blob40a547a2efe24f2602d4bd59fcaa54cb1156fca0
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 <oox/vml/vmlshape.hxx>
26 #include <vcl/wmf.hxx>
27 #include <vcl/virdev.hxx>
29 #include <com/sun/star/beans/PropertyValues.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/awt/XControlModel.hpp>
32 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
33 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
34 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
35 #include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
36 #include <com/sun/star/drawing/XShapes.hpp>
37 #include <com/sun/star/drawing/XControlShape.hpp>
38 #include <com/sun/star/graphic/XGraphic.hpp>
39 #include <com/sun/star/table/BorderLine2.hpp>
40 #include <com/sun/star/text/HoriOrientation.hpp>
41 #include <com/sun/star/text/RelOrientation.hpp>
42 #include <com/sun/star/text/SizeType.hpp>
43 #include <com/sun/star/text/VertOrientation.hpp>
44 #include <com/sun/star/text/WrapTextMode.hpp>
45 #include <com/sun/star/text/XTextContent.hpp>
46 #include <com/sun/star/text/XTextDocument.hpp>
47 #include <com/sun/star/text/XTextFrame.hpp>
48 #include <com/sun/star/lang/XServiceInfo.hpp>
49 #include <com/sun/star/text/TextContentAnchorType.hpp>
50 #include <com/sun/star/text/GraphicCrop.hpp>
51 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
52 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
53 #include <rtl/math.hxx>
54 #include <rtl/ustrbuf.hxx>
55 #include <svx/svdtrans.hxx>
56 #include <oox/drawingml/shapepropertymap.hxx>
57 #include <oox/helper/graphichelper.hxx>
58 #include <oox/helper/propertyset.hxx>
59 #include <oox/ole/axcontrol.hxx>
60 #include <oox/ole/axcontrolfragment.hxx>
61 #include <oox/ole/oleobjecthelper.hxx>
62 #include <oox/token/properties.hxx>
63 #include <oox/token/tokens.hxx>
64 #include <oox/vml/vmldrawing.hxx>
65 #include <oox/vml/vmlshapecontainer.hxx>
66 #include <oox/vml/vmltextbox.hxx>
67 #include <oox/core/xmlfilterbase.hxx>
68 #include <oox/helper/containerhelper.hxx>
69 #include <svx/EnhancedCustomShapeTypeNames.hxx>
70 #include <svx/unoapi.hxx>
71 #include <svx/svdoashp.hxx>
72 #include <comphelper/sequence.hxx>
73 #include <comphelper/processfactory.hxx>
74 #include <comphelper/propertyvalue.hxx>
75 #include <comphelper/storagehelper.hxx>
76 #include <vcl/svapp.hxx>
78 using ::com::sun::star::beans::XPropertySet;
79 using ::com::sun::star::uno::Any;
81 using namespace ::com::sun::star;
82 using namespace ::com::sun::star::text;
84 namespace oox {
85 namespace vml {
87 using namespace ::com::sun::star::drawing;
88 using namespace ::com::sun::star::graphic;
89 using namespace ::com::sun::star::uno;
90 using namespace ::com::sun::star::io;
92 using ::oox::core::XmlFilterBase;
94 namespace {
96 const sal_Int32 VML_SHAPETYPE_PICTUREFRAME = 75;
97 const sal_Int32 VML_SHAPETYPE_HOSTCONTROL = 201;
99 awt::Point lclGetAbsPoint( const awt::Point& rRelPoint, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
101 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
102 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
103 awt::Point aAbsPoint;
104 aAbsPoint.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelPoint.X - rCoordSys.X) + 0.5 );
105 aAbsPoint.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelPoint.Y - rCoordSys.Y) + 0.5 );
106 return aAbsPoint;
109 awt::Rectangle lclGetAbsRect( const awt::Rectangle& rRelRect, const awt::Rectangle& rShapeRect, const awt::Rectangle& rCoordSys )
111 double fWidthRatio = static_cast< double >( rShapeRect.Width ) / rCoordSys.Width;
112 double fHeightRatio = static_cast< double >( rShapeRect.Height ) / rCoordSys.Height;
113 awt::Rectangle aAbsRect;
114 aAbsRect.X = static_cast< sal_Int32 >( rShapeRect.X + fWidthRatio * (rRelRect.X - rCoordSys.X) + 0.5 );
115 aAbsRect.Y = static_cast< sal_Int32 >( rShapeRect.Y + fHeightRatio * (rRelRect.Y - rCoordSys.Y) + 0.5 );
116 aAbsRect.Width = static_cast< sal_Int32 >( fWidthRatio * rRelRect.Width + 0.5 );
117 aAbsRect.Height = static_cast< sal_Int32 >( fHeightRatio * rRelRect.Height + 0.5 );
118 return aAbsRect;
121 /// Count the crop value based on a crop fraction and a reference size.
122 sal_Int32 lclConvertCrop(const OUString& rCrop, sal_uInt32 nSize)
124 if (rCrop.endsWith("f"))
126 // Numeric value is specified in 1/65536-ths.
127 sal_uInt32 nCrop = rCrop.copy(0, rCrop.getLength() - 1).toUInt32();
128 return (nCrop * nSize) / 65536;
131 return 0;
134 } // namespace
136 ShapeTypeModel::ShapeTypeModel():
137 mbAutoHeight( false ),
138 mbVisible( true )
142 void ShapeTypeModel::assignUsed( const ShapeTypeModel& rSource )
144 moShapeType.assignIfUsed( rSource.moShapeType );
145 moCoordPos.assignIfUsed( rSource.moCoordPos );
146 moCoordSize.assignIfUsed( rSource.moCoordSize );
147 /* The style properties position, left, top, width, height, margin-left,
148 margin-top are not derived from shape template to shape. */
149 maStrokeModel.assignUsed( rSource.maStrokeModel );
150 maFillModel.assignUsed( rSource.maFillModel );
151 moGraphicPath.assignIfUsed( rSource.moGraphicPath );
152 moGraphicTitle.assignIfUsed( rSource.moGraphicTitle );
155 ShapeType::ShapeType( Drawing& rDrawing ) :
156 mrDrawing( rDrawing )
160 ShapeType::~ShapeType()
164 sal_Int32 ShapeType::getShapeType() const
166 return maTypeModel.moShapeType.get( 0 );
169 OUString ShapeType::getGraphicPath() const
171 return maTypeModel.moGraphicPath.get( OUString() );
174 awt::Rectangle ShapeType::getCoordSystem() const
176 Int32Pair aCoordPos = maTypeModel.moCoordPos.get( Int32Pair( 0, 0 ) );
177 Int32Pair aCoordSize = maTypeModel.moCoordSize.get( Int32Pair( 1000, 1000 ) );
178 if( aCoordSize.first == 0 )
179 aCoordSize.first = 1;
180 if( aCoordSize.second == 0 )
181 aCoordSize.second = 1;
182 return awt::Rectangle( aCoordPos.first, aCoordPos.second, aCoordSize.first, aCoordSize.second );
185 awt::Rectangle ShapeType::getRectangle( const ShapeParentAnchor* pParentAnchor ) const
187 return pParentAnchor ?
188 lclGetAbsRect( getRelRectangle(), pParentAnchor->maShapeRect, pParentAnchor->maCoordSys ) :
189 getAbsRectangle();
192 awt::Rectangle ShapeType::getAbsRectangle() const
194 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
196 sal_Int32 nWidth = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maWidth, 0, true, true );
197 if ( nWidth == 0 )
198 nWidth = 1;
200 sal_Int32 nHeight = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maHeight, 0, false, true );
201 if ( nHeight == 0 )
202 nHeight = 1;
204 sal_Int32 nLeft = ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maLeft, 0, true, true )
205 + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true );
206 if (nLeft == 0 && maTypeModel.maPosition == "absolute")
207 nLeft = 1;
209 return awt::Rectangle(
210 nLeft,
211 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maTop, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maTypeModel.maMarginTop, 0, false, true ),
212 nWidth, nHeight );
215 awt::Rectangle ShapeType::getRelRectangle() const
217 sal_Int32 nWidth = maTypeModel.maWidth.toInt32();
218 if ( nWidth == 0 )
219 nWidth = 1;
221 sal_Int32 nHeight = maTypeModel.maHeight.toInt32();
222 if ( nHeight == 0 )
223 nHeight = 1;
225 return awt::Rectangle(
226 maTypeModel.maLeft.toInt32(),
227 maTypeModel.maTop.toInt32(),
228 nWidth, nHeight );
231 ClientData::ClientData() :
232 mnObjType( XML_TOKEN_INVALID ),
233 mnTextHAlign( XML_Left ),
234 mnTextVAlign( XML_Top ),
235 mnCol( -1 ),
236 mnRow( -1 ),
237 mnChecked( VML_CLIENTDATA_UNCHECKED ),
238 mnDropStyle( XML_Combo ),
239 mnDropLines( 1 ),
240 mnVal( 0 ),
241 mnMin( 0 ),
242 mnMax( 0 ),
243 mnInc( 0 ),
244 mnPage( 0 ),
245 mnSelType( XML_Single ),
246 mnVTEdit( VML_CLIENTDATA_TEXT ),
247 mbPrintObject( true ),
248 mbVisible( false ),
249 mbDde( false ),
250 mbNo3D( false ),
251 mbNo3D2( false ),
252 mbMultiLine( false ),
253 mbVScroll( false ),
254 mbSecretEdit( false )
258 ShapeModel::ShapeModel()
259 : mbIsSignatureLine(false)
260 , mbSignatureLineShowSignDate(true)
261 , mbSignatureLineCanAddComment(false)
265 ShapeModel::~ShapeModel()
269 TextBox& ShapeModel::createTextBox(ShapeTypeModel& rModel)
271 mxTextBox.reset( new TextBox(rModel) );
272 return *mxTextBox;
275 ClientData& ShapeModel::createClientData()
277 mxClientData.reset( new ClientData );
278 return *mxClientData;
281 ShapeBase::ShapeBase( Drawing& rDrawing ) :
282 ShapeType( rDrawing )
286 void ShapeBase::finalizeFragmentImport()
288 if( maShapeModel.maType.getLength() > 1 )
290 OUString aType = maShapeModel.maType;
291 if (aType[ 0 ] == '#')
292 aType = aType.copy(1);
293 if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( aType ) )
294 maTypeModel.assignUsed( pShapeType->getTypeModel() );
295 else {
296 // Temporary fix, shapetype not found if referenced from different substream
297 // FIXME: extend scope of ShapeContainer to store all shapetypes from the document
298 const OUString sShapeTypePrefix = "shapetype_";
299 if (aType.startsWith(sShapeTypePrefix)) {
300 maTypeModel.moShapeType = aType.copy(sShapeTypePrefix.getLength()).toInt32();
306 OUString ShapeBase::getShapeName() const
308 if( !maTypeModel.maShapeName.isEmpty() )
309 return maTypeModel.maShapeName;
311 OUString aBaseName = mrDrawing.getShapeBaseName( *this );
312 if( !aBaseName.isEmpty() )
314 sal_Int32 nShapeIdx = mrDrawing.getLocalShapeIndex( getShapeId() );
315 if( nShapeIdx > 0 )
316 return aBaseName + OUStringLiteral1(' ') + OUString::number( nShapeIdx );
319 return OUString();
322 const ShapeType* ShapeBase::getChildTypeById( const OUString& ) const
324 return nullptr;
327 const ShapeBase* ShapeBase::getChildById( const OUString& ) const
329 return nullptr;
332 Reference< XShape > ShapeBase::convertAndInsert( const Reference< XShapes >& rxShapes, const ShapeParentAnchor* pParentAnchor ) const
334 Reference< XShape > xShape;
335 if( mrDrawing.isShapeSupported( *this ) )
337 /* Calculate shape rectangle. Applications may do something special
338 according to some imported shape client data (e.g. Excel cell anchor). */
339 awt::Rectangle aShapeRect = calcShapeRectangle( pParentAnchor );
341 if( ((aShapeRect.Width > 0) || (aShapeRect.Height > 0)) && rxShapes.is() )
343 xShape = implConvertAndInsert( rxShapes, aShapeRect );
344 if( xShape.is() )
346 // set imported or generated shape name (not supported by form controls)
347 PropertySet aShapeProp( xShape );
348 if( aShapeProp.hasProperty( PROP_Name ) )
349 aShapeProp.setProperty( PROP_Name, getShapeName() );
350 uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
352 OUString sLinkChainName = getTypeModel().maLegacyId;
353 sal_Int32 id = 0;
354 sal_Int32 idPos = sLinkChainName.indexOf("_x");
355 sal_Int32 seq = 0;
356 if (idPos >= 0)
358 sal_Int32 seqPos = sLinkChainName.indexOf("_s",idPos);
359 if (idPos < seqPos)
361 id = sLinkChainName.copy(idPos+2,seqPos-idPos+2).toInt32();
362 seq = sLinkChainName.copy(seqPos+2).toInt32();
366 OUString s_mso_next_textbox;
367 if( getTextBox() )
368 s_mso_next_textbox = getTextBox()->msNextTextbox;
369 if( s_mso_next_textbox.startsWith("#") )
370 s_mso_next_textbox = s_mso_next_textbox.copy(1);
372 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
374 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
375 uno::Any aAny = propertySet->getPropertyValue("FrameInteropGrabBag");
376 auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >());
378 aGrabBag.push_back(comphelper::makePropertyValue("VML-Z-ORDER", maTypeModel.maZIndex.toInt32()));
380 if( !s_mso_next_textbox.isEmpty() )
381 aGrabBag.push_back(comphelper::makePropertyValue("mso-next-textbox", s_mso_next_textbox));
383 if( !sLinkChainName.isEmpty() )
385 aGrabBag.push_back(comphelper::makePropertyValue("TxbxHasLink", true));
386 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Id", id));
387 aGrabBag.push_back(comphelper::makePropertyValue("Txbx-Seq", seq));
388 aGrabBag.push_back(comphelper::makePropertyValue("LinkChainName", sLinkChainName));
391 if(!maTypeModel.maRotation.isEmpty())
392 aGrabBag.push_back(comphelper::makePropertyValue("mso-rotation-angle", ConversionHelper::decodeRotation(maTypeModel.maRotation)));
393 propertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(comphelper::containerToSequence(aGrabBag)));
394 sal_Int32 backColorTransparency = 0;
395 propertySet->getPropertyValue("BackColorTransparency")
396 >>= backColorTransparency;
397 if (propertySet->getPropertyValue("FillStyle") == FillStyle_NONE &&
398 backColorTransparency == 100)
400 // If there is no fill, the Word default is 100% transparency.
401 propertySet->setPropertyValue("FillTransparence", makeAny(sal_Int16(100)));
404 else
406 if( maTypeModel.maZIndex.toInt32() )
408 uno::Sequence<beans::PropertyValue> aGrabBag;
409 uno::Reference<beans::XPropertySet> propertySet (xShape, uno::UNO_QUERY);
410 propertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
411 sal_Int32 length;
413 length = aGrabBag.getLength();
414 aGrabBag.realloc( length+1 );
415 aGrabBag[length].Name = "VML-Z-ORDER";
416 aGrabBag[length].Value <<= maTypeModel.maZIndex.toInt32();
418 if( !s_mso_next_textbox.isEmpty() )
420 length = aGrabBag.getLength();
421 aGrabBag.realloc( length+1 );
422 aGrabBag[length].Name = "mso-next-textbox";
423 aGrabBag[length].Value <<= s_mso_next_textbox;
426 if( !sLinkChainName.isEmpty() )
428 length = aGrabBag.getLength();
429 aGrabBag.realloc( length+4 );
430 aGrabBag[length].Name = "TxbxHasLink";
431 aGrabBag[length].Value <<= true;
432 aGrabBag[length+1].Name = "Txbx-Id";
433 aGrabBag[length+1].Value <<= id;
434 aGrabBag[length+2].Name = "Txbx-Seq";
435 aGrabBag[length+2].Value <<= seq;
436 aGrabBag[length+3].Name = "LinkChainName";
437 aGrabBag[length+3].Value <<= sLinkChainName;
439 propertySet->setPropertyValue( "InteropGrabBag", uno::makeAny(aGrabBag) );
442 Reference< XControlShape > xControlShape( xShape, uno::UNO_QUERY );
443 if ( xControlShape.is() && !getTypeModel().mbVisible )
445 PropertySet aControlShapeProp( xControlShape->getControl() );
446 aControlShapeProp.setProperty( PROP_EnableVisible, uno::makeAny( false ) );
448 /* Notify the drawing that a new shape has been inserted. For
449 convenience, pass the rectangle that contains position and
450 size of the shape. */
451 bool bGroupChild = pParentAnchor != nullptr;
452 mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
455 else
456 SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
458 return xShape;
461 void ShapeBase::convertFormatting( const Reference< XShape >& rxShape ) const
463 if( rxShape.is() )
465 /* Calculate shape rectangle. Applications may do something special
466 according to some imported shape client data (e.g. Excel cell anchor). */
467 awt::Rectangle aShapeRect = calcShapeRectangle( nullptr );
469 // convert the shape, if the calculated rectangle is not empty
470 if( (aShapeRect.Width > 0) || (aShapeRect.Height > 0) )
472 rxShape->setPosition( awt::Point( aShapeRect.X, aShapeRect.Y ) );
473 rxShape->setSize( awt::Size( aShapeRect.Width, aShapeRect.Height ) );
474 convertShapeProperties( rxShape );
479 // protected ------------------------------------------------------------------
481 awt::Rectangle ShapeBase::calcShapeRectangle( const ShapeParentAnchor* pParentAnchor ) const
483 /* Calculate shape rectangle. Applications may do something special
484 according to some imported shape client data (e.g. Excel cell anchor). */
485 awt::Rectangle aShapeRect;
486 const ClientData* pClientData = getClientData();
487 if( !pClientData || !mrDrawing.convertClientAnchor( aShapeRect, pClientData->maAnchor ) )
488 aShapeRect = getRectangle( pParentAnchor );
489 return aShapeRect;
492 void ShapeBase::convertShapeProperties( const Reference< XShape >& rxShape ) const
494 ::oox::drawingml::ShapePropertyMap aPropMap( mrDrawing.getFilter().getModelObjectHelper() );
495 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
496 maTypeModel.maStrokeModel.pushToPropMap( aPropMap, rGraphicHelper );
497 maTypeModel.maFillModel.pushToPropMap( aPropMap, rGraphicHelper );
499 uno::Reference<lang::XServiceInfo> xSInfo(rxShape, uno::UNO_QUERY_THROW);
500 if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
502 // Any other service supporting the ShadowFormat property?
503 maTypeModel.maShadowModel.pushToPropMap(aPropMap, rGraphicHelper);
504 // TextFrames have BackColor, not FillColor
505 if (aPropMap.hasProperty(PROP_FillColor))
507 aPropMap.setAnyProperty(PROP_BackColor, aPropMap.getProperty(PROP_FillColor));
508 aPropMap.erase(PROP_FillColor);
510 // TextFrames have BackColorTransparency, not FillTransparence
511 if (aPropMap.hasProperty(PROP_FillTransparence))
513 aPropMap.setAnyProperty(PROP_BackColorTransparency, aPropMap.getProperty(PROP_FillTransparence));
514 aPropMap.erase(PROP_FillTransparence);
516 // And no LineColor property; individual borders can have colors and widths
517 boost::optional<sal_Int32> oLineWidth;
518 if (maTypeModel.maStrokeModel.moWeight.has())
519 oLineWidth.reset(ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maStrokeModel.moWeight.get(), 0, false, false));
520 if (aPropMap.hasProperty(PROP_LineColor))
522 uno::Reference<beans::XPropertySet> xPropertySet(rxShape, uno::UNO_QUERY);
523 static const sal_Int32 aBorders[] = {
524 PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
526 for (sal_Int32 nBorder : aBorders)
528 table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<table::BorderLine2>();
529 aBorderLine.Color = aPropMap.getProperty(PROP_LineColor).get<sal_Int32>();
530 if (oLineWidth)
531 aBorderLine.LineWidth = *oLineWidth;
532 aPropMap.setProperty(nBorder, aBorderLine);
534 aPropMap.erase(PROP_LineColor);
537 else if (xSInfo->supportsService("com.sun.star.drawing.CustomShape"))
538 maTypeModel.maTextpathModel.pushToPropMap(aPropMap, rxShape, rGraphicHelper);
540 PropertySet( rxShape ).setProperties( aPropMap );
543 SimpleShape::SimpleShape( Drawing& rDrawing, const OUString& rService ) :
544 ShapeBase( rDrawing ),
545 maService( rService )
549 void lcl_setSurround(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
551 OUString aWrapType = rTypeModel.moWrapType.get();
553 // 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.
554 sal_Int32 nMarginTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, rTypeModel.maMarginTop, 0, false, true);
555 if (nMarginTop < -35277) // Less than 1000 points.
556 aWrapType.clear();
558 css::text::WrapTextMode nSurround = css::text::WrapTextMode_THROUGH;
559 if ( aWrapType == "square" || aWrapType == "tight" ||
560 aWrapType == "through" )
562 nSurround = css::text::WrapTextMode_PARALLEL;
563 if ( rTypeModel.moWrapSide.get() == "left" )
564 nSurround = css::text::WrapTextMode_LEFT;
565 else if ( rTypeModel.moWrapSide.get() == "right" )
566 nSurround = css::text::WrapTextMode_RIGHT;
568 else if ( aWrapType == "topAndBottom" )
569 nSurround = css::text::WrapTextMode_NONE;
571 rPropSet.setProperty(PROP_Surround, static_cast<sal_Int32>(nSurround));
574 void lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
576 if ( rTypeModel.maPosition == "absolute" )
578 // Word supports as-character (inline) and at-character only, absolute can't be inline.
579 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER);
580 // anchor is set after insertion, so reset to NONE
581 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
583 if ( rTypeModel.maPositionVerticalRelative == "page" )
585 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
587 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
589 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
591 else
593 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
596 else if( rTypeModel.maPosition == "relative" )
597 { // I'm not very sure this is correct either.
598 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH);
599 // anchor is set after insertion, so reset to NONE
600 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::NONE));
602 else // static (is the default) means anchored inline
604 rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER);
605 // Use top orientation, this one seems similar to what MSO uses as inline
606 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
609 if ( rTypeModel.maPositionHorizontal == "center" )
610 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::CENTER));
611 else if ( rTypeModel.maPositionHorizontal == "left" )
612 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
613 else if ( rTypeModel.maPositionHorizontal == "right" )
614 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
615 else if ( rTypeModel.maPositionHorizontal == "inside" )
617 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::LEFT));
618 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
620 else if ( rTypeModel.maPositionHorizontal == "outside" )
622 rPropSet.setAnyProperty(PROP_HoriOrient, makeAny(text::HoriOrientation::RIGHT));
623 rPropSet.setAnyProperty(PROP_PageToggle, makeAny(true));
626 if ( rTypeModel.maPositionHorizontalRelative == "page" )
627 rPropSet.setAnyProperty(PROP_HoriOrientRelation, makeAny(text::RelOrientation::PAGE_FRAME));
628 else if ( rTypeModel.maPositionVerticalRelative == "margin" )
629 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
630 else if ( rTypeModel.maPositionVerticalRelative == "text" )
631 rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
633 if ( rTypeModel.maPositionVertical == "center" )
634 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::CENTER));
635 else if ( rTypeModel.maPositionVertical == "top" )
636 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::TOP));
637 else if ( rTypeModel.maPositionVertical == "bottom" )
638 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::BOTTOM));
639 else if ( rTypeModel.maPositionVertical == "inside" )
640 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_TOP));
641 else if ( rTypeModel.maPositionVertical == "outside" )
642 rPropSet.setAnyProperty(PROP_VertOrient, makeAny(text::VertOrientation::LINE_BOTTOM));
644 lcl_setSurround( rPropSet, rTypeModel, rGraphicHelper );
647 Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
649 awt::Rectangle aShapeRect(rShapeRect);
650 boost::optional<sal_Int32> oRotation;
651 bool bFlipX = false, bFlipY = false;
652 if (!maTypeModel.maRotation.isEmpty())
653 oRotation.reset(ConversionHelper::decodeRotation(maTypeModel.maRotation));
654 if (!maTypeModel.maFlip.isEmpty())
656 if (maTypeModel.maFlip == "x")
658 bFlipX = true;
660 else if (maTypeModel.maFlip == "y")
662 bFlipY = true;
666 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( maService, rxShapes, aShapeRect );
667 SdrObject* pShape = GetSdrObjectFromXShape( xShape );
668 if( pShape && getShapeType() >= 0 )
670 OUString aShapeType;
671 aShapeType = EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT >(getShapeType()) );
672 //The resize autoshape to fit text attr of FontWork/Word-Art should always be false
673 //for the fallback geometry.
674 if(aShapeType.startsWith("fontwork"))
676 pShape->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
677 pShape->SetMergedItem(makeSdrTextAutoGrowWidthItem(false));
680 convertShapeProperties( xShape );
682 // Handle left/right/top/bottom wrap distance.
683 // Default value of mso-wrap-distance-left/right is supposed to be 0 (see
684 // 19.1.2.19 of the VML spec), but Word implements a non-zero value.
685 // [MS-ODRAW] says the below default value in 2.3.4.9.
686 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
687 OUString aWrapDistanceLeft = OUString::number(0x0001BE7C);
688 if (!maTypeModel.maWrapDistanceLeft.isEmpty())
689 aWrapDistanceLeft = maTypeModel.maWrapDistanceLeft;
690 sal_Int32 nWrapDistanceLeft = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceLeft, 0, true, false);
691 PropertySet(xShape).setAnyProperty(PROP_LeftMargin, uno::makeAny(nWrapDistanceLeft));
692 OUString aWrapDistanceRight = OUString::number(0x0001BE7C);
693 if (!maTypeModel.maWrapDistanceRight.isEmpty())
694 aWrapDistanceRight = maTypeModel.maWrapDistanceRight;
695 sal_Int32 nWrapDistanceRight = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, aWrapDistanceRight, 0, true, false);
696 PropertySet(xShape).setAnyProperty(PROP_RightMargin, uno::makeAny(nWrapDistanceRight));
697 sal_Int32 nWrapDistanceTop = 0;
698 if (!maTypeModel.maWrapDistanceTop.isEmpty())
699 nWrapDistanceTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceTop, 0, false, true);
700 PropertySet(xShape).setAnyProperty(PROP_TopMargin, uno::makeAny(nWrapDistanceTop));
701 sal_Int32 nWrapDistanceBottom = 0;
702 if (!maTypeModel.maWrapDistanceBottom.isEmpty())
703 nWrapDistanceBottom = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maTypeModel.maWrapDistanceBottom, 0, false, true);
704 PropertySet(xShape).setAnyProperty(PROP_BottomMargin, uno::makeAny(nWrapDistanceBottom));
706 if ( maService == "com.sun.star.text.TextFrame" )
708 PropertySet( xShape ).setAnyProperty( PROP_FrameIsAutomaticHeight, makeAny( maTypeModel.mbAutoHeight ) );
709 PropertySet( xShape ).setAnyProperty( PROP_SizeType, makeAny( maTypeModel.mbAutoHeight ? SizeType::MIN : SizeType::FIX ) );
710 if( getTextBox()->borderDistanceSet )
712 PropertySet( xShape ).setAnyProperty( PROP_LeftBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceLeft )));
713 PropertySet( xShape ).setAnyProperty( PROP_TopBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceTop )));
714 PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceRight )));
715 PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceBottom )));
717 if (!maTypeModel.maLayoutFlowAlt.isEmpty())
719 // Can't handle this property here, as the frame is not attached yet: pass it to writerfilter.
720 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
721 uno::Sequence<beans::PropertyValue> aGrabBag;
722 xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
723 beans::PropertyValue aPair;
724 aPair.Name = "mso-layout-flow-alt";
725 aPair.Value <<= maTypeModel.maLayoutFlowAlt;
726 if (aGrabBag.hasElements())
728 sal_Int32 nLength = aGrabBag.getLength();
729 aGrabBag.realloc(nLength + 1);
730 aGrabBag[nLength] = aPair;
732 else
734 aGrabBag.realloc(1);
735 aGrabBag[0] = aPair;
737 xPropertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(aGrabBag));
740 else
742 // FIXME Setting the relative width/height only for everything but text frames as
743 // TextFrames already have relative width/height feature... but currently not working
744 // in the way we need.
746 // Set the relative width / height if any
747 if ( !maTypeModel.maWidthPercent.isEmpty( ) )
749 // Only page-relative width is supported ATM
750 if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
752 sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10;
753 // Only apply if nWidth != 0
754 if ( nWidth )
755 PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, makeAny( nWidth ) );
758 if ( !maTypeModel.maHeightPercent.isEmpty( ) )
760 // Only page-relative height is supported ATM
761 if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
763 sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10;
764 // Only apply if nHeight != 0
765 if ( nHeight )
766 PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, makeAny( nHeight ) );
770 // drawinglayer default is center, MSO default is top.
771 drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP;
772 if (maTypeModel.maVTextAnchor == "middle")
773 eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER;
774 else if (maTypeModel.maVTextAnchor == "bottom")
775 eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
776 PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, makeAny(eTextVerticalAdjust));
778 if (getTextBox())
780 getTextBox()->convert(xShape);
781 if (getTextBox()->borderDistanceSet)
783 awt::Size aSize = xShape->getSize();
784 PropertySet(xShape).setAnyProperty(PROP_TextLeftDistance, makeAny(sal_Int32(getTextBox()->borderDistanceLeft)));
785 PropertySet(xShape).setAnyProperty(PROP_TextUpperDistance, makeAny(sal_Int32(getTextBox()->borderDistanceTop)));
786 PropertySet(xShape).setAnyProperty(PROP_TextRightDistance, makeAny(sal_Int32(getTextBox()->borderDistanceRight)));
787 PropertySet(xShape).setAnyProperty(PROP_TextLowerDistance, makeAny(sal_Int32(getTextBox()->borderDistanceBottom)));
788 xShape->setSize(aSize);
793 // Import Legacy Fragments (if any)
794 if( xShape.is() && !maShapeModel.maLegacyDiagramPath.isEmpty() )
796 Reference< XInputStream > xInStrm( mrDrawing.getFilter().openInputStream( maShapeModel.maLegacyDiagramPath ), UNO_SET_THROW );
797 if( xInStrm.is() )
798 PropertySet( xShape ).setProperty( PROP_LegacyFragment, xInStrm );
801 PropertySet aPropertySet(xShape);
802 if (xShape.is())
804 if (oRotation)
806 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(*oRotation));
807 uno::Reference<lang::XServiceInfo> xServiceInfo(rxShapes, uno::UNO_QUERY);
808 if (!xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
810 // If rotation is used, simple setPosition() is not enough.
811 aPropertySet.setAnyProperty(PROP_HoriOrientPosition, makeAny(aShapeRect.X));
812 aPropertySet.setAnyProperty(PROP_VertOrientPosition, makeAny(aShapeRect.Y));
816 // custom shape geometry attributes
817 std::vector<css::beans::PropertyValue> aPropVec;
819 // When flip has 'x' or 'y', the associated ShapeRect will be changed but direction change doesn't occur.
820 // It might occur internally in SdrObject of "sw" module, not here.
821 // The associated properties "PROP_MirroredX" and "PROP_MirroredY" have to be set here so that direction change will occur internally.
822 if (bFlipX || bFlipY)
824 assert(!(bFlipX && bFlipY));
825 css::beans::PropertyValue aProp;
826 if (bFlipX)
827 aProp.Name = "MirroredX";
828 else
829 aProp.Name = "MirroredY";
830 aProp.Value <<= true;
831 aPropVec.push_back(aProp);
834 if (!maTypeModel.maAdjustments.isEmpty())
836 std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
837 sal_Int32 nIndex = 0;
840 OUString aToken = maTypeModel.maAdjustments.getToken(0, ',', nIndex);
841 drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue;
842 if (aToken.isEmpty())
843 aAdjustmentValue.State = css::beans::PropertyState::PropertyState_DEFAULT_VALUE;
844 else
845 aAdjustmentValue.Value <<= aToken.toInt32();
846 aAdjustmentValues.push_back(aAdjustmentValue);
847 } while (nIndex >= 0);
849 css::beans::PropertyValue aProp;
850 aProp.Name = "AdjustmentValues";
851 aProp.Value <<= comphelper::containerToSequence(aAdjustmentValues);
852 aPropVec.push_back(aProp);
855 if (!aPropVec.empty())
856 aPropertySet.setAnyProperty(PROP_CustomShapeGeometry, makeAny(comphelper::containerToSequence(aPropVec)));
859 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper );
861 return xShape;
864 Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
866 Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath);
867 return SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
870 Reference< XShape > SimpleShape::createPictureObject(const Reference< XShapes >& rxShapes,
871 const awt::Rectangle& rShapeRect,
872 uno::Reference<graphic::XGraphic> const & rxGraphic) const
874 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GraphicObjectShape", rxShapes, rShapeRect );
875 if( xShape.is() )
877 PropertySet aPropSet(xShape);
878 if (rxGraphic.is())
880 aPropSet.setProperty(PROP_Graphic, rxGraphic);
882 uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY);
883 // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape.
884 if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
886 aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
887 aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
888 aPropSet.setProperty(PROP_Opaque, false);
890 // fdo#70457: preserve rotation information
891 if ( !maTypeModel.maRotation.isEmpty() )
892 aPropSet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
894 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
895 lcl_SetAnchorType(aPropSet, maTypeModel, rGraphicHelper);
897 if (maTypeModel.moCropBottom.has() || maTypeModel.moCropLeft.has() || maTypeModel.moCropRight.has() || maTypeModel.moCropTop.has())
899 text::GraphicCrop aGraphicCrop;
900 awt::Size aOriginalSize = rGraphicHelper.getOriginalSize(rxGraphic);
902 if (maTypeModel.moCropBottom.has())
903 aGraphicCrop.Bottom = lclConvertCrop(maTypeModel.moCropBottom.get(), aOriginalSize.Height);
904 if (maTypeModel.moCropLeft.has())
905 aGraphicCrop.Left = lclConvertCrop(maTypeModel.moCropLeft.get(), aOriginalSize.Width);
906 if (maTypeModel.moCropRight.has())
907 aGraphicCrop.Right = lclConvertCrop(maTypeModel.moCropRight.get(), aOriginalSize.Width);
908 if (maTypeModel.moCropTop.has())
909 aGraphicCrop.Top = lclConvertCrop(maTypeModel.moCropTop.get(), aOriginalSize.Height);
911 aPropSet.setProperty(PROP_GraphicCrop, aGraphicCrop);
914 return xShape;
917 RectangleShape::RectangleShape( Drawing& rDrawing ) :
918 SimpleShape( rDrawing, "com.sun.star.drawing.RectangleShape" )
922 Reference<XShape> RectangleShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
924 OUString aGraphicPath = getGraphicPath();
926 // try to create a picture object
927 if(!aGraphicPath.isEmpty())
928 return SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
930 // default: try to create a rectangle shape
931 Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect);
932 OUString sArcsize = maTypeModel.maArcsize;
933 if ( !sArcsize.isEmpty( ) )
935 sal_Unicode cLastChar = sArcsize[sArcsize.getLength() - 1];
936 sal_Int32 nValue = sArcsize.copy( 0, sArcsize.getLength() - 1 ).toInt32( );
937 // Get the smallest half-side
938 double size = std::min( rShapeRect.Height, rShapeRect.Width ) / 2.0;
939 sal_Int32 nRadius = 0;
940 if ( cLastChar == 'f' )
941 nRadius = size * nValue / 65536;
942 else if ( cLastChar == '%' )
943 nRadius = size * nValue / 100;
944 PropertySet( xShape ).setAnyProperty( PROP_CornerRadius, makeAny( nRadius ) );
946 return xShape;
949 EllipseShape::EllipseShape( Drawing& rDrawing ) :
950 SimpleShape( rDrawing, "com.sun.star.drawing.EllipseShape" )
954 PolyLineShape::PolyLineShape( Drawing& rDrawing ) :
955 SimpleShape( rDrawing, "com.sun.star.drawing.PolyLineShape" )
959 Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
961 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
962 // polygon path
963 awt::Rectangle aCoordSys = getCoordSystem();
964 if( !maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
966 ::std::vector< awt::Point > aAbsPoints;
967 for (auto const& point : maShapeModel.maPoints)
968 aAbsPoints.push_back( lclGetAbsPoint( point, rShapeRect, aCoordSys ) );
969 PointSequenceSequence aPointSeq( 1 );
970 aPointSeq[ 0 ] = ContainerHelper::vectorToSequence( aAbsPoints );
971 PropertySet aPropSet( xShape );
972 aPropSet.setProperty( PROP_PolyPolygon, aPointSeq );
974 return xShape;
977 LineShape::LineShape(Drawing& rDrawing)
978 : SimpleShape(rDrawing, "com.sun.star.drawing.LineShape")
982 awt::Rectangle LineShape::getAbsRectangle() const
984 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
985 awt::Rectangle aShapeRect;
986 sal_Int32 nIndex = 0;
988 aShapeRect.X = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, true, true);
989 aShapeRect.Y = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maFrom.getToken(0, ',', nIndex), 0, false, true);
990 nIndex = 0;
991 aShapeRect.Width = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, true, true) - aShapeRect.X;
992 aShapeRect.Height = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, maShapeModel.maTo.getToken(0, ',', nIndex), 0, false, true) - aShapeRect.Y;
993 return aShapeRect;
996 awt::Rectangle LineShape::getRelRectangle() const
998 awt::Rectangle aShapeRect;
999 sal_Int32 nIndex = 0;
1001 aShapeRect.X = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1002 aShapeRect.Y = maShapeModel.maFrom.getToken(0, ',', nIndex).toInt32();
1003 nIndex = 0;
1004 aShapeRect.Width = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.X;
1005 aShapeRect.Height = maShapeModel.maTo.getToken(0, ',', nIndex).toInt32() - aShapeRect.Y;
1006 return aShapeRect;
1009 BezierShape::BezierShape(Drawing& rDrawing)
1010 : SimpleShape(rDrawing, "com.sun.star.drawing.OpenBezierShape")
1014 Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1016 // If we have an 'x' in the last part of the path it means it is closed...
1017 sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(',');
1018 if ( nPos != -1 && maShapeModel.maVmlPath.indexOf('x', nPos) != -1 )
1020 const_cast<BezierShape*>( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1023 awt::Rectangle aCoordSys = getCoordSystem();
1024 PolyPolygonBezierCoords aBezierCoords;
1026 if( (aCoordSys.Width > 0) && (aCoordSys.Height > 0) )
1028 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1030 // Bezier paths may consist of one or more sub-paths
1031 typedef ::std::vector< ::std::vector< awt::Point > > SubPathList;
1032 typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
1033 SubPathList aCoordLists;
1034 FlagsList aFlagLists;
1035 sal_Int32 nIndex = 0;
1037 // Curve defined by to, from, control1 and control2 attributes
1038 if ( maShapeModel.maVmlPath.isEmpty() )
1040 aCoordLists.emplace_back( );
1041 aFlagLists.emplace_back( );
1043 // Start point
1044 aCoordLists[ 0 ].emplace_back(
1045 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, true, true ),
1046 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maFrom.getToken( 0, ',', nIndex ), 0, false, true ) );
1047 // Control point 1
1048 aCoordLists[ 0 ].emplace_back(
1049 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, true, true ),
1050 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl1.getToken( 0, ',', nIndex ), 0, false, true ) );
1051 // Control point 2
1052 aCoordLists[ 0 ].emplace_back(
1053 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, true, true ),
1054 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maControl2.getToken( 0, ',', nIndex ), 0, false, true ) );
1055 // End point
1056 aCoordLists[ 0 ].emplace_back(
1057 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, true, true ),
1058 ConversionHelper::decodeMeasureToHmm( rGraphicHelper, maShapeModel.maTo.getToken( 0, ',', nIndex ), 0, false, true ) );
1060 // First and last points are normals, points 2 and 4 are controls
1061 aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
1062 aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
1063 aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
1065 // Curve defined by path attribute
1066 else
1068 // Parse VML path string and convert to absolute coordinates
1069 ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
1071 for (auto & coordList : aCoordLists)
1072 for (auto & point : coordList)
1074 point = lclGetAbsPoint( point, rShapeRect, aCoordSys );
1078 aBezierCoords.Coordinates.realloc( aCoordLists.size() );
1079 for ( size_t i = 0; i < aCoordLists.size(); i++ )
1080 aBezierCoords.Coordinates[i] = ContainerHelper::vectorToSequence( aCoordLists[i] );
1082 aBezierCoords.Flags.realloc( aFlagLists.size() );
1083 for ( size_t i = 0; i < aFlagLists.size(); i++ )
1084 aBezierCoords.Flags[i] = ContainerHelper::vectorToSequence( aFlagLists[i] );
1086 if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
1087 && aCoordLists.front().front().X == aCoordLists.back().back().X
1088 && aCoordLists.front().front().Y == aCoordLists.back().back().Y )
1089 { // HACK: If the shape is in fact closed, which can be found out only when the path is known,
1090 // force to closed bezier shape (otherwise e.g. fill won't work).
1091 const_cast< BezierShape* >( this )->setService( "com.sun.star.drawing.ClosedBezierShape" );
1095 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1097 if( aBezierCoords.Coordinates.hasElements())
1099 PropertySet aPropSet( xShape );
1100 aPropSet.setProperty( PROP_PolyPolygonBezier, aBezierCoords );
1103 // Handle horizontal and vertical flip.
1104 if (!maTypeModel.maFlip.isEmpty())
1106 if (SdrObject* pShape = GetSdrObjectFromXShape(xShape))
1108 if (maTypeModel.maFlip.startsWith("x"))
1110 Point aCenter(pShape->GetSnapRect().Center());
1111 Point aPoint2(aCenter);
1112 aPoint2.setY(aPoint2.getY() + 1);
1113 pShape->NbcMirror(aCenter, aPoint2);
1115 if (maTypeModel.maFlip.endsWith("y"))
1117 Point aCenter(pShape->GetSnapRect().Center());
1118 Point aPoint2(aCenter);
1119 aPoint2.setX(aPoint2.getX() + 1);
1120 pShape->NbcMirror(aCenter, aPoint2);
1125 // Hacky way of ensuring the shape is correctly sized/positioned
1128 // E.g. SwXFrame::setPosition() unconditionally throws
1129 xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
1130 xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
1132 catch (const ::css::uno::Exception&)
1134 // TODO: try some other way to ensure size/position
1136 return xShape;
1139 CustomShape::CustomShape( Drawing& rDrawing ) :
1140 SimpleShape( rDrawing, "com.sun.star.drawing.CustomShape" )
1144 Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1146 // try to create a custom shape
1147 Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
1148 if( xShape.is() ) try
1150 // create the custom shape geometry
1151 Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
1152 xDefaulter->createCustomShapeDefaults( OUString::number( getShapeType() ) );
1153 // convert common properties
1154 convertShapeProperties( xShape );
1156 catch( Exception& )
1159 return xShape;
1162 ComplexShape::ComplexShape( Drawing& rDrawing ) :
1163 CustomShape( rDrawing )
1167 Reference< XShape > ComplexShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1169 XmlFilterBase& rFilter = mrDrawing.getFilter();
1170 sal_Int32 nShapeType = getShapeType();
1171 OUString aGraphicPath = getGraphicPath();
1173 // try to find registered OLE object info
1174 if( const OleObjectInfo* pOleObjectInfo = mrDrawing.getOleObjectInfo( maTypeModel.maShapeId ) )
1176 SAL_WARN_IF(
1177 nShapeType != VML_SHAPETYPE_PICTUREFRAME, "oox",
1178 "ComplexShape::implConvertAndInsert - unexpected shape type");
1180 // if OLE object is embedded into a DrawingML shape (PPTX), do not create it here
1181 if( pOleObjectInfo->mbDmlShape )
1182 return Reference< XShape >();
1184 PropertyMap aOleProps;
1185 awt::Size aOleSize( rShapeRect.Width, rShapeRect.Height );
1186 if( rFilter.getOleObjectHelper().importOleObject( aOleProps, *pOleObjectInfo, aOleSize ) )
1188 Reference< XShape > xShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.OLE2Shape", rxShapes, rShapeRect );
1189 if( xShape.is() )
1191 // set the replacement graphic
1192 if( !aGraphicPath.isEmpty() )
1194 WmfExternal aExtHeader;
1195 aExtHeader.mapMode = 8;
1196 aExtHeader.xExt = rShapeRect.Width;
1197 aExtHeader.yExt = rShapeRect.Height;
1199 Reference< XGraphic > xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath, &aExtHeader);
1200 if (xGraphic.is())
1201 aOleProps.setProperty( PROP_Graphic, xGraphic);
1204 PropertySet aPropSet( xShape );
1205 aPropSet.setProperties( aOleProps );
1207 return xShape;
1212 // try to find registered form control info
1213 const ControlInfo* pControlInfo = mrDrawing.getControlInfo( maTypeModel.maShapeId );
1214 if( pControlInfo && !pControlInfo->maFragmentPath.isEmpty() )
1216 if( !pControlInfo->maName.isEmpty() )
1218 // load the control properties from fragment
1219 ::oox::ole::EmbeddedControl aControl(pControlInfo->maName);
1220 if( rFilter.importFragment( new ::oox::ole::AxControlFragment( rFilter, pControlInfo->maFragmentPath, aControl ) ) )
1222 // create and return the control shape (including control model)
1223 sal_Int32 nCtrlIndex = -1;
1224 Reference< XShape > xShape = mrDrawing.createAndInsertXControlShape( aControl, rxShapes, rShapeRect, nCtrlIndex );
1226 if (pControlInfo->mbTextContentShape)
1228 PropertySet aPropertySet(xShape);
1229 lcl_SetAnchorType(aPropertySet, maTypeModel, mrDrawing.getFilter().getGraphicHelper());
1231 // on error, proceed and try to create picture from replacement image
1232 if( xShape.is() )
1233 return xShape;
1238 // host application wants to create the shape (do not try failed OLE controls again)
1239 if( (nShapeType == VML_SHAPETYPE_HOSTCONTROL) && !pControlInfo )
1241 OSL_ENSURE( getClientData(), "ComplexShape::implConvertAndInsert - missing client data" );
1242 Reference< XShape > xShape = mrDrawing.createAndInsertClientXShape( *this, rxShapes, rShapeRect );
1243 if( xShape.is() )
1244 return xShape;
1248 if( getShapeModel().mbIsSignatureLine )
1250 uno::Reference<graphic::XGraphic> xGraphic;
1253 // Get the document signatures
1254 Reference<security::XDocumentDigitalSignatures> xSignatures(
1255 security::DocumentDigitalSignatures::createWithVersion(
1256 comphelper::getProcessComponentContext(), "1.2"));
1258 uno::Reference<embed::XStorage> xStorage
1259 = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
1260 ZIP_STORAGE_FORMAT_STRING, mrDrawing.getFilter().getFileUrl(),
1261 embed::ElementModes::READ);
1262 SAL_WARN_IF(!xStorage.is(), "oox.vml", "No xStorage!");
1264 uno::Sequence<security::DocumentSignatureInformation> xSignatureInfo
1265 = xSignatures->verifyScriptingContentSignatures(xStorage,
1266 uno::Reference<io::XInputStream>());
1268 for (int i = 0; i < xSignatureInfo.getLength(); i++)
1270 // Try to find matching signature line image - if none exists that is fine,
1271 // then the signature line is not digitally signed.
1272 if (xSignatureInfo[i].SignatureLineId == getShapeModel().maSignatureId)
1274 if (xSignatureInfo[i].SignatureIsValid)
1276 // Signature is valid, use the 'valid' image
1277 SAL_WARN_IF(!xSignatureInfo[i].ValidSignatureLineImage.is(), "oox.vml",
1278 "No ValidSignatureLineImage!");
1279 xGraphic = xSignatureInfo[i].ValidSignatureLineImage;
1281 else
1283 // Signature is invalid, use the 'invalid' image
1284 SAL_WARN_IF(!xSignatureInfo[i].InvalidSignatureLineImage.is(), "oox.vml",
1285 "No InvalidSignatureLineImage!");
1286 xGraphic = xSignatureInfo[i].InvalidSignatureLineImage;
1288 break;
1292 catch (css::uno::Exception&)
1294 // DocumentDigitalSignatures service not available.
1295 // We continue by rendering the "unsigned" shape instead.
1298 Reference< XShape > xShape;
1299 if (xGraphic.is())
1301 // If available, use the signed image from the signature
1302 xShape = SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
1304 else
1306 // Create shape with the fallback "unsigned" image
1307 xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1310 // Store signature line properties
1311 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1312 xPropertySet->setPropertyValue("IsSignatureLine", uno::makeAny(true));
1313 xPropertySet->setPropertyValue("SignatureLineId",
1314 uno::makeAny(getShapeModel().maSignatureId));
1315 xPropertySet->setPropertyValue(
1316 "SignatureLineSuggestedSignerName",
1317 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerName));
1318 xPropertySet->setPropertyValue(
1319 "SignatureLineSuggestedSignerTitle",
1320 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerTitle));
1321 xPropertySet->setPropertyValue(
1322 "SignatureLineSuggestedSignerEmail",
1323 uno::makeAny(getShapeModel().maSignatureLineSuggestedSignerEmail));
1324 xPropertySet->setPropertyValue(
1325 "SignatureLineSigningInstructions",
1326 uno::makeAny(getShapeModel().maSignatureLineSigningInstructions));
1327 xPropertySet->setPropertyValue(
1328 "SignatureLineShowSignDate",
1329 uno::makeAny(getShapeModel().mbSignatureLineShowSignDate));
1330 xPropertySet->setPropertyValue(
1331 "SignatureLineCanAddComment",
1332 uno::makeAny(getShapeModel().mbSignatureLineCanAddComment));
1334 if (!aGraphicPath.isEmpty())
1336 xGraphic = rFilter.getGraphicHelper().importEmbeddedGraphic(aGraphicPath);
1337 xPropertySet->setPropertyValue("SignatureLineUnsignedImage", uno::makeAny(xGraphic));
1339 return xShape;
1342 // try to create a picture object
1343 if( !aGraphicPath.isEmpty() )
1345 Reference<XShape> xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
1346 // AS_CHARACTER shape: vertical orientation default is bottom, MSO default is top.
1347 if ( maTypeModel.maPosition != "absolute" && maTypeModel.maPosition != "relative" )
1348 PropertySet( xShape ).setAnyProperty( PROP_VertOrient, makeAny(text::VertOrientation::TOP));
1349 return xShape;
1352 // default: try to create a custom shape
1353 return CustomShape::implConvertAndInsert( rxShapes, rShapeRect );
1356 GroupShape::GroupShape( Drawing& rDrawing ) :
1357 ShapeBase( rDrawing ),
1358 mxChildren( new ShapeContainer( rDrawing ) )
1362 GroupShape::~GroupShape()
1366 void GroupShape::finalizeFragmentImport()
1368 // basic shape processing
1369 ShapeBase::finalizeFragmentImport();
1370 // finalize all child shapes
1371 mxChildren->finalizeFragmentImport();
1374 const ShapeType* GroupShape::getChildTypeById( const OUString& rShapeId ) const
1376 return mxChildren->getShapeTypeById( rShapeId );
1379 const ShapeBase* GroupShape::getChildById( const OUString& rShapeId ) const
1381 return mxChildren->getShapeById( rShapeId );
1384 Reference< XShape > GroupShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
1386 Reference< XShape > xGroupShape;
1387 // check that this shape contains children and a valid coordinate system
1388 ShapeParentAnchor aParentAnchor;
1389 aParentAnchor.maShapeRect = rShapeRect;
1390 aParentAnchor.maCoordSys = getCoordSystem();
1391 if( !mxChildren->empty() && (aParentAnchor.maCoordSys.Width > 0) && (aParentAnchor.maCoordSys.Height > 0) ) try
1393 xGroupShape = mrDrawing.createAndInsertXShape( "com.sun.star.drawing.GroupShape", rxShapes, rShapeRect );
1394 Reference< XShapes > xChildShapes( xGroupShape, UNO_QUERY_THROW );
1395 mxChildren->convertAndInsert( xChildShapes, &aParentAnchor );
1396 if( !xChildShapes->hasElements() )
1398 SAL_WARN("oox", "no child shape has been created - deleting the group shape");
1399 rxShapes->remove( xGroupShape );
1400 xGroupShape.clear();
1403 catch( Exception& )
1407 uno::Reference<beans::XPropertySet> xPropertySet;
1408 if (!maTypeModel.maEditAs.isEmpty())
1409 xPropertySet = uno::Reference<beans::XPropertySet>(xGroupShape, uno::UNO_QUERY);
1410 if (xPropertySet.is())
1412 uno::Sequence<beans::PropertyValue> aGrabBag;
1413 xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
1414 beans::PropertyValue aPair;
1415 aPair.Name = "mso-edit-as";
1416 aPair.Value <<= maTypeModel.maEditAs;
1417 if (aGrabBag.hasElements())
1419 sal_Int32 nLength = aGrabBag.getLength();
1420 aGrabBag.realloc(nLength + 1);
1421 aGrabBag[nLength] = aPair;
1423 else
1425 aGrabBag.realloc(1);
1426 aGrabBag[0] = aPair;
1428 xPropertySet->setPropertyValue("InteropGrabBag", uno::makeAny(aGrabBag));
1430 // Make sure group shapes are inline as well, unless there is an explicit different style.
1431 PropertySet aPropertySet(xGroupShape);
1432 const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper();
1433 lcl_SetAnchorType(aPropertySet, maTypeModel, rGraphicHelper);
1434 if (!maTypeModel.maRotation.isEmpty())
1435 aPropertySet.setAnyProperty(PROP_RotateAngle, makeAny(ConversionHelper::decodeRotation(maTypeModel.maRotation)));
1436 return xGroupShape;
1439 } // namespace vml
1440 } // namespace oox
1442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */