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 .
21 #include "eschesdo.hxx"
22 #include <o3tl/any.hxx>
23 #include <svx/svdobj.hxx>
24 #include <tools/poly.hxx>
25 #include <tools/debug.hxx>
26 #include <comphelper/diagnose_ex.hxx>
27 #include <svx/fmdpage.hxx>
28 #include <com/sun/star/awt/Rectangle.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <com/sun/star/beans/XPropertySetInfo.hpp>
32 #include <com/sun/star/text/XText.hpp>
33 #include <com/sun/star/text/TextContentAnchorType.hpp>
34 #include <com/sun/star/drawing/CircleKind.hpp>
35 #include <com/sun/star/drawing/FillStyle.hpp>
36 #include <comphelper/extract.hxx>
37 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
38 #include <basegfx/matrix/b2dhommatrix.hxx>
40 using namespace ::com::sun::star
;
41 using namespace ::com::sun::star::beans
;
42 using namespace ::com::sun::star::container
;
43 using namespace ::com::sun::star::uno
;
44 using namespace ::com::sun::star::drawing
;
45 using namespace ::com::sun::star::text
;
46 using namespace ::com::sun::star::task
;
48 constexpr o3tl::Length
geUnitsSrc(o3tl::Length::mm100
);
49 // PowerPoint: 576 dpi, WinWord: 1440 dpi, Excel: 1440 dpi
50 constexpr o3tl::Length
geUnitsDest(o3tl::Length::twip
);
52 ImplEESdrWriter::ImplEESdrWriter( EscherEx
& rEx
)
55 , mpHostAppData(nullptr)
56 , mbIsTitlePossible(false)
57 , mpSdrPage( nullptr )
63 Point
ImplEESdrWriter::ImplMapPoint( const Point
& rPoint
)
65 return o3tl::convert( rPoint
, geUnitsSrc
, geUnitsDest
);
68 Size
ImplEESdrWriter::ImplMapSize( const Size
& rSize
)
70 Size
aRetSize( o3tl::convert( rSize
, geUnitsSrc
, geUnitsDest
) );
72 if ( !aRetSize
.Width() )
73 aRetSize
.AdjustWidth( 1 );
74 if ( !aRetSize
.Height() )
75 aRetSize
.AdjustHeight( 1 );
79 void ImplEESdrWriter::ImplFlipBoundingBox( ImplEESdrObject
& rObj
, EscherPropertyContainer
& rPropOpt
)
81 sal_Int32 nAngle
= rObj
.GetAngle();
82 tools::Rectangle
aRect( rObj
.GetRect() );
84 // for position calculations, we normalize the angle between 0 and 90 degrees
86 nAngle
= ( 36000 + nAngle
) % 36000;
87 if ( nAngle
% 18000 == 0 )
89 while ( nAngle
> 9000 )
90 nAngle
= ( 18000 - ( nAngle
% 18000 ) );
92 double fVal
= basegfx::deg2rad
<100>(nAngle
);
93 double fCos
= cos( fVal
);
94 double fSin
= sin( fVal
);
96 double nWidthHalf
= static_cast<double>(aRect
.GetWidth()) / 2;
97 double nHeightHalf
= static_cast<double>(aRect
.GetHeight()) / 2;
100 // when you rotate an object, the top-left corner of its bounding box is moved
101 // nXDiff and nYDiff pixels. To get their values we use these equations:
103 // fSin * nHeightHalf + fCos * nWidthHalf == nXDiff + nWidthHalf
104 // fSin * nWidthHalf + fCos * nHeightHalf == nYDiff + nHeightHalf
106 double nXDiff
= fSin
* nHeightHalf
+ fCos
* nWidthHalf
- nWidthHalf
;
107 double nYDiff
= fSin
* nWidthHalf
+ fCos
* nHeightHalf
- nHeightHalf
;
109 aRect
.Move( static_cast<sal_Int32
>(nXDiff
), static_cast<sal_Int32
>(nYDiff
) );
111 // calculate the proper angle value to be saved
112 nAngle
= rObj
.GetAngle();
114 nAngle
= ( 36000 + nAngle
) % 36000;
116 nAngle
= ( 36000 - ( nAngle
% 36000 ) );
120 nAngle
&=~0xffff; // nAngle round to full degrees
121 rPropOpt
.AddOpt( ESCHER_Prop_Rotation
, nAngle
);
123 rObj
.SetAngle( nAngle
);
124 rObj
.SetRect( aRect
);
128 sal_uInt32
ImplEESdrWriter::ImplWriteShape( ImplEESdrObject
& rObj
,
129 EscherSolverContainer
& rSolverContainer
,
130 const bool bOOxmlExport
)
132 sal_uInt32 nShapeID
= 0;
133 sal_uInt16 nShapeType
= 0;
134 bool bDontWriteText
= false; // if a metafile is written as shape replacement, then the text is already part of the metafile
135 bool bAdditionalText
= false;
136 sal_uInt32 nGrpShapeID
= 0;
137 auto addShape
= [this, &rObj
, &rSolverContainer
, &nShapeID
, &nShapeType
](sal_uInt16 nType
, ShapeFlag nFlags
)
140 nShapeID
= mpEscherEx
->GenerateShapeId();
141 rObj
.SetShapeId( nShapeID
);
142 mpEscherEx
->AddShape( nType
, nFlags
, nShapeID
);
143 rSolverContainer
.AddShape( rObj
.GetShapeRef(), nShapeID
);
147 mpHostAppData
= mpEscherEx
->StartShape( rObj
.GetShapeRef(), (mpEscherEx
->GetGroupLevel() > 1) ? &rObj
.GetRect() : nullptr );
148 if ( mpHostAppData
&& mpHostAppData
->DontWriteShape() )
151 // #i51348# get shape name
153 if( const SdrObject
* pSdrObj
= rObj
.GetSdrObject() )
154 if (!pSdrObj
->GetName().isEmpty())
155 aShapeName
= pSdrObj
->GetName();
156 uno::Reference
< drawing::XShape
> xShape
= rObj
.GetShapeRef();
159 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, uno::UNO_QUERY
);
160 if (xPropertySet
.is())
162 uno::Sequence
<beans::PropertyValue
> aGrabBag
;
163 uno::Reference
< XPropertySetInfo
> xPropInfo
= xPropertySet
->getPropertySetInfo();
164 if ( xPropInfo
.is() && xPropInfo
->hasPropertyByName( "InteropGrabBag" ) )
166 xPropertySet
->getPropertyValue( "InteropGrabBag" ) >>= aGrabBag
;
167 for (const beans::PropertyValue
& rProp
: std::as_const(aGrabBag
))
169 if (rProp
.Name
== "mso-edit-as")
172 rProp
.Value
>>= rEditAs
;
173 mpEscherEx
->SetEditAs(rEditAs
);
181 if( rObj
.GetType() == "drawing.Group" )
183 Reference
< XIndexAccess
> xXIndexAccess( rObj
.GetShapeRef(), UNO_QUERY
);
185 if( xXIndexAccess
.is() && 0 != xXIndexAccess
->getCount() )
187 nShapeID
= mpEscherEx
->EnterGroup( aShapeName
, &rObj
.GetRect() );
188 nShapeType
= ESCHER_ShpInst_Min
;
190 for( sal_uInt32 n
= 0, nCnt
= xXIndexAccess
->getCount();
193 ImplEESdrObject
aObj( *o3tl::doAccess
<Reference
<XShape
>>(
194 xXIndexAccess
->getByIndex( n
)) );
197 aObj
.SetOOXML(bOOxmlExport
);
198 ImplWriteShape( aObj
, rSolverContainer
, bOOxmlExport
);
201 mpEscherEx
->LeaveGroup();
205 rObj
.SetAngle( rObj
.ImplGetInt32PropertyValue( "RotateAngle" ));
207 if( ( rObj
.ImplGetPropertyValue( "IsFontwork" ) &&
208 ::cppu::any2bool( rObj
.GetUsrAny() ) ) ||
209 rObj
.GetType() == "drawing.Measure" )
211 rObj
.SetType("drawing.dontknow");
214 const css::awt::Size
aSize100thmm( rObj
.GetShapeRef()->getSize() );
215 const css::awt::Point
aPoint100thmm( rObj
.GetShapeRef()->getPosition() );
216 tools::Rectangle
aRect100thmm( Point( aPoint100thmm
.X
, aPoint100thmm
.Y
), Size( aSize100thmm
.Width
, aSize100thmm
.Height
) );
218 mpPicStrm
= mpEscherEx
->QueryPictureStream();
219 EscherPropertyContainer
aPropOpt( mpEscherEx
->GetGraphicProvider(), mpPicStrm
, aRect100thmm
);
221 // #i51348# shape name
222 if (!aShapeName
.isEmpty())
223 aPropOpt
.AddOpt( ESCHER_Prop_wzName
, aShapeName
);
224 if ( InteractionInfo
* pInteraction
= mpHostAppData
? mpHostAppData
->GetInteractionInfo():nullptr )
226 const std::unique_ptr
< SvMemoryStream
>& pMemStrm
= pInteraction
->getHyperlinkRecord();
229 aPropOpt
.AddOpt(ESCHER_Prop_pihlShape
, false, 0, *pMemStrm
);
231 aPropOpt
.AddOpt( ESCHER_Prop_fPrint
, 0x00080008 );
234 if ( rObj
.GetType() == "drawing.Custom" )
236 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
237 ShapeFlag nMirrorFlags
;
239 OUString sCustomShapeType
;
240 MSO_SPT eShapeType
= EscherPropertyContainer::GetCustomShapeType( rObj
.GetShapeRef(), nMirrorFlags
, sCustomShapeType
, rObj
.GetOOXML() );
241 if ( sCustomShapeType
== "col-502ad400" || sCustomShapeType
== "col-60da8460" )
243 addShape( ESCHER_ShpInst_PictureFrame
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
245 if ( aPropOpt
.CreateGraphicProperties( rObj
.mXPropSet
, "MetaFile", false ) )
247 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x800080 );
248 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100000 ); // no fill
249 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x90000 ); // no linestyle
250 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(rObj
.GetShapeRef());
253 tools::Rectangle aBound
= pObj
->GetCurrentBoundRect();
254 Point
aPosition( ImplMapPoint( aBound
.TopLeft() ) );
255 Size
aSize( ImplMapSize( aBound
.GetSize() ) );
256 rObj
.SetRect( tools::Rectangle( aPosition
, aSize
) );
258 bDontWriteText
= true;
264 const Reference
< XPropertySet
> xPropSet
= rObj
.mXPropSet
;
265 drawing::FillStyle eFS
= drawing::FillStyle_NONE
;
268 uno::Reference
< XPropertySetInfo
> xPropInfo
= xPropSet
->getPropertySetInfo();
269 if ( xPropInfo
.is() && xPropInfo
->hasPropertyByName("FillStyle"))
270 xPropSet
->getPropertyValue("FillStyle") >>= eFS
;
273 if (eFS
== drawing::FillStyle_BITMAP
&& eShapeType
== mso_sptMax
)
275 // We can't map this custom shape to a DOC preset and it has a bitmap fill.
276 // Make sure that at least the bitmap fill is not lost.
277 addShape( ESCHER_ShpInst_PictureFrame
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
278 if ( aPropOpt
.CreateGraphicProperties( rObj
.mXPropSet
, "Bitmap", false, true, true, bOOxmlExport
) )
279 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x800080 );
283 addShape(sal::static_int_cast
< sal_uInt16
>(eShapeType
),
284 nMirrorFlags
| ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
285 aPropOpt
.CreateCustomShapeProperties( eShapeType
, rObj
.GetShapeRef() );
286 aPropOpt
.CreateFillProperties( rObj
.mXPropSet
, true );
287 if ( rObj
.ImplGetText() )
289 if ( !aPropOpt
.IsFontWork() )
290 aPropOpt
.CreateTextProperties( rObj
.mXPropSet
, mpEscherEx
->QueryTextID(
291 rObj
.GetShapeRef(), rObj
.GetShapeId() ), true, false );
296 else if ( rObj
.GetType() == "drawing.Rectangle" )
298 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
299 sal_Int32 nRadius
= rObj
.ImplGetInt32PropertyValue("CornerRadius");
302 nRadius
= ImplMapSize( Size( nRadius
, 0 )).Width();
303 addShape( ESCHER_ShpInst_RoundRectangle
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
304 sal_Int32 nLength
= rObj
.GetRect().GetWidth();
305 if ( nLength
> rObj
.GetRect().GetHeight() )
306 nLength
= rObj
.GetRect().GetHeight();
308 if ( nRadius
>= nLength
|| nLength
== 0 )
309 nRadius
= 0x2a30; // 0x2a30 is PPTs maximum radius
311 nRadius
= ( 0x2a30 * nRadius
) / nLength
;
312 aPropOpt
.AddOpt( ESCHER_Prop_adjustValue
, nRadius
);
316 addShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
318 aPropOpt
.CreateFillProperties( rObj
.mXPropSet
, true );
319 if( rObj
.ImplGetText() )
320 aPropOpt
.CreateTextProperties( rObj
.mXPropSet
,
321 mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
322 rObj
.GetShapeId() ), false, false );
324 else if ( rObj
.GetType() == "drawing.Ellipse" )
326 CircleKind eCircleKind
= CircleKind_FULL
;
327 PolyStyle ePolyKind
= PolyStyle();
328 if ( rObj
.ImplGetPropertyValue( "CircleKind" ) )
330 eCircleKind
= *o3tl::doAccess
<CircleKind
>(rObj
.GetUsrAny());
331 switch ( eCircleKind
)
333 case CircleKind_SECTION
:
335 ePolyKind
= PolyStyle::Pie
;
338 case CircleKind_ARC
:
340 ePolyKind
= PolyStyle::Arc
;
344 case CircleKind_CUT
:
346 ePolyKind
= PolyStyle::Chord
;
351 eCircleKind
= CircleKind_FULL
;
354 if ( eCircleKind
== CircleKind_FULL
)
356 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
357 addShape( ESCHER_ShpInst_Ellipse
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
358 aPropOpt
.CreateFillProperties( rObj
.mXPropSet
, true );
362 sal_Int32 nStartAngle
, nEndAngle
;
363 if ( !rObj
.ImplGetPropertyValue( "CircleStartAngle" ) )
365 nStartAngle
= *o3tl::doAccess
<sal_Int32
>(rObj
.GetUsrAny());
366 if( !rObj
.ImplGetPropertyValue( "CircleEndAngle" ) )
368 nEndAngle
= *o3tl::doAccess
<sal_Int32
>(rObj
.GetUsrAny());
370 Point aStart
, aEnd
, aCenter
;
371 aStart
.setX( static_cast<sal_Int32
>( cos( basegfx::deg2rad
<100>(nStartAngle
) ) * 100.0 ) );
372 aStart
.setY( - static_cast<sal_Int32
>( sin( basegfx::deg2rad
<100>(nStartAngle
) ) * 100.0 ) );
373 aEnd
.setX( static_cast<sal_Int32
>( cos( basegfx::deg2rad
<100>(nEndAngle
) ) * 100.0 ) );
374 aEnd
.setY( - static_cast<sal_Int32
>( sin( basegfx::deg2rad
<100>(nEndAngle
) ) * 100.0 ) );
375 const tools::Rectangle
& rRect
= aRect100thmm
;
376 aCenter
.setX( rRect
.Left() + ( rRect
.GetWidth() / 2 ) );
377 aCenter
.setY( rRect
.Top() + ( rRect
.GetHeight() / 2 ) );
378 aStart
.AdjustX(aCenter
.X() );
379 aStart
.AdjustY(aCenter
.Y() );
380 aEnd
.AdjustX(aCenter
.X() );
381 aEnd
.AdjustY(aCenter
.Y() );
382 tools::Polygon
aPolygon( rRect
, aStart
, aEnd
, ePolyKind
);
383 if( rObj
.GetAngle() )
385 aPolygon
.Rotate( rRect
.TopLeft(), Degree10(static_cast<sal_Int16
>( rObj
.GetAngle() / 10 )) );
388 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
389 addShape( ESCHER_ShpInst_NotPrimitive
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
390 css::awt::Rectangle aNewRect
;
393 case PolyStyle::Pie
:
394 case PolyStyle::Chord
:
396 aPropOpt
.CreatePolygonProperties( rObj
.mXPropSet
, ESCHER_CREATEPOLYGON_POLYPOLYGON
, false, aNewRect
, &aPolygon
);
397 aPropOpt
.CreateFillProperties( rObj
.mXPropSet
, true );
401 case PolyStyle::Arc
:
403 aPropOpt
.CreatePolygonProperties( rObj
.mXPropSet
, ESCHER_CREATEPOLYGON_POLYLINE
, false, aNewRect
, &aPolygon
);
404 aPropOpt
.CreateLineProperties( rObj
.mXPropSet
, false );
408 rObj
.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect
.X
, aNewRect
.Y
) ),
409 ImplMapSize( Size( aNewRect
.Width
, aNewRect
.Height
) ) ) );
411 if ( rObj
.ImplGetText() )
412 aPropOpt
.CreateTextProperties( rObj
.mXPropSet
,
413 mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
414 rObj
.GetShapeId() ), false, false );
417 else if ( rObj
.GetType() == "drawing.Control" )
419 const Reference
< XPropertySet
> xPropSet
= rObj
.mXPropSet
;
420 const Reference
<XPropertySetInfo
> xPropInfo
= xPropSet
.is() ? xPropSet
->getPropertySetInfo() : Reference
<XPropertySetInfo
>();
421 // This code is expected to be called only for DOCX/XLSX formats.
422 if (xPropInfo
.is() && bOOxmlExport
)
424 bool bInline
= false;
425 if (xPropInfo
->hasPropertyByName("AnchorType"))
427 text::TextContentAnchorType eAnchorType
;
428 xPropSet
->getPropertyValue("AnchorType") >>= eAnchorType
;
429 bInline
= eAnchorType
== text::TextContentAnchorType_AS_CHARACTER
;
432 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
433 nShapeType
= bInline
? ESCHER_ShpInst_PictureFrame
: ESCHER_ShpInst_HostControl
;
434 const ShapeFlag nFlags
= ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
;
435 nShapeID
= rObj
.GetShapeId();
438 mpEscherEx
->AddShape(nShapeType
, nFlags
, nShapeID
);
439 rSolverContainer
.AddShape(rObj
.GetShapeRef(), nShapeID
);
443 addShape(nShapeType
, nFlags
);
449 else if ( rObj
.GetType() == "drawing.Connector" )
453 css::awt::Rectangle aNewRect
;
454 if ( ! aPropOpt
.CreateConnectorProperties( rObj
.GetShapeRef(),
455 rSolverContainer
, aNewRect
, nSpType
, nSpFlags
) )
457 rObj
.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect
.X
, aNewRect
.Y
) ),
458 ImplMapSize( Size( aNewRect
.Width
, aNewRect
.Height
) ) ) );
460 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
461 addShape( nSpType
, nSpFlags
);
463 else if ( rObj
.GetType() == "drawing.Measure" )
467 else if ( rObj
.GetType() == "drawing.Line" )
469 css::awt::Rectangle aNewRect
;
470 aPropOpt
.CreatePolygonProperties( rObj
.mXPropSet
, ESCHER_CREATEPOLYGON_LINE
, false, aNewRect
);
471 //i27942: Poly/Lines/Bezier do not support text.
473 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
474 ShapeFlag nFlags
= ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
;
475 if( aNewRect
.Height
< 0 )
476 nFlags
|= ShapeFlag::FlipV
;
477 if( aNewRect
.Width
< 0 )
478 nFlags
|= ShapeFlag::FlipH
;
480 addShape( ESCHER_ShpInst_Line
, nFlags
);
481 aPropOpt
.AddOpt( ESCHER_Prop_shapePath
, ESCHER_ShapeComplex
);
482 aPropOpt
.CreateLineProperties( rObj
.mXPropSet
, false );
485 else if ( rObj
.GetType() == "drawing.PolyPolygon" )
487 if( rObj
.ImplHasText() )
489 nGrpShapeID
= ImplEnterAdditionalTextGroup( rObj
.GetShapeRef(), &rObj
.GetRect() );
490 bAdditionalText
= true;
492 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
493 addShape( ESCHER_ShpInst_NotPrimitive
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
494 css::awt::Rectangle aNewRect
;
495 aPropOpt
.CreatePolygonProperties( rObj
.mXPropSet
, ESCHER_CREATEPOLYGON_POLYPOLYGON
, false, aNewRect
);
496 aPropOpt
.CreateFillProperties( rObj
.mXPropSet
, true );
499 else if ( rObj
.GetType() == "drawing.PolyLine" )
501 //i27942: Poly/Lines/Bezier do not support text.
503 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
504 addShape( ESCHER_ShpInst_NotPrimitive
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
505 css::awt::Rectangle aNewRect
;
506 aPropOpt
.CreatePolygonProperties( rObj
.mXPropSet
, ESCHER_CREATEPOLYGON_POLYLINE
, false, aNewRect
);
507 aPropOpt
.CreateLineProperties( rObj
.mXPropSet
, false );
510 else if ( rObj
.GetType() == "drawing.OpenBezier" )
512 //i27942: Poly/Lines/Bezier do not support text.
514 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
515 addShape( ESCHER_ShpInst_NotPrimitive
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
516 css::awt::Rectangle aNewRect
;
517 aPropOpt
.CreatePolygonProperties( rObj
.mXPropSet
, ESCHER_CREATEPOLYGON_POLYLINE
, true, aNewRect
);
518 aPropOpt
.CreateLineProperties( rObj
.mXPropSet
, false );
521 else if ( rObj
.GetType() == "drawing.ClosedBezier" )
523 if ( rObj
.ImplHasText() )
525 nGrpShapeID
= ImplEnterAdditionalTextGroup( rObj
.GetShapeRef(), &rObj
.GetRect() );
526 bAdditionalText
= true;
528 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
529 addShape( ESCHER_ShpInst_NotPrimitive
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
530 css::awt::Rectangle aNewRect
;
531 aPropOpt
.CreatePolygonProperties( rObj
.mXPropSet
, ESCHER_CREATEPOLYGON_POLYPOLYGON
, true, aNewRect
);
532 aPropOpt
.CreateFillProperties( rObj
.mXPropSet
, true );
535 else if ( rObj
.GetType() == "drawing.GraphicObject" )
537 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
539 // a GraphicObject can also be a ClickMe element
540 if( rObj
.IsEmptyPresObj() )
542 addShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::HaveMaster
| ShapeFlag::HaveAnchor
);
543 sal_uInt32 nTxtBxId
= mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
545 aPropOpt
.AddOpt( ESCHER_Prop_lTxid
, nTxtBxId
);
546 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x10001 );
547 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x10001 );
548 aPropOpt
.AddOpt( ESCHER_Prop_hspMaster
, 0 );
552 if( rObj
.ImplGetText() )
554 /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we
555 have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat).
557 addShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
558 if ( aPropOpt
.CreateGraphicProperties( rObj
.mXPropSet
, "Graphic", true, true, false ) )
560 aPropOpt
.AddOpt( ESCHER_Prop_WrapText
, ESCHER_WrapNone
);
561 aPropOpt
.AddOpt( ESCHER_Prop_AnchorText
, ESCHER_AnchorMiddle
);
562 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x140014 );
563 aPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, 0x8000000 );
564 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x80000 );
565 if ( rObj
.ImplGetText() )
566 aPropOpt
.CreateTextProperties( rObj
.mXPropSet
,
567 mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
568 rObj
.GetShapeId() ), false, false );
573 addShape( ESCHER_ShpInst_PictureFrame
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
574 if ( aPropOpt
.CreateGraphicProperties( rObj
.mXPropSet
, "Graphic", false, true, true, bOOxmlExport
) )
575 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x800080 );
579 else if ( rObj
.GetType() == "drawing.Text" )
581 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
582 addShape( ESCHER_ShpInst_TextBox
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
583 aPropOpt
.CreateFillProperties( rObj
.mXPropSet
, true );
584 if( rObj
.ImplGetText() )
585 aPropOpt
.CreateTextProperties( rObj
.mXPropSet
,
586 mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
587 rObj
.GetShapeId() ) );
589 else if ( rObj
.GetType() == "drawing.Page" )
591 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
592 addShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
593 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x40004 );
594 aPropOpt
.AddOpt( ESCHER_Prop_fFillOK
, 0x100001 );
595 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x110011 );
596 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x90008 );
597 aPropOpt
.AddOpt( ESCHER_Prop_fshadowObscured
, 0x10001 );
599 else if ( rObj
.GetType() == "drawing.Frame" )
603 else if ( rObj
.GetType() == "drawing.OLE2" )
605 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
606 if( rObj
.IsEmptyPresObj() )
608 addShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::HaveMaster
| ShapeFlag::HaveAnchor
);
609 sal_uInt32 nTxtBxId
= mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
611 aPropOpt
.AddOpt( ESCHER_Prop_lTxid
, nTxtBxId
);
612 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x10001 );
613 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x10001 );
614 aPropOpt
.AddOpt( ESCHER_Prop_hspMaster
, 0 );
618 //2do: could be made an option in HostAppData whether OLE object should be written or not
619 const bool bAppOLE
= true;
620 addShape( ESCHER_ShpInst_PictureFrame
,
621 ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
| (bAppOLE
? ShapeFlag::OLEShape
: ShapeFlag::NONE
) );
622 if ( aPropOpt
.CreateOLEGraphicProperties( rObj
.GetShapeRef() ) )
625 { // snooped from Xcl hex dump, nobody knows the trouble I have seen
626 aPropOpt
.AddOpt( ESCHER_Prop_FitTextToShape
, 0x00080008 );
627 aPropOpt
.AddOpt( ESCHER_Prop_pictureId
, 0x00000001 );
628 aPropOpt
.AddOpt( ESCHER_Prop_fillColor
, 0x08000041 );
629 aPropOpt
.AddOpt( ESCHER_Prop_fillBackColor
, 0x08000041 );
630 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x00110010 );
631 aPropOpt
.AddOpt( ESCHER_Prop_lineColor
, 0x08000040 );
632 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
,0x00080008 );
633 aPropOpt
.AddOpt( ESCHER_Prop_fPrint
, 0x00080000 );
635 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x800080 );
639 else if( '3' == rObj
.GetType()[8] &&
640 'D' == rObj
.GetType()[9] ) // drawing.3D
642 // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject
643 if ( !rObj
.ImplGetPropertyValue( "Bitmap" ) )
646 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
647 addShape( ESCHER_ShpInst_PictureFrame
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
649 if ( aPropOpt
.CreateGraphicProperties( rObj
.mXPropSet
, "Bitmap", false ) )
650 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x800080 );
652 else if ( rObj
.GetType() == "drawing.Caption" )
655 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
656 addShape( ESCHER_ShpInst_TextBox
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
657 if ( aPropOpt
.CreateGraphicProperties( rObj
.mXPropSet
, "MetaFile", false ) )
658 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x800080 );
660 else if ( rObj
.GetType() == "drawing.dontknow" )
663 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
664 addShape( ESCHER_ShpInst_PictureFrame
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
665 if ( aPropOpt
.CreateGraphicProperties( rObj
.mXPropSet
, "MetaFile", false ) )
666 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x800080 );
672 aPropOpt
.CreateShadowProperties( rObj
.mXPropSet
);
674 if( SDRLAYER_NOTFOUND
!= mpEscherEx
->GetHellLayerId() &&
675 rObj
.ImplGetPropertyValue( "LayerID" ) &&
676 *o3tl::doAccess
<sal_Int16
>(rObj
.GetUsrAny()) == mpEscherEx
->GetHellLayerId().get() )
678 aPropOpt
.AddOpt( ESCHER_Prop_fPrint
, 0x200020 );
682 tools::Rectangle
aRect( rObj
.GetRect() );
684 rObj
.SetRect( aRect
);
687 if( rObj
.GetAngle() )
688 ImplFlipBoundingBox( rObj
, aPropOpt
);
690 aPropOpt
.CreateShapeProperties( rObj
.GetShapeRef() );
691 const SdrObject
* sdrObj
= rObj
.GetSdrObject();
692 mpEscherEx
->AddSdrObjectVMLObject(*sdrObj
);
693 mpEscherEx
->Commit( aPropOpt
, rObj
.GetRect());
694 if( mpEscherEx
->GetGroupLevel() > 1 )
695 mpEscherEx
->AddChildAnchor( rObj
.GetRect() );
698 { //! with AdditionalText the App has to control whether these are written or not
699 mpHostAppData
->WriteClientAnchor( *mpEscherEx
, rObj
.GetRect() );
700 mpHostAppData
->WriteClientData( *mpEscherEx
);
701 if ( !bDontWriteText
)
702 mpHostAppData
->WriteClientTextbox( *mpEscherEx
);
704 mpEscherEx
->CloseContainer(); // ESCHER_SpContainer
706 if( bAdditionalText
)
708 mpEscherEx
->EndShape( nShapeType
, nShapeID
);
709 ImplWriteAdditionalText( rObj
);
714 if ( bAdditionalText
)
715 mpEscherEx
->EndShape( ESCHER_ShpInst_Min
, nGrpShapeID
);
717 mpEscherEx
->EndShape( nShapeType
, nShapeID
);
721 void ImplEESdrWriter::ImplWriteAdditionalText( ImplEESdrObject
& rObj
)
723 sal_uInt32 nShapeID
= 0;
724 sal_uInt16 nShapeType
= 0;
727 mpHostAppData
= mpEscherEx
->StartShape( rObj
.GetShapeRef(), (mpEscherEx
->GetGroupLevel() > 1) ? &rObj
.GetRect() : nullptr );
728 if ( mpHostAppData
&& mpHostAppData
->DontWriteShape() )
731 const css::awt::Size
aSize100thmm( rObj
.GetShapeRef()->getSize() );
732 const css::awt::Point
aPoint100thmm( rObj
.GetShapeRef()->getPosition() );
733 tools::Rectangle
aRect100thmm( Point( aPoint100thmm
.X
, aPoint100thmm
.Y
), Size( aSize100thmm
.Width
, aSize100thmm
.Height
) );
735 mpPicStrm
= mpEscherEx
->QueryPictureStream();
736 EscherPropertyContainer
aPropOpt( mpEscherEx
->GetGraphicProvider(), mpPicStrm
, aRect100thmm
);
737 rObj
.SetAngle( rObj
.ImplGetInt32PropertyValue( "RotateAngle" ));
738 sal_Int32 nAngle
= rObj
.GetAngle();
739 if( rObj
.GetType() == "drawing.Line" )
741 //2do: this does not work right
742 double fDist
= hypot( rObj
.GetRect().GetWidth(),
743 rObj
.GetRect().GetHeight() );
744 rObj
.SetRect( tools::Rectangle( Point(),
745 Point( static_cast<sal_Int32
>( fDist
), -1 ) ) );
747 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
748 mpEscherEx
->AddShape( ESCHER_ShpInst_TextBox
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
);
749 if ( rObj
.ImplGetText() )
750 aPropOpt
.CreateTextProperties( rObj
.mXPropSet
,
751 mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
752 rObj
.GetShapeId() ) );
754 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x90000 );
755 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100000 );
756 aPropOpt
.AddOpt( ESCHER_Prop_FitTextToShape
, 0x60006 ); // Size Shape To Fit Text
758 nAngle
= ( 36000 + nAngle
) % 36000;
760 ImplFlipBoundingBox( rObj
, aPropOpt
);
764 mpEscherEx
->OpenContainer( ESCHER_SpContainer
);
765 nShapeID
= mpEscherEx
->GenerateShapeId();
766 nShapeType
= ESCHER_ShpInst_TextBox
;
767 mpEscherEx
->AddShape( nShapeType
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
, nShapeID
);
768 if ( rObj
.ImplGetText() )
769 aPropOpt
.CreateTextProperties( rObj
.mXPropSet
,
770 mpEscherEx
->QueryTextID( rObj
.GetShapeRef(),
771 rObj
.GetShapeId() ) );
772 aPropOpt
.AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x90000 );
773 aPropOpt
.AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100000 );
776 nAngle
= ( 36000 + nAngle
) % 36000;
778 nAngle
= ( 36000 - ( nAngle
% 36000 ) );
782 nAngle
&=~0xffff; // nAngle round to full degrees
783 aPropOpt
.AddOpt( ESCHER_Prop_Rotation
, nAngle
);
784 mpEscherEx
->SetGroupSnapRect( mpEscherEx
->GetGroupLevel(),
786 mpEscherEx
->SetGroupLogicRect( mpEscherEx
->GetGroupLevel(),
789 rObj
.SetAngle( nAngle
);
790 aPropOpt
.CreateShapeProperties( rObj
.GetShapeRef() );
791 const SdrObject
* sdrObj
= rObj
.GetSdrObject();
792 mpEscherEx
->AddSdrObjectVMLObject(*sdrObj
);
793 mpEscherEx
->Commit( aPropOpt
, rObj
.GetRect());
795 // write the childanchor
796 mpEscherEx
->AddChildAnchor( rObj
.GetRect() );
798 #if defined EES_WRITE_EPP
800 mpEscherEx
->AddClientAnchor( maRect
);
802 mpEscherEx
->OpenContainer( ESCHER_ClientTextbox
);
803 mpEscherEx
->AddAtom( 4, EPP_TextHeaderAtom
);
804 *mpStrm
<< (sal_uInt32
)EPP_TEXTTYPE_Other
; // Text in a Shape
805 ImplWriteTextStyleAtom();
806 mpEscherEx
->CloseContainer(); // ESCHER_ClientTextBox
807 #else // !EES_WRITE_EPP
809 { //! the App has to control whether these are written or not
810 mpHostAppData
->WriteClientAnchor( *mpEscherEx
, rObj
.GetRect() );
811 mpHostAppData
->WriteClientData( *mpEscherEx
);
812 mpHostAppData
->WriteClientTextbox( *mpEscherEx
);
814 #endif // EES_WRITE_EPP
815 mpEscherEx
->CloseContainer(); // ESCHER_SpContainer
817 mpEscherEx
->LeaveGroup();
818 mpEscherEx
->EndShape( nShapeType
, nShapeID
);
822 sal_uInt32
ImplEESdrWriter::ImplEnterAdditionalTextGroup( const Reference
< XShape
>& rShape
,
823 const tools::Rectangle
* pBoundRect
)
825 mpHostAppData
= mpEscherEx
->EnterAdditionalTextGroup();
826 sal_uInt32 nGrpId
= mpEscherEx
->EnterGroup( pBoundRect
);
827 mpHostAppData
= mpEscherEx
->StartShape( rShape
, pBoundRect
);
832 void ImplEESdrWriter::ImplInitPageValues()
834 mbIsTitlePossible
= true; // With more than one title PowerPoint will fail.
837 void ImplEESdrWriter::ImplWritePage(
838 EscherSolverContainer
& rSolverContainer
, bool ooxmlExport
)
840 ImplInitPageValues();
842 const sal_uInt32 nShapes
= mXShapes
->getCount();
843 for( sal_uInt32 n
= 0; n
< nShapes
; ++n
)
845 ImplEESdrObject
aObj( *o3tl::doAccess
<Reference
<XShape
>>(
846 mXShapes
->getByIndex( n
)) );
849 ImplWriteShape( aObj
, rSolverContainer
, ooxmlExport
);
854 ImplEESdrWriter::~ImplEESdrWriter()
856 DBG_ASSERT( !mpSolverContainer
, "ImplEESdrWriter::~ImplEESdrWriter: unwritten SolverContainer" );
857 Reference
<css::lang::XComponent
> xComp(mXDrawPage
, UNO_QUERY
);
863 bool ImplEESdrWriter::ImplInitPage( const SdrPage
& rPage
)
865 rtl::Reference
<SvxDrawPage
> pSvxDrawPage
;
866 if ( mpSdrPage
!= &rPage
|| !mXDrawPage
.is() )
868 // eventually write SolverContainer of current page, deletes the Solver
869 ImplFlushSolverContainer();
872 Reference
<css::lang::XComponent
> xOldDrawPage(mXDrawPage
, UNO_QUERY
);
873 if (xOldDrawPage
.is())
874 xOldDrawPage
->dispose();
875 mXDrawPage
= pSvxDrawPage
= new SvxFmDrawPage( const_cast<SdrPage
*>(&rPage
) );
876 mXShapes
= mXDrawPage
;
877 if ( !mXShapes
.is() )
879 ImplInitPageValues();
882 mpSolverContainer
.reset( new EscherSolverContainer
);
885 pSvxDrawPage
= comphelper::getFromUnoTunnel
<SvxDrawPage
>(mXDrawPage
);
887 return pSvxDrawPage
!= nullptr;
890 bool ImplEESdrWriter::ImplInitUnoShapes( const Reference
< XShapes
>& rxShapes
)
892 // eventually write SolverContainer of current page, deletes the Solver
893 ImplFlushSolverContainer();
902 ImplInitPageValues();
904 mpSolverContainer
.reset( new EscherSolverContainer
);
908 void ImplEESdrWriter::ImplExitPage()
910 // close all groups before the solver container is written
911 while( mpEscherEx
->GetGroupLevel() )
912 mpEscherEx
->LeaveGroup();
914 ImplFlushSolverContainer();
915 mpSdrPage
= nullptr; // reset page for next init
919 void ImplEESdrWriter::ImplFlushSolverContainer()
921 if ( mpSolverContainer
)
923 mpSolverContainer
->WriteSolver( mpEscherEx
->GetStream() );
924 mpSolverContainer
.reset();
928 void ImplEESdrWriter::ImplWriteCurrentPage(bool ooxmlExport
)
930 assert(mpSolverContainer
&& "ImplEESdrWriter::ImplWriteCurrentPage: no SolverContainer");
931 ImplWritePage( *mpSolverContainer
, ooxmlExport
);
935 sal_uInt32
ImplEESdrWriter::ImplWriteTheShape( ImplEESdrObject
& rObj
, bool ooxmlExport
)
937 assert(mpSolverContainer
&& "ImplEESdrWriter::ImplWriteShape: no SolverContainer");
938 return ImplWriteShape( rObj
, *mpSolverContainer
, ooxmlExport
);
941 void EscherEx::AddSdrPage( const SdrPage
& rPage
, bool ooxmlExport
)
943 if ( mpImplEESdrWriter
->ImplInitPage( rPage
) )
944 mpImplEESdrWriter
->ImplWriteCurrentPage(ooxmlExport
);
947 void EscherEx::AddUnoShapes( const Reference
< XShapes
>& rxShapes
, bool ooxmlExport
)
949 if ( mpImplEESdrWriter
->ImplInitUnoShapes( rxShapes
) )
950 mpImplEESdrWriter
->ImplWriteCurrentPage(ooxmlExport
);
953 sal_uInt32
EscherEx::AddSdrObject(const SdrObject
& rObj
, bool ooxmlExport
, sal_uInt32 nId
)
955 ImplEESdrObject
aObj(*mpImplEESdrWriter
, rObj
, mbOOXML
, nId
);
957 return mpImplEESdrWriter
->ImplWriteTheShape( aObj
, ooxmlExport
);
962 void EscherEx::EndSdrObjectPage()
964 mpImplEESdrWriter
->ImplExitPage();
967 EscherExHostAppData
* EscherEx::StartShape( const Reference
< XShape
>& /* rShape */, const tools::Rectangle
* /*pChildAnchor*/ )
972 void EscherEx::EndShape( sal_uInt16
/* nShapeType */, sal_uInt32
/* nShapeID */ )
976 sal_uInt32
EscherEx::QueryTextID( const Reference
< XShape
>&, sal_uInt32
)
981 // add a dummy rectangle shape into the escher stream
982 sal_uInt32
EscherEx::AddDummyShape()
984 OpenContainer( ESCHER_SpContainer
);
985 sal_uInt32 nShapeID
= GenerateShapeId();
986 AddShape( ESCHER_ShpInst_Rectangle
, ShapeFlag::HaveShapeProperty
| ShapeFlag::HaveAnchor
, nShapeID
);
993 const SdrObject
* EscherEx::GetSdrObject( const Reference
< XShape
>& rShape
)
995 const SdrObject
* pRet
= SdrObject::getSdrObjectFromXShape( rShape
);
996 DBG_ASSERT( pRet
, "EscherEx::GetSdrObject: no SdrObj" );
1001 ImplEESdrObject::ImplEESdrObject( ImplEESdrWriter
& rEx
,
1002 const SdrObject
& rObj
, bool bOOXML
, sal_uInt32 nId
) :
1008 mbEmptyPresObj( false ),
1011 SdrPage
* pPage
= rObj
.getSdrPageFromSdrObject();
1012 DBG_ASSERT( pPage
, "ImplEESdrObject::ImplEESdrObject: no SdrPage" );
1013 if( pPage
&& rEx
.ImplInitPage( *pPage
) )
1015 // why not declare a const parameter if the object will
1017 mXShape
.set( const_cast<SdrObject
*>(&rObj
)->getUnoShape(), UNO_QUERY
);
1022 ImplEESdrObject::ImplEESdrObject( const Reference
< XShape
>& rShape
) :
1029 mbEmptyPresObj( false ),
1036 ImplEESdrObject::~ImplEESdrObject()
1040 static basegfx::B2DRange
getUnrotatedGroupBoundRange(const Reference
< XShape
>& rxShape
)
1042 basegfx::B2DRange aRetval
;
1048 if(rxShape
->getShapeType() == "com.sun.star.drawing.GroupShape")
1050 // it's a group shape, iterate over children
1051 const Reference
< XIndexAccess
> xXIndexAccess(rxShape
, UNO_QUERY
);
1053 if(xXIndexAccess
.is())
1055 for(sal_uInt32
n(0), nCnt
= xXIndexAccess
->getCount(); n
< nCnt
; ++n
)
1057 const Reference
< XShape
> axShape(xXIndexAccess
->getByIndex(n
), UNO_QUERY
);
1061 // we are calculating the bound for a group, correct rotation for sub-objects
1062 // to get the unrotated bounds for the group
1063 const basegfx::B2DRange
aExtend(getUnrotatedGroupBoundRange(axShape
));
1065 aRetval
.expand(aExtend
);
1072 // iT#s a xShape, get its transformation
1073 const Reference
< XPropertySet
> xPropSet(rxShape
, UNO_QUERY
);
1077 const Any aAny
= xPropSet
->getPropertyValue("Transformation");
1081 HomogenMatrix3 aMatrix
;
1083 if(aAny
>>= aMatrix
)
1085 basegfx::B2DHomMatrix aHomogenMatrix
;
1087 aHomogenMatrix
.set(0, 0, aMatrix
.Line1
.Column1
);
1088 aHomogenMatrix
.set(0, 1, aMatrix
.Line1
.Column2
);
1089 aHomogenMatrix
.set(0, 2, aMatrix
.Line1
.Column3
);
1090 aHomogenMatrix
.set(1, 0, aMatrix
.Line2
.Column1
);
1091 aHomogenMatrix
.set(1, 1, aMatrix
.Line2
.Column2
);
1092 aHomogenMatrix
.set(1, 2, aMatrix
.Line2
.Column3
);
1093 // For this to be a valid 2D transform matrix, the last row must be [0,0,1]
1094 assert( aMatrix
.Line3
.Column1
== 0 );
1095 assert( aMatrix
.Line3
.Column2
== 0 );
1096 assert( aMatrix
.Line3
.Column3
== 1 );
1098 basegfx::B2DVector aScale
, aTranslate
;
1099 double fRotate
, fShearX
;
1101 // decompose transformation
1102 aHomogenMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
1104 // check if rotation needs to be corrected
1105 if(!basegfx::fTools::equalZero(fRotate
))
1107 // to correct, keep in mind that ppt graphics are rotated around their center
1108 const basegfx::B2DPoint
aCenter(aHomogenMatrix
* basegfx::B2DPoint(0.5, 0.5));
1110 aHomogenMatrix
.translate(-aCenter
.getX(), -aCenter
.getY());
1111 aHomogenMatrix
.rotate(-fRotate
);
1112 aHomogenMatrix
.translate(aCenter
.getX(), aCenter
.getY());
1116 // check if shear needs to be corrected (always correct shear,
1117 // ppt does not know about it)
1118 if(!basegfx::fTools::equalZero(fShearX
))
1120 const basegfx::B2DPoint
aMinimum(aHomogenMatrix
* basegfx::B2DPoint(0.0, 0.0));
1122 aHomogenMatrix
.translate(-aMinimum
.getX(), -aMinimum
.getY());
1123 aHomogenMatrix
.shearX(-fShearX
);
1124 aHomogenMatrix
.translate(aMinimum
.getX(), aMinimum
.getY());
1127 // create range. It's no longer rotated (or sheared), so use
1128 // minimum and maximum values
1129 aRetval
.expand(aHomogenMatrix
* basegfx::B2DPoint(0.0, 0.0));
1130 aRetval
.expand(aHomogenMatrix
* basegfx::B2DPoint(1.0, 1.0));
1137 catch(css::uno::Exception
&)
1144 void ImplEESdrObject::Init()
1146 mXPropSet
.set( mXShape
, UNO_QUERY
);
1147 if( !mXPropSet
.is() )
1150 // detect name first to make below test (is group) work
1151 mType
= mXShape
->getShapeType();
1152 (void)mType
.startsWith( "com.sun.star.", &mType
); // strip "com.sun.star."
1153 (void)mType
.endsWith( "Shape", &mType
); // strip "Shape"
1155 if(GetType() == "drawing.Group")
1157 // if it's a group, the unrotated range is needed for that group
1158 const basegfx::B2DRange
aUnrotatedRange(getUnrotatedGroupBoundRange(mXShape
));
1159 const Point
aNewP(basegfx::fround(aUnrotatedRange
.getMinX()), basegfx::fround(aUnrotatedRange
.getMinY()));
1160 const Size
aNewS(basegfx::fround(aUnrotatedRange
.getWidth()), basegfx::fround(aUnrotatedRange
.getHeight()));
1162 SetRect(ImplEESdrWriter::ImplMapPoint(aNewP
), ImplEESdrWriter::ImplMapSize(aNewS
));
1166 // if it's no group, use position and size directly, rotated/sheared or not
1167 const Point
aOldP(mXShape
->getPosition().X
, mXShape
->getPosition().Y
);
1168 const Size
aOldS(mXShape
->getSize().Width
, mXShape
->getSize().Height
);
1170 SetRect(ImplEESdrWriter::ImplMapPoint(aOldP
), ImplEESdrWriter::ImplMapSize(aOldS
));
1173 if( ImplGetPropertyValue( "IsPresentationObject" ) )
1174 mbPresObj
= ::cppu::any2bool( mAny
);
1176 if( mbPresObj
&& ImplGetPropertyValue( "IsEmptyPresentationObject" ) )
1177 mbEmptyPresObj
= ::cppu::any2bool( mAny
);
1182 bool ImplEESdrObject::ImplGetPropertyValue( const OUString
& rString
)
1184 bool bRetValue
= false;
1189 mAny
= mXPropSet
->getPropertyValue( rString
);
1190 if( mAny
.hasValue() )
1193 catch( const css::uno::Exception
& )
1201 void ImplEESdrObject::SetRect( const Point
& rPos
, const Size
& rSz
)
1203 maRect
= tools::Rectangle( rPos
, rSz
);
1206 const SdrObject
* ImplEESdrObject::GetSdrObject() const
1208 return EscherEx::GetSdrObject( mXShape
);
1211 // loads and converts text from shape, result is saved in mnTextSize
1212 sal_uInt32
ImplEESdrObject::ImplGetText()
1214 Reference
< XText
> xXText( mXShape
, UNO_QUERY
);
1220 mnTextSize
= xXText
->getString().getLength();
1222 catch (const uno::RuntimeException
&)
1224 TOOLS_WARN_EXCEPTION("filter.ms", "ImplGetText");
1230 bool ImplEESdrObject::ImplHasText() const
1232 Reference
< XText
> xXText( mXShape
, UNO_QUERY
);
1233 return xXText
.is() && !xXText
->getString().isEmpty();
1237 void ImplEESdrObject::SetOOXML(bool bOOXML
)
1242 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */