1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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
;
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
;
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 );
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 );
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;
140 ShapeTypeModel::ShapeTypeModel():
141 mbAutoHeight( false ),
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
) :
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 );
204 sal_Int32 nHeight
= ConversionHelper::decodeMeasureToHmm( rGraphicHelper
, maTypeModel
.maHeight
, 0, false, true );
209 if (o3tl::checked_add
<sal_Int32
>(ConversionHelper::decodeMeasureToHmm(rGraphicHelper
, maTypeModel
.maLeft
, 0, true, true),
210 ConversionHelper::decodeMeasureToHmm(rGraphicHelper
, maTypeModel
.maMarginLeft
, 0, true, true),
213 SAL_WARN("oox", "overflow in addition");
216 if (nLeft
== 0 && maTypeModel
.maPosition
== "absolute")
219 return awt::Rectangle(
221 ConversionHelper::decodeMeasureToHmm( rGraphicHelper
, maTypeModel
.maTop
, 0, false, true ) + ConversionHelper::decodeMeasureToHmm( rGraphicHelper
, maTypeModel
.maMarginTop
, 0, false, true ),
225 awt::Rectangle
ShapeType::getRelRectangle() const
227 sal_Int32 nWidth
= maTypeModel
.maWidth
.toInt32();
231 sal_Int32 nHeight
= maTypeModel
.maHeight
.toInt32();
235 return awt::Rectangle(
236 maTypeModel
.maLeft
.toInt32(),
237 maTypeModel
.maTop
.toInt32(),
241 ClientData::ClientData() :
242 mnObjType( XML_TOKEN_INVALID
),
243 mnTextHAlign( XML_Left
),
244 mnTextVAlign( XML_Top
),
247 mnChecked( VML_CLIENTDATA_UNCHECKED
),
248 mnDropStyle( XML_Combo
),
255 mnSelType( XML_Single
),
256 mnVTEdit( VML_CLIENTDATA_TEXT
),
257 mbPrintObject( true ),
262 mbMultiLine( 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
) );
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() );
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() );
326 return aBaseName
+ OUStringLiteral1(' ') + OUString::number( nShapeIdx
);
332 const ShapeType
* ShapeBase::getChildTypeById( const OUString
& ) const
337 const ShapeBase
* ShapeBase::getChildById( const OUString
& ) const
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
);
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
;
364 sal_Int32 idPos
= sLinkChainName
.indexOf("_x");
368 sal_Int32 seqPos
= sLinkChainName
.indexOf("_s",idPos
);
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
;
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)));
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
;
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
);
467 SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
472 void ShapeBase::convertFormatting( const Reference
< XShape
>& rxShape
) const
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
);
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
>();
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.
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
);
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")
672 else if (maTypeModel
.maFlip
== "y")
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
;
748 xPropertySet
->setPropertyValue("FrameInteropGrabBag", uno::makeAny(aGrabBag
));
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
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
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
));
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
);
809 PropertySet( xShape
).setProperty( PROP_LegacyFragment
, xInStrm
);
812 PropertySet
aPropertySet(xShape
);
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
;
838 aProp
.Name
= "MirroredX";
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
;
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
);
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
);
888 PropertySet
aPropSet(xShape
);
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
);
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
) );
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
);
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
);
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);
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
;
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();
1015 aShapeRect
.Width
= maShapeModel
.maTo
.getToken(0, ',', nIndex
).toInt32() - aShapeRect
.X
;
1016 aShapeRect
.Height
= maShapeModel
.maTo
.getToken(0, ',', nIndex
).toInt32() - aShapeRect
.Y
;
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( );
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 ) );
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 ) );
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 ) );
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
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
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
);
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
) )
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
);
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
);
1212 aOleProps
.setProperty( PROP_Graphic
, xGraphic
);
1215 PropertySet
aPropSet( xShape
);
1216 aPropSet
.setProperties( aOleProps
);
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
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
);
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
)
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
;
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
;
1305 catch (css::uno::Exception
&)
1307 // DocumentDigitalSignatures service not available.
1308 // We continue by rendering the "unsigned" shape instead.
1311 Reference
< XShape
> xShape
;
1314 // If available, use the signed image from the signature
1315 xShape
= SimpleShape::createPictureObject(rxShapes
, rShapeRect
, xGraphic
);
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
));
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
));
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();
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
;
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
)));
1456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */