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 .
20 #include "eschesdo.hxx"
21 #include <o3tl/any.hxx>
22 #include <svx/svdxcgv.hxx>
23 #include <svx/svdomedia.hxx>
24 #include <svx/xflftrit.hxx>
25 #include <filter/msfilter/escherex.hxx>
26 #include <filter/msfilter/util.hxx>
27 #include <svx/unoapi.hxx>
28 #include <svx/svdobj.hxx>
29 #include <svx/svdoashp.hxx>
30 #include <svx/svdoole2.hxx>
31 #include <svx/svdmodel.hxx>
32 #include <editeng/outlobj.hxx>
33 #include <vcl/gradient.hxx>
34 #include <vcl/graph.hxx>
35 #include <vcl/cvtgrf.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/wrkwin.hxx>
38 #include <tools/stream.hxx>
39 #include <tools/zcodec.hxx>
40 #include <svx/svdopath.hxx>
42 #include <vcl/graphicfilter.hxx>
43 #include "svx/EnhancedCustomShapeTypeNames.hxx"
44 #include "svx/EnhancedCustomShapeGeometry.hxx"
45 #include <svx/EnhancedCustomShapeFunctionParser.hxx>
46 #include "svx/EnhancedCustomShape2d.hxx"
47 #include <com/sun/star/beans/PropertyValues.hpp>
48 #include <com/sun/star/beans/XPropertyState.hpp>
49 #include <com/sun/star/awt/GradientStyle.hpp>
50 #include <com/sun/star/awt/RasterOperation.hpp>
51 #include <com/sun/star/awt/Gradient.hpp>
52 #include <com/sun/star/drawing/LineStyle.hpp>
53 #include <com/sun/star/drawing/LineJoint.hpp>
54 #include <com/sun/star/drawing/LineCap.hpp>
55 #include <com/sun/star/drawing/FillStyle.hpp>
56 #include <com/sun/star/drawing/LineDash.hpp>
57 #include <com/sun/star/drawing/BezierPoint.hpp>
58 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
59 #include <com/sun/star/drawing/ConnectorType.hpp>
60 #include <com/sun/star/drawing/ConnectionType.hpp>
61 #include <com/sun/star/drawing/CircleKind.hpp>
62 #include <com/sun/star/drawing/PointSequence.hpp>
63 #include <com/sun/star/drawing/FlagSequence.hpp>
64 #include <com/sun/star/drawing/PolygonFlags.hpp>
65 #include <com/sun/star/text/WritingMode.hpp>
66 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
67 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
68 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
69 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
70 #include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
71 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
72 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
73 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
74 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
75 #include <com/sun/star/drawing/ProjectionMode.hpp>
76 #include <com/sun/star/text/XSimpleText.hpp>
77 #include <com/sun/star/drawing/ShadeMode.hpp>
78 #include <com/sun/star/drawing/TextFitToSizeType.hpp>
79 #include <vcl/hatch.hxx>
80 #include <com/sun/star/awt/XGraphics.hpp>
81 #include <com/sun/star/awt/FontSlant.hpp>
82 #include <com/sun/star/awt/FontWeight.hpp>
83 #include <com/sun/star/drawing/ColorMode.hpp>
84 #include <com/sun/star/drawing/Position3D.hpp>
85 #include <com/sun/star/drawing/Direction3D.hpp>
86 #include <com/sun/star/drawing/Hatch.hpp>
87 #include <com/sun/star/text/GraphicCrop.hpp>
88 #include <unotools/ucbstreamhelper.hxx>
89 #include <unotools/localfilehelper.hxx>
90 #include <comphelper/string.hxx>
91 #include <toolkit/helper/vclunohelper.hxx>
92 #include <vcl/virdev.hxx>
94 #include <rtl/strbuf.hxx>
97 using namespace ::com::sun::star
;
100 EscherExContainer::EscherExContainer( SvStream
& rSt
, const sal_uInt16 nRecType
, const sal_uInt16 nInstance
) :
103 rStrm
.WriteUInt32( ( 0xf | ( nInstance
<< 4 ) ) | ( nRecType
<< 16 ) ).WriteUInt32( 0 );
104 nContPos
= rStrm
.Tell();
106 EscherExContainer::~EscherExContainer()
108 sal_uInt32 nPos
= rStrm
.Tell();
109 sal_uInt32 nSize
= nPos
- nContPos
;
112 rStrm
.Seek( nContPos
- 4 );
113 rStrm
.WriteUInt32( nSize
);
118 EscherExAtom::EscherExAtom( SvStream
& rSt
, const sal_uInt16 nRecType
, const sal_uInt16 nInstance
, const sal_uInt8 nVersion
) :
121 rStrm
.WriteUInt32( ( nVersion
| ( nInstance
<< 4 ) ) | ( nRecType
<< 16 ) ).WriteUInt32( 0 );
122 nContPos
= rStrm
.Tell();
124 EscherExAtom::~EscherExAtom()
126 sal_uInt32 nPos
= rStrm
.Tell();
127 sal_uInt32 nSize
= nPos
- nContPos
;
130 rStrm
.Seek( nContPos
- 4 );
131 rStrm
.WriteUInt32( nSize
);
136 EscherExClientRecord_Base::~EscherExClientRecord_Base()
140 EscherExClientAnchor_Base::~EscherExClientAnchor_Base()
144 EscherPropertyContainer::EscherPropertyContainer(
145 EscherGraphicProvider
* pGraphProv
, SvStream
* pPiOutStrm
,
146 Rectangle
* pBoundRect
):
147 pGraphicProvider(pGraphProv
),
148 pPicOutStrm(pPiOutStrm
),
149 pShapeBoundRect(pBoundRect
),
154 pSortStruct(new EscherPropSortStruct
[nSortBufSize
]),
155 bHasComplexData(false)
158 EscherPropertyContainer::EscherPropertyContainer()
159 : EscherPropertyContainer(nullptr, nullptr, nullptr)
162 EscherPropertyContainer::EscherPropertyContainer(
163 EscherGraphicProvider
& rGraphProv
,
164 SvStream
* pPiOutStrm
,
165 Rectangle
& rBoundRect
) :
166 EscherPropertyContainer(&rGraphProv
, pPiOutStrm
, &rBoundRect
)
169 EscherPropertyContainer::~EscherPropertyContainer()
171 if ( bHasComplexData
)
173 while ( nSortCount
-- )
174 delete[] pSortStruct
[ nSortCount
].pBuf
;
176 delete[] pSortStruct
;
179 void EscherPropertyContainer::AddOpt( sal_uInt16 nPropID
, sal_uInt32 nPropValue
, bool bBlib
)
181 AddOpt( nPropID
, bBlib
, nPropValue
, nullptr, 0 );
184 void EscherPropertyContainer::AddOpt( sal_uInt16 nPropID
, const OUString
& rString
)
186 sal_Int32 j
, i
, nLen
= rString
.getLength() * 2 + 2;
187 sal_uInt8
* pBuf
= new sal_uInt8
[ nLen
];
188 for ( j
= i
= 0; i
< rString
.getLength(); i
++ )
190 sal_uInt16 nChar
= (sal_uInt16
)rString
[ i
];
191 pBuf
[ j
++ ] = (sal_uInt8
)nChar
;
192 pBuf
[ j
++ ] = (sal_uInt8
)( nChar
>> 8 );
196 AddOpt( nPropID
, true, nLen
, pBuf
, nLen
);
199 void EscherPropertyContainer::AddOpt( sal_uInt16 nPropID
, bool bBlib
, sal_uInt32 nPropValue
, sal_uInt8
* pProp
, sal_uInt32 nPropSize
)
201 if ( bBlib
) // bBlib is only valid when fComplex = 0
204 nPropID
|= 0x8000; // fComplex = sal_True;
207 for( i
= 0; i
< nSortCount
; i
++ )
209 if ( ( pSortStruct
[ i
].nPropId
&~0xc000 ) == ( nPropID
&~0xc000 ) ) // check, whether the Property only gets replaced
211 pSortStruct
[ i
].nPropId
= nPropID
;
212 if ( pSortStruct
[ i
].pBuf
)
214 nCountSize
-= pSortStruct
[ i
].nPropSize
;
215 delete[] pSortStruct
[ i
].pBuf
;
217 pSortStruct
[ i
].pBuf
= pProp
;
218 pSortStruct
[ i
].nPropSize
= nPropSize
;
219 pSortStruct
[ i
].nPropValue
= nPropValue
;
221 nCountSize
+= nPropSize
;
227 if ( nSortCount
== nSortBufSize
) // increase buffer
230 EscherPropSortStruct
* pTemp
= new EscherPropSortStruct
[ nSortBufSize
];
231 for( i
= 0; i
< nSortCount
; i
++ )
233 pTemp
[ i
] = pSortStruct
[ i
];
235 delete[] pSortStruct
;
238 pSortStruct
[ nSortCount
].nPropId
= nPropID
; // insert property
239 pSortStruct
[ nSortCount
].pBuf
= pProp
;
240 pSortStruct
[ nSortCount
].nPropSize
= nPropSize
;
241 pSortStruct
[ nSortCount
++ ].nPropValue
= nPropValue
;
245 nCountSize
+= nPropSize
;
246 bHasComplexData
= true;
250 bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId
, sal_uInt32
& rPropValue
) const
252 EscherPropSortStruct aPropStruct
;
254 if ( GetOpt( nPropId
, aPropStruct
) )
256 rPropValue
= aPropStruct
.nPropValue
;
262 bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId
, EscherPropSortStruct
& rPropValue
) const
264 for( sal_uInt32 i
= 0; i
< nSortCount
; i
++ )
266 if ( ( pSortStruct
[ i
].nPropId
&~0xc000 ) == ( nPropId
&~0xc000 ) )
268 rPropValue
= pSortStruct
[ i
];
275 EscherProperties
EscherPropertyContainer::GetOpts() const
277 EscherProperties aVector
;
279 for ( sal_uInt32 i
= 0; i
< nSortCount
; ++i
)
280 aVector
.push_back( pSortStruct
[ i
] );
285 extern "C" int SAL_CALL
EscherPropSortFunc( const void* p1
, const void* p2
)
287 sal_Int16 nID1
= static_cast<EscherPropSortStruct
const *>(p1
)->nPropId
&~0xc000;
288 sal_Int16 nID2
= static_cast<EscherPropSortStruct
const *>(p2
)->nPropId
&~0xc000;
292 else if( nID1
> nID2
)
298 void EscherPropertyContainer::Commit( SvStream
& rSt
, sal_uInt16 nVersion
, sal_uInt16 nRecType
)
300 rSt
.WriteUInt16( ( nCountCount
<< 4 ) | ( nVersion
& 0xf ) ).WriteUInt16( nRecType
).WriteUInt32( nCountSize
);
303 qsort( pSortStruct
, nSortCount
, sizeof( EscherPropSortStruct
), EscherPropSortFunc
);
306 for ( i
= 0; i
< nSortCount
; i
++ )
308 sal_uInt32 nPropValue
= pSortStruct
[ i
].nPropValue
;
309 sal_uInt16 nPropId
= pSortStruct
[ i
].nPropId
;
311 rSt
.WriteUInt16( nPropId
)
312 .WriteUInt32( nPropValue
);
314 if ( bHasComplexData
)
316 for ( i
= 0; i
< nSortCount
; i
++ )
318 if ( pSortStruct
[ i
].pBuf
)
319 rSt
.WriteBytes(pSortStruct
[i
].pBuf
, pSortStruct
[i
].nPropSize
);
325 bool EscherPropertyContainer::IsFontWork() const
327 sal_uInt32 nTextPathFlags
= 0;
328 GetOpt( DFF_Prop_gtextFStrikethrough
, nTextPathFlags
);
329 return ( nTextPathFlags
& 0x4000 ) != 0;
332 sal_uInt32
EscherPropertyContainer::ImplGetColor( const sal_uInt32 nSOColor
, bool bSwap
)
336 sal_uInt32 nColor
= nSOColor
& 0xff00; // green
337 nColor
|= (sal_uInt8
)( nSOColor
) << 16; // red
338 nColor
|= (sal_uInt8
)( nSOColor
>> 16 ); // blue
342 return nSOColor
& 0xffffff;
345 sal_uInt32
EscherPropertyContainer::GetGradientColor(
346 const css::awt::Gradient
* pGradient
,
347 sal_uInt32 nStartColor
)
349 sal_uInt32 nIntensity
= 100;
354 if ( nStartColor
& 1 )
356 nIntensity
= pGradient
->StartIntensity
;
357 aColor
= pGradient
->StartColor
;
361 nIntensity
= pGradient
->EndIntensity
;
362 aColor
= pGradient
->EndColor
;
365 sal_uInt32 nRed
= ( aColor
.GetRed() * nIntensity
) / 100;
366 sal_uInt32 nGreen
= ( ( aColor
.GetGreen() * nIntensity
) / 100 ) << 8;
367 sal_uInt32 nBlue
= ( ( aColor
.GetBlue() * nIntensity
) / 100 ) << 16;
368 return nRed
| nGreen
| nBlue
;
371 void EscherPropertyContainer::CreateGradientProperties(
372 const css::awt::Gradient
& rGradient
)
374 sal_uInt32 nFillType
= ESCHER_FillShadeScale
;
375 sal_uInt32 nAngle
= 0;
376 sal_uInt32 nFillFocus
= 0;
377 sal_uInt32 nFillLR
= 0;
378 sal_uInt32 nFillTB
= 0;
379 sal_uInt32 nFirstColor
= 0;
380 bool bWriteFillTo
= false;
382 switch ( rGradient
.Style
)
384 case css::awt::GradientStyle_LINEAR
:
385 case css::awt::GradientStyle_AXIAL
:
387 nFillType
= ESCHER_FillShadeScale
;
388 nAngle
= (rGradient
.Angle
* 0x10000) / 10;
389 nFillFocus
= (sal::static_int_cast
<int>(rGradient
.Style
) ==
390 sal::static_int_cast
<int>(GradientStyle::Linear
)) ? 0 : 50;
393 case css::awt::GradientStyle_RADIAL
:
394 case css::awt::GradientStyle_ELLIPTICAL
:
395 case css::awt::GradientStyle_SQUARE
:
396 case css::awt::GradientStyle_RECT
:
398 nFillLR
= (rGradient
.XOffset
* 0x10000) / 100;
399 nFillTB
= (rGradient
.YOffset
* 0x10000) / 100;
400 if ( ((nFillLR
> 0) && (nFillLR
< 0x10000)) || ((nFillTB
> 0) && (nFillTB
< 0x10000)) )
401 nFillType
= ESCHER_FillShadeShape
;
403 nFillType
= ESCHER_FillShadeCenter
;
408 case css::awt::GradientStyle_MAKE_FIXED_SIZE
: break;
410 AddOpt( ESCHER_Prop_fillType
, nFillType
);
411 AddOpt( ESCHER_Prop_fillAngle
, nAngle
);
412 AddOpt( ESCHER_Prop_fillColor
, GetGradientColor( &rGradient
, nFirstColor
) );
413 AddOpt( ESCHER_Prop_fillBackColor
, GetGradientColor( &rGradient
, nFirstColor
^ 1 ) );
414 AddOpt( ESCHER_Prop_fillFocus
, nFillFocus
);
417 AddOpt( ESCHER_Prop_fillToLeft
, nFillLR
);
418 AddOpt( ESCHER_Prop_fillToTop
, nFillTB
);
419 AddOpt( ESCHER_Prop_fillToRight
, nFillLR
);
420 AddOpt( ESCHER_Prop_fillToBottom
, nFillTB
);
424 void EscherPropertyContainer::CreateGradientProperties(
425 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
, bool bTransparentGradient
)
428 css::awt::Gradient
const * pGradient
= nullptr;
430 sal_uInt32 nFillType
= ESCHER_FillShadeScale
;
431 sal_Int32 nAngle
= 0;
432 sal_uInt32 nFillFocus
= 0;
433 sal_uInt32 nFillLR
= 0;
434 sal_uInt32 nFillTB
= 0;
435 sal_uInt32 nFirstColor
= 0;// like the control var nChgColors in import logic
436 bool bWriteFillTo
= false;
438 // Transparency gradient: Means the third setting in transparency page is set
439 if (bTransparentGradient
&& EscherPropertyValueHelper::GetPropertyValue(
440 aAny
, rXPropSet
, "FillTransparenceGradient" ) )
442 pGradient
= o3tl::doAccess
<css::awt::Gradient
>(aAny
);
444 css::uno::Any aAnyTemp
;
445 const rtl::OUString
aPropName( "FillStyle" );
446 if ( EscherPropertyValueHelper::GetPropertyValue(
447 aAnyTemp
, rXPropSet
, aPropName
) )
449 css::drawing::FillStyle eFS
;
450 if ( ! ( aAnyTemp
>>= eFS
) )
451 eFS
= css::drawing::FillStyle_SOLID
;
452 // solid and transparency
453 if ( eFS
== css::drawing::FillStyle_SOLID
)
455 if ( EscherPropertyValueHelper::GetPropertyValue(
456 aAnyTemp
, rXPropSet
, "FillColor" ) )
458 const_cast<css::awt::Gradient
*>(pGradient
)->StartColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAnyTemp
), false );
459 const_cast<css::awt::Gradient
*>(pGradient
)->EndColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAnyTemp
), false );
462 // gradient and transparency.
463 else if( eFS
== css::drawing::FillStyle_GRADIENT
)
465 if ( EscherPropertyValueHelper::GetPropertyValue(
466 aAny
, rXPropSet
, "FillGradient" ) )
467 pGradient
= o3tl::doAccess
<css::awt::Gradient
>(aAny
);
472 // Not transparency gradient
473 else if ( EscherPropertyValueHelper::GetPropertyValue(
474 aAny
, rXPropSet
, "FillGradient" ) )
476 pGradient
= o3tl::doAccess
<css::awt::Gradient
>(aAny
);
481 switch ( pGradient
->Style
)
483 case css::awt::GradientStyle_LINEAR
:
484 case css::awt::GradientStyle_AXIAL
:
486 nFillType
= ESCHER_FillShadeScale
;
487 nAngle
= pGradient
->Angle
;
488 while ( nAngle
> 0 ) nAngle
-= 3600;
489 while ( nAngle
<= -3600 ) nAngle
+= 3600;
490 // Value of the real number = Integral + (Fractional / 65536.0)
491 nAngle
= ( nAngle
* 0x10000) / 10;
493 nFillFocus
= (pGradient
->Style
== css::awt::GradientStyle_LINEAR
) ?
494 ( pGradient
->XOffset
+ pGradient
->YOffset
)/2 : -50;
496 nFirstColor
=nFirstColor
^ 1;
498 nFirstColor
=nFirstColor
^ 1;
501 case css::awt::GradientStyle_RADIAL
:
502 case css::awt::GradientStyle_ELLIPTICAL
:
503 case css::awt::GradientStyle_SQUARE
:
504 case css::awt::GradientStyle_RECT
:
506 // according to the import logic and rect type fill** value
507 nFillLR
= (pGradient
->XOffset
* 0x10000) / 100;
508 nFillTB
= (pGradient
->YOffset
* 0x10000) / 100;
509 if ( ((nFillLR
> 0) && (nFillLR
< 0x10000)) || ((nFillTB
> 0) && (nFillTB
< 0x10000)) )
510 nFillType
= ESCHER_FillShadeShape
;
512 nFillType
= ESCHER_FillShadeCenter
;
521 AddOpt( ESCHER_Prop_fillType
, nFillType
);
522 AddOpt( ESCHER_Prop_fillAngle
, nAngle
);
523 AddOpt( ESCHER_Prop_fillColor
, GetGradientColor( pGradient
, nFirstColor
) );
524 AddOpt( ESCHER_Prop_fillBackColor
, GetGradientColor( pGradient
, nFirstColor
^ 1 ) );
525 AddOpt( ESCHER_Prop_fillFocus
, nFillFocus
);
528 // according to rect type fillTo** value
531 AddOpt( ESCHER_Prop_fillToLeft
, nFillLR
);
532 AddOpt( ESCHER_Prop_fillToRight
, nFillLR
);
536 AddOpt( ESCHER_Prop_fillToTop
, nFillTB
);
537 AddOpt( ESCHER_Prop_fillToBottom
, nFillTB
);
541 // Transparency gradient
542 if (bTransparentGradient
&& EscherPropertyValueHelper::GetPropertyValue(
543 aAny
, rXPropSet
, "FillTransparenceGradient" ) )
545 pGradient
= o3tl::doAccess
<css::awt::Gradient
>(aAny
);
548 sal_uInt32 nBlue
= GetGradientColor( pGradient
, nFirstColor
) >> 16;
549 AddOpt( ESCHER_Prop_fillOpacity
,( ( 100 - ( nBlue
* 100 / 255 ) ) << 16 ) / 100 );
550 nBlue
= GetGradientColor( pGradient
, nFirstColor
^ 1 ) >>16 ;
551 AddOpt( ESCHER_Prop_fillBackOpacity
,( ( 100 - ( nBlue
* 100 / 255 ) ) << 16 )/ 100 );
556 void EscherPropertyContainer::CreateFillProperties(
557 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
558 bool bEdge
, const css::uno::Reference
< css::drawing::XShape
> & rXShape
)
562 SdrObject
* pObj
= GetSdrObjectFromXShape( rXShape
);
565 SfxItemSet
aAttr( pObj
->GetMergedItemSet() );
566 // tranparency with gradient. Means the third setting in transparency page is set
567 bool bTransparentGradient
= ( aAttr
.GetItemState( XATTR_FILLFLOATTRANSPARENCE
) == SfxItemState::SET
) &&
568 static_cast<const XFillFloatTransparenceItem
&>( aAttr
.Get( XATTR_FILLFLOATTRANSPARENCE
) ).IsEnabled();
569 CreateFillProperties( rXPropSet
, bEdge
, bTransparentGradient
);
574 void EscherPropertyContainer::CreateFillProperties(
575 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
576 bool bEdge
, bool bTransparentGradient
)
580 AddOpt( ESCHER_Prop_WrapText
, ESCHER_WrapNone
);
581 AddOpt( ESCHER_Prop_AnchorText
, ESCHER_AnchorMiddle
);
582 const OUString
aPropName( "FillStyle" );
584 if ( EscherPropertyValueHelper::GetPropertyValue(
585 aAny
, rXPropSet
, aPropName
) )
587 css::drawing::FillStyle eFS
;
588 if ( ! ( aAny
>>= eFS
) )
589 eFS
= css::drawing::FillStyle_SOLID
;
590 sal_uInt32 nFillBackColor
= 0;
593 case css::drawing::FillStyle_GRADIENT
:
595 CreateGradientProperties( rXPropSet
, bTransparentGradient
);
596 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x140014 );
600 case css::drawing::FillStyle_BITMAP
:
602 CreateGraphicProperties( rXPropSet
, "FillBitmapURL", true );
603 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x140014 );
604 AddOpt( ESCHER_Prop_fillBackColor
, nFillBackColor
);
607 case css::drawing::FillStyle_HATCH
:
609 CreateGraphicProperties( rXPropSet
, "FillHatch", true );
612 case css::drawing::FillStyle_SOLID
:
615 if ( bTransparentGradient
)
616 CreateGradientProperties( rXPropSet
, bTransparentGradient
);
619 css::beans::PropertyState ePropState
= EscherPropertyValueHelper::GetPropertyState(
620 rXPropSet
, aPropName
);
621 if ( ePropState
== css::beans::PropertyState_DIRECT_VALUE
)
622 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillSolid
);
624 if ( EscherPropertyValueHelper::GetPropertyValue(
625 aAny
, rXPropSet
, "FillColor" ) )
627 sal_uInt32 nFillColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
) );
628 nFillBackColor
= nFillColor
^ 0xffffff;
629 AddOpt( ESCHER_Prop_fillColor
, nFillColor
);
631 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100010 );
632 AddOpt( ESCHER_Prop_fillBackColor
, nFillBackColor
);
636 case css::drawing::FillStyle_NONE
:
637 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100000 );
640 if ( eFS
!= css::drawing::FillStyle_NONE
)
642 sal_uInt16 nTransparency
= ( EscherPropertyValueHelper::GetPropertyValue(
643 aAny
, rXPropSet
, "FillTransparence", true ) )
644 ? *o3tl::doAccess
<sal_Int16
>(aAny
) : 0;
646 AddOpt( ESCHER_Prop_fillOpacity
, ( ( 100 - nTransparency
) << 16 ) / 100 );
649 CreateLineProperties( rXPropSet
, bEdge
);
652 void EscherPropertyContainer::CreateTextProperties(
653 const uno::Reference
< beans::XPropertySet
> & rXPropSet
, sal_uInt32 nTextId
,
654 const bool bIsCustomShape
, const bool bIsTextFrame
)
657 text::WritingMode
eWM( text::WritingMode_LR_TB
);
658 drawing::TextVerticalAdjust
eVA( drawing::TextVerticalAdjust_TOP
);
659 drawing::TextHorizontalAdjust
eHA( drawing::TextHorizontalAdjust_LEFT
);
661 sal_Int32
nLeft ( 0 );
662 sal_Int32
nTop ( 0 );
663 sal_Int32
nRight ( 0 );
664 sal_Int32
nBottom ( 0 );
666 // used with normal shapes:
667 bool bAutoGrowWidth ( false );
668 const bool bAutoGrowHeight ( false ); //#ii63936 not setting autogrowheight, because minframeheight would be ignored
669 // used with ashapes:
670 bool bWordWrap ( false );
671 bool bAutoGrowSize ( false );
673 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextWritingMode", true ) )
675 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextVerticalAdjust", true ) )
677 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextHorizontalAdjust", true ) )
679 if ( bIsCustomShape
)
681 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextWordWrap" ) )
683 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextAutoGrowHeight", true ) )
684 aAny
>>= bAutoGrowSize
;
686 else if ( bIsTextFrame
)
688 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextAutoGrowWidth", true ) )
689 aAny
>>= bAutoGrowWidth
;
691 // i63936 not setting autogrowheight, because otherwise
692 // the minframeheight of the text will be ignored
694 // if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", sal_True ) )
695 // aAny >>= bAutoGrowHeight;
697 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextLeftDistance" ) )
699 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextUpperDistance" ) )
701 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextRightDistance" ) )
703 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "TextLowerDistance" ) )
706 ESCHER_AnchorText eAnchor
= ESCHER_AnchorTop
;
707 ESCHER_WrapMode eWrapMode
= ESCHER_WrapSquare
;
708 sal_uInt32 nTextAttr
= 0x40004; // rotate text with shape
710 if ( eWM
== text::WritingMode_TB_RL
)
711 { // vertical writing
714 case drawing::TextHorizontalAdjust_LEFT
:
715 eAnchor
= ESCHER_AnchorBottom
;
717 case drawing::TextHorizontalAdjust_CENTER
:
718 eAnchor
= ESCHER_AnchorMiddle
;
721 case drawing::TextHorizontalAdjust_BLOCK
:
722 case drawing::TextHorizontalAdjust_RIGHT
:
723 eAnchor
= ESCHER_AnchorTop
;
726 if ( eVA
== drawing::TextVerticalAdjust_CENTER
)
730 case ESCHER_AnchorMiddle
:
731 eAnchor
= ESCHER_AnchorMiddleCentered
;
733 case ESCHER_AnchorBottom
:
734 eAnchor
= ESCHER_AnchorBottomCentered
;
737 case ESCHER_AnchorTop
:
738 eAnchor
= ESCHER_AnchorTopCentered
;
742 if ( bIsCustomShape
)
745 eWrapMode
= ESCHER_WrapSquare
;
747 eWrapMode
= ESCHER_WrapNone
;
749 nTextAttr
|= 0x20002;
753 if ( bAutoGrowHeight
)
754 eWrapMode
= ESCHER_WrapNone
;
755 if ( bAutoGrowWidth
)
756 nTextAttr
|= 0x20002;
759 AddOpt( ESCHER_Prop_txflTextFlow
, ESCHER_txflTtoBA
); // rotate text within shape by 90
762 { // normal from left to right
765 case drawing::TextVerticalAdjust_CENTER
:
766 eAnchor
= ESCHER_AnchorMiddle
;
769 case drawing::TextVerticalAdjust_BOTTOM
:
770 eAnchor
= ESCHER_AnchorBottom
;
774 case drawing::TextVerticalAdjust_TOP
:
775 eAnchor
= ESCHER_AnchorTop
;
778 if ( eHA
== drawing::TextHorizontalAdjust_CENTER
)
782 case ESCHER_AnchorMiddle
:
783 eAnchor
= ESCHER_AnchorMiddleCentered
;
785 case ESCHER_AnchorBottom
:
786 eAnchor
= ESCHER_AnchorBottomCentered
;
788 case ESCHER_AnchorTop
:
789 eAnchor
= ESCHER_AnchorTopCentered
;
794 if ( bIsCustomShape
)
797 eWrapMode
= ESCHER_WrapSquare
;
799 eWrapMode
= ESCHER_WrapNone
;
801 nTextAttr
|= 0x20002;
805 if ( bAutoGrowWidth
)
806 eWrapMode
= ESCHER_WrapNone
;
807 if ( bAutoGrowHeight
)
808 nTextAttr
|= 0x20002;
811 AddOpt( ESCHER_Prop_dxTextLeft
, nLeft
* 360 );
812 AddOpt( ESCHER_Prop_dxTextRight
, nRight
* 360 );
813 AddOpt( ESCHER_Prop_dyTextTop
, nTop
* 360 );
814 AddOpt( ESCHER_Prop_dyTextBottom
, nBottom
* 360 );
816 AddOpt( ESCHER_Prop_WrapText
, eWrapMode
);
817 AddOpt( ESCHER_Prop_AnchorText
, eAnchor
);
818 AddOpt( ESCHER_Prop_FitTextToShape
, nTextAttr
);
821 AddOpt( ESCHER_Prop_lTxid
, nTextId
);
823 // n#404221: In case of rotation we need to write the txtflTextFlow
825 // fdo#58204: not custom shapes (TODO: other cases when it doesn't work?)
826 if (bIsTextFrame
&& !bIsCustomShape
)
828 sal_uInt16 nAngle
= EscherPropertyValueHelper::GetPropertyValue(
829 aAny
, rXPropSet
, "RotateAngle", true ) ?
830 (sal_uInt16
)( ( *o3tl::doAccess
<sal_Int32
>(aAny
) ) + 5 ) / 10 : 0;
833 AddOpt( ESCHER_Prop_txflTextFlow
, ESCHER_txflBtoT
);
837 AddOpt( ESCHER_Prop_txflTextFlow
, ESCHER_txflTtoBA
);
842 bool EscherPropertyContainer::GetLineArrow( const bool bLineStart
,
843 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
844 ESCHER_LineEnd
& reLineEnd
, sal_Int32
& rnArrowLength
, sal_Int32
& rnArrowWidth
)
846 const OUString
sLine ( bLineStart
? OUString("LineStart") : OUString("LineEnd") );
847 const OUString
sLineName ( bLineStart
? OUString("LineStartName") : OUString("LineEndName") );
849 bool bIsArrow
= false;
852 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, sLine
) )
854 tools::PolyPolygon
aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aAny
) );
855 if ( aPolyPoly
.Count() && aPolyPoly
[ 0 ].GetSize() )
859 reLineEnd
= ESCHER_LineArrowEnd
;
863 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, sLineName
) )
865 OUString aArrowStartName
= *o3tl::doAccess
<OUString
>(aAny
);
866 sal_Int16 nWhich
= bLineStart
? XATTR_LINESTART
: XATTR_LINEEND
;
868 OUString aApiName
= SvxUnogetApiNameForItem(nWhich
, aArrowStartName
);
869 bool bIsMapped
= true;
870 if ( !aApiName
.isEmpty() )
873 // TODO: calculate the best option for ArrowLength and ArrowWidth
874 if ( aApiName
== "Arrow concave" )
875 reLineEnd
= ESCHER_LineArrowStealthEnd
;
876 else if ( aApiName
== "Square 45" )
877 reLineEnd
= ESCHER_LineArrowDiamondEnd
;
878 else if ( aApiName
== "Small Arrow" )
879 reLineEnd
= ESCHER_LineArrowEnd
;
880 else if ( aApiName
== "Dimension Lines" )
884 reLineEnd
= ESCHER_LineArrowOvalEnd
;
886 else if ( aApiName
== "Double Arrow" )
887 reLineEnd
= ESCHER_LineArrowEnd
;
888 else if ( aApiName
== "Rounded short Arrow" )
889 reLineEnd
= ESCHER_LineArrowEnd
;
890 else if ( aApiName
== "Symmetric Arrow" )
891 reLineEnd
= ESCHER_LineArrowEnd
;
892 else if ( aApiName
== "Line Arrow" )
893 reLineEnd
= ESCHER_LineArrowOpenEnd
;
894 else if ( aApiName
== "Rounded large Arrow" )
895 reLineEnd
= ESCHER_LineArrowEnd
;
896 else if ( aApiName
== "Circle" )
897 reLineEnd
= ESCHER_LineArrowOvalEnd
;
898 else if ( aApiName
== "Square" )
899 reLineEnd
= ESCHER_LineArrowDiamondEnd
;
900 else if ( aApiName
== "Arrow" )
901 reLineEnd
= ESCHER_LineArrowEnd
;
906 if ( !bIsMapped
&& comphelper::string::getTokenCount(aArrowStartName
, ' ') == 2 )
909 OUString
aArrowName( aArrowStartName
.getToken( 0, ' ' ) );
910 if ( aArrowName
== "msArrowEnd" )
911 reLineEnd
= ESCHER_LineArrowEnd
;
912 else if ( aArrowName
== "msArrowOpenEnd" )
913 reLineEnd
= ESCHER_LineArrowOpenEnd
;
914 else if ( aArrowName
== "msArrowStealthEnd" )
915 reLineEnd
= ESCHER_LineArrowStealthEnd
;
916 else if ( aArrowName
== "msArrowDiamondEnd" )
917 reLineEnd
= ESCHER_LineArrowDiamondEnd
;
918 else if ( aArrowName
== "msArrowOvalEnd" )
919 reLineEnd
= ESCHER_LineArrowOvalEnd
;
923 // now we have the arrow, and try to determine the arrow size;
926 OUString
aArrowSize( aArrowStartName
.getToken( 1, ' ' ) );
927 sal_Int32 nArrowSize
= aArrowSize
.toInt32();
928 rnArrowWidth
= ( nArrowSize
- 1 ) / 3;
929 rnArrowLength
= nArrowSize
- ( rnArrowWidth
* 3 ) - 1;
938 void EscherPropertyContainer::CreateLineProperties(
939 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
943 sal_uInt32 nLineFlags
= 0x80008;
945 ESCHER_LineEnd eLineEnd
;
946 sal_Int32 nArrowLength
;
947 sal_Int32 nArrowWidth
;
949 bool bSwapLineEnds
= false;
950 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "CircleKind", true ) )
952 css::drawing::CircleKind eCircleKind
;
953 if ( aAny
>>= eCircleKind
)
955 if ( eCircleKind
== css::drawing::CircleKind_ARC
)
956 bSwapLineEnds
= true;
959 if ( GetLineArrow( !bSwapLineEnds
, rXPropSet
, eLineEnd
, nArrowLength
, nArrowWidth
) )
961 AddOpt( ESCHER_Prop_lineStartArrowLength
, nArrowLength
);
962 AddOpt( ESCHER_Prop_lineStartArrowWidth
, nArrowWidth
);
963 AddOpt( ESCHER_Prop_lineStartArrowhead
, eLineEnd
);
964 nLineFlags
|= 0x100010;
966 if ( GetLineArrow( bSwapLineEnds
, rXPropSet
, eLineEnd
, nArrowLength
, nArrowWidth
) )
968 AddOpt( ESCHER_Prop_lineEndArrowLength
, nArrowLength
);
969 AddOpt( ESCHER_Prop_lineEndArrowWidth
, nArrowWidth
);
970 AddOpt( ESCHER_Prop_lineEndArrowhead
, eLineEnd
);
971 nLineFlags
|= 0x100010;
975 if(EscherPropertyValueHelper::GetPropertyValue(aAny
, rXPropSet
, "LineCap"))
977 css::drawing::LineCap
aLineCap(css::drawing::LineCap_BUTT
);
979 if(aAny
>>= aLineCap
)
983 default: /* css::drawing::LineCap_BUTT */
985 AddOpt(ESCHER_Prop_lineEndCapStyle
, ESCHER_LineEndCapFlat
);
988 case css::drawing::LineCap_ROUND
:
990 AddOpt(ESCHER_Prop_lineEndCapStyle
, ESCHER_LineEndCapRound
);
993 case css::drawing::LineCap_SQUARE
:
995 AddOpt(ESCHER_Prop_lineEndCapStyle
, ESCHER_LineEndCapSquare
);
1002 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "LineStyle" ) )
1004 css::drawing::LineStyle eLS
;
1009 case css::drawing::LineStyle_NONE
:
1010 AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x90000 ); // 80000
1013 case css::drawing::LineStyle_DASH
:
1015 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "LineDash" ) )
1017 ESCHER_LineDashing eDash
= ESCHER_LineSolid
;
1018 auto pLineDash
= o3tl::doAccess
<css::drawing::LineDash
>(aAny
);
1019 sal_Int32 nDistance
= pLineDash
->Distance
<< 1;
1020 switch ( pLineDash
->Style
)
1022 case css::drawing::DashStyle_ROUND
:
1023 case css::drawing::DashStyle_ROUNDRELATIVE
:
1024 AddOpt( ESCHER_Prop_lineEndCapStyle
, 0 ); // set Style Round
1028 if ( ((!(pLineDash
->Dots
)) || (!(pLineDash
->Dashes
)) ) || ( pLineDash
->DotLen
== pLineDash
->DashLen
) )
1030 sal_Int32 nLen
= pLineDash
->DotLen
;
1031 if ( pLineDash
->Dashes
)
1032 nLen
= pLineDash
->DashLen
;
1034 if ( nLen
>= nDistance
)
1035 eDash
= ESCHER_LineLongDashGEL
;
1036 else if ( pLineDash
->Dots
)
1037 eDash
= ESCHER_LineDotSys
;
1039 eDash
= ESCHER_LineDashGEL
;
1043 if ( pLineDash
->Dots
!= pLineDash
->Dashes
)
1045 if ( ( pLineDash
->DashLen
> nDistance
) || ( pLineDash
->DotLen
> nDistance
) )
1046 eDash
= ESCHER_LineLongDashDotDotGEL
;
1048 eDash
= ESCHER_LineDashDotDotSys
;
1052 if ( ( pLineDash
->DashLen
> nDistance
) || ( pLineDash
->DotLen
> nDistance
) )
1053 eDash
= ESCHER_LineLongDashDotGEL
;
1055 eDash
= ESCHER_LineDashDotGEL
;
1059 AddOpt( ESCHER_Prop_lineDashing
, eDash
);
1063 case css::drawing::LineStyle_SOLID
:
1066 AddOpt( ESCHER_Prop_fNoLineDrawDash
, nLineFlags
);
1071 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "LineColor" ) )
1073 sal_uInt32 nLineColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
) );
1074 AddOpt( ESCHER_Prop_lineColor
, nLineColor
);
1075 AddOpt( ESCHER_Prop_lineBackColor
, nLineColor
^ 0xffffff );
1079 sal_uInt32 nLineSize
= ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "LineWidth" ) )
1080 ? *o3tl::doAccess
<sal_uInt32
>(aAny
) : 0;
1081 if ( nLineSize
> 1 )
1082 AddOpt( ESCHER_Prop_lineWidth
, nLineSize
* 360 ); // 100TH MM -> PT , 1PT = 12700 EMU
1084 ESCHER_LineJoin eLineJoin
= ESCHER_LineJoinMiter
;
1085 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "LineJoint", true ) )
1087 css::drawing::LineJoint eLJ
;
1092 case css::drawing::LineJoint_NONE
:
1093 case css::drawing::LineJoint_BEVEL
:
1094 eLineJoin
= ESCHER_LineJoinBevel
;
1097 case css::drawing::LineJoint_MIDDLE
:
1098 case css::drawing::LineJoint_MITER
:
1099 eLineJoin
= ESCHER_LineJoinMiter
;
1101 case css::drawing::LineJoint_ROUND
:
1102 eLineJoin
= ESCHER_LineJoinRound
;
1107 AddOpt( ESCHER_Prop_lineJoinStyle
, eLineJoin
);
1109 if ( EscherPropertyValueHelper::GetPropertyValue(
1110 aAny
, rXPropSet
, "LineTransparence", true ) )
1112 sal_Int16 nTransparency
= 0;
1113 if ( aAny
>>= nTransparency
)
1114 AddOpt( ESCHER_Prop_lineOpacity
, ( ( 100 - nTransparency
) << 16 ) / 100 );
1120 AddOpt( ESCHER_Prop_fFillOK
, 0x1001 );
1121 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100000 );
1125 static Size
lcl_SizeToEmu(Size aPrefSize
, const MapMode
& aPrefMapMode
)
1128 if (aPrefMapMode
== MapUnit::MapPixel
)
1129 aRetSize
= Application::GetDefaultDevice()->PixelToLogic( aPrefSize
, MapUnit::Map100thMM
);
1131 aRetSize
= OutputDevice::LogicToLogic( aPrefSize
, aPrefMapMode
, MapUnit::Map100thMM
);
1135 void EscherPropertyContainer::ImplCreateGraphicAttributes( const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
1136 sal_uInt32 nBlibId
, bool bCreateCroppingAttributes
)
1140 sal_uInt32 nPicFlags
= 0;
1141 css::drawing::ColorMode
eColorMode( css::drawing::ColorMode_STANDARD
);
1142 sal_Int16 nLuminance
= 0;
1143 sal_Int32 nContrast
= 0;
1145 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "GraphicColorMode" ) )
1146 aAny
>>= eColorMode
;
1147 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "AdjustLuminance" ) )
1148 aAny
>>= nLuminance
;
1149 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "AdjustContrast" ) )
1151 sal_Int16 nC
= sal_Int16();
1156 if ( eColorMode
== css::drawing::ColorMode_WATERMARK
)
1158 eColorMode
= css::drawing::ColorMode_STANDARD
;
1160 if ( nLuminance
> 100 )
1163 if ( nContrast
< -100 )
1166 if ( eColorMode
== css::drawing::ColorMode_GREYS
)
1167 nPicFlags
|= 0x40004;
1168 else if ( eColorMode
== css::drawing::ColorMode_MONO
)
1169 nPicFlags
|= 0x60006;
1174 if ( nContrast
== 100)
1175 nContrast
= 0x10000;
1176 else if ( nContrast
< 100 )
1178 nContrast
*= 0x10000;
1181 else if ( nContrast
< 200 )
1182 nContrast
= ( 100 * 0x10000 ) / ( 200 - nContrast
);
1184 nContrast
= 0x7fffffff;
1185 AddOpt( ESCHER_Prop_pictureContrast
, nContrast
);
1188 AddOpt( ESCHER_Prop_pictureBrightness
, nLuminance
* 327 );
1190 AddOpt( ESCHER_Prop_pictureActive
, nPicFlags
);
1192 if ( bCreateCroppingAttributes
&& pGraphicProvider
)
1195 MapMode aPrefMapMode
;
1196 if ( pGraphicProvider
->GetPrefSize( nBlibId
, aPrefSize
, aPrefMapMode
) )
1198 Size
aCropSize(lcl_SizeToEmu(aPrefSize
, aPrefMapMode
));
1199 if ( aCropSize
.Width() && aCropSize
.Height() )
1201 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "GraphicCrop" ) )
1203 css::text::GraphicCrop aGraphCrop
;
1204 if ( aAny
>>= aGraphCrop
)
1206 if ( aGraphCrop
.Left
)
1208 sal_uInt32 nLeft
= ( aGraphCrop
.Left
* 65536 ) / aCropSize
.Width();
1209 AddOpt( ESCHER_Prop_cropFromLeft
, nLeft
);
1211 if ( aGraphCrop
.Top
)
1213 sal_uInt32 nTop
= ( aGraphCrop
.Top
* 65536 ) / aCropSize
.Height();
1214 AddOpt( ESCHER_Prop_cropFromTop
, nTop
);
1216 if ( aGraphCrop
.Right
)
1218 sal_uInt32 nRight
= ( aGraphCrop
.Right
* 65536 ) / aCropSize
.Width();
1219 AddOpt( ESCHER_Prop_cropFromRight
, nRight
);
1221 if ( aGraphCrop
.Bottom
)
1223 sal_uInt32 nBottom
= ( aGraphCrop
.Bottom
* 65536 ) / aCropSize
.Height();
1224 AddOpt( ESCHER_Prop_cropFromBottom
, nBottom
);
1233 void EscherPropertyContainer::CreateShapeProperties( const css::uno::Reference
< css::drawing::XShape
> & rXShape
)
1235 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
1236 if ( aXPropSet
.is() )
1240 sal_uInt32 nShapeAttr
= 0;
1241 if (EscherPropertyValueHelper::GetPropertyValue(aAny
, aXPropSet
, "Visible", true) && (aAny
>>= bVal
))
1244 nShapeAttr
|= 0x20002; // set fHidden = true
1246 if (EscherPropertyValueHelper::GetPropertyValue(aAny
, aXPropSet
, "Printable", true) && (aAny
>>= bVal
))
1249 nShapeAttr
|= 0x10000; // set fPrint = false;
1252 AddOpt( ESCHER_Prop_fPrint
, nShapeAttr
);
1256 bool EscherPropertyContainer::CreateOLEGraphicProperties(
1257 const css::uno::Reference
< css::drawing::XShape
> & rXShape
)
1259 bool bRetValue
= false;
1263 SdrObject
* pSdrOLE2( GetSdrObjectFromXShape( rXShape
) ); // SJ: leaving unoapi, because currently there is
1264 if ( pSdrOLE2
&& nullptr != dynamic_cast<const SdrOle2Obj
* > (pSdrOLE2
) ) // no access to the native graphic object
1266 const Graphic
* pGraphic
= static_cast<SdrOle2Obj
*>(pSdrOLE2
)->GetGraphic();
1269 GraphicObject
aGraphicObject( *pGraphic
);
1270 bRetValue
= CreateGraphicProperties( rXShape
,aGraphicObject
);
1277 bool EscherPropertyContainer::CreateGraphicProperties( const css::uno::Reference
< css::drawing::XShape
> & rXShape
, const GraphicObject
& rGraphicObj
)
1279 bool bRetValue
= false;
1280 OString
aUniqueId( rGraphicObj
.GetUniqueID() );
1281 if ( !aUniqueId
.isEmpty() )
1283 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillPicture
);
1284 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
1286 if ( pGraphicProvider
&& pPicOutStrm
&& pShapeBoundRect
&& aXPropSet
.is() )
1289 std::unique_ptr
< css::awt::Rectangle
> pVisArea
;
1290 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "VisibleArea" ) )
1292 pVisArea
.reset(new css::awt::Rectangle
);
1293 aAny
>>= (*pVisArea
);
1295 Rectangle
aRect( Point( 0, 0 ), pShapeBoundRect
->GetSize() );
1296 sal_uInt32 nBlibId
= pGraphicProvider
->GetBlibID( *pPicOutStrm
, aUniqueId
, aRect
, pVisArea
.get() );
1299 AddOpt( ESCHER_Prop_pib
, nBlibId
, true );
1300 ImplCreateGraphicAttributes( aXPropSet
, nBlibId
, false );
1308 bool EscherPropertyContainer::CreateMediaGraphicProperties(
1309 const css::uno::Reference
< css::drawing::XShape
> & rXShape
)
1311 bool bRetValue
= false;
1314 SdrObject
* pSdrMedia( GetSdrObjectFromXShape( rXShape
) ); // SJ: leaving unoapi, because currently there is
1315 if ( dynamic_cast<const SdrMediaObj
* >(pSdrMedia
) != nullptr ) // no access to the native graphic object
1317 GraphicObject
aGraphicObject( static_cast<SdrMediaObj
*>(pSdrMedia
)->getSnapshot() );
1318 bRetValue
= CreateGraphicProperties( rXShape
, aGraphicObject
);
1324 bool EscherPropertyContainer::ImplCreateEmbeddedBmp( const OString
& rUniqueId
)
1326 if( !rUniqueId
.isEmpty() )
1328 EscherGraphicProvider aProvider
;
1329 SvMemoryStream aMemStrm
;
1331 if ( aProvider
.GetBlibID( aMemStrm
, rUniqueId
, aRect
) )
1333 // grab BLIP from stream and insert directly as complex property
1334 // ownership of stream memory goes to complex property
1335 aMemStrm
.ObjectOwnsMemory( false );
1336 sal_uInt8
const * pBuf
= static_cast<sal_uInt8
const *>(aMemStrm
.GetData());
1337 sal_uInt32 nSize
= aMemStrm
.Seek( STREAM_SEEK_TO_END
);
1338 AddOpt( ESCHER_Prop_fillBlip
, true, nSize
, const_cast<sal_uInt8
*>(pBuf
), nSize
);
1345 void EscherPropertyContainer::CreateEmbeddedBitmapProperties(
1346 const OUString
& rBitmapUrl
, css::drawing::BitmapMode eBitmapMode
)
1348 OUString
aVndUrl( "vnd.sun.star.GraphicObject:" );
1349 sal_Int32 nIndex
= rBitmapUrl
.indexOf( aVndUrl
);
1352 nIndex
+= aVndUrl
.getLength();
1353 if( rBitmapUrl
.getLength() > nIndex
)
1355 OString
aUniqueId(OUStringToOString(rBitmapUrl
.copy(nIndex
, rBitmapUrl
.getLength() - nIndex
), RTL_TEXTENCODING_UTF8
));
1356 bool bRetValue
= ImplCreateEmbeddedBmp( aUniqueId
);
1359 // bitmap mode property
1360 bool bRepeat
= eBitmapMode
== css::drawing::BitmapMode_REPEAT
;
1361 AddOpt( ESCHER_Prop_fillType
, bRepeat
? ESCHER_FillTexture
: ESCHER_FillPicture
);
1370 GraphicObject
lclDrawHatch( const css::drawing::Hatch
& rHatch
, const Color
& rBackColor
, bool bFillBackground
, const Rectangle
& rRect
)
1372 // #i121183# For hatch, do no longer create a bitmap with the fixed size of 28x28 pixels. Also
1373 // do not create a bitmap in page size, that would explode file sizes (and have no good quality).
1374 // Better use a MetaFile graphic in page size; thus we have good quality due to vector format and
1375 // no bit file sizes.
1376 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1379 pVDev
->SetOutputSizePixel(Size(2, 2));
1380 pVDev
->EnableOutput(false);
1381 pVDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
1384 pVDev
->SetLineColor();
1385 pVDev
->SetFillColor(bFillBackground
? rBackColor
: Color(COL_TRANSPARENT
));
1386 pVDev
->DrawRect(rRect
);
1387 pVDev
->DrawHatch(tools::PolyPolygon(rRect
), Hatch((HatchStyle
)rHatch
.Style
, Color(rHatch
.Color
), rHatch
.Distance
, (sal_uInt16
)rHatch
.Angle
));
1390 aMtf
.SetPrefMapMode(MapMode(MapUnit::Map100thMM
));
1391 aMtf
.SetPrefSize(rRect
.GetSize());
1393 return GraphicObject(Graphic(aMtf
));
1399 void EscherPropertyContainer::CreateEmbeddedHatchProperties( const css::drawing::Hatch
& rHatch
, const Color
& rBackColor
, bool bFillBackground
)
1401 const Rectangle
aRect(pShapeBoundRect
? *pShapeBoundRect
: Rectangle(Point(0,0), Size(28000, 21000)));
1402 GraphicObject aGraphicObject
= lclDrawHatch( rHatch
, rBackColor
, bFillBackground
, aRect
);
1403 OString aUniqueId
= aGraphicObject
.GetUniqueID();
1404 bool bRetValue
= ImplCreateEmbeddedBmp( aUniqueId
);
1406 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillTexture
);
1410 bool EscherPropertyContainer::CreateGraphicProperties(
1411 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
1412 const OUString
& rSource
, const bool bCreateFillBitmap
, const bool bCreateCroppingAttributes
,
1413 const bool bFillBitmapModeAllowed
, const bool bOOxmlExport
)
1415 bool bRetValue
= false;
1416 bool bCreateFillStyles
= false;
1418 std::unique_ptr
<GraphicAttr
> pGraphicAttr
;
1419 GraphicObject aGraphicObject
;
1420 OUString aGraphicUrl
;
1423 css::drawing::BitmapMode
eBitmapMode( css::drawing::BitmapMode_NO_REPEAT
);
1426 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, rSource
) )
1428 bool bMirrored
= false;
1429 bool bRotate
= true;
1430 bool bIsGraphicMtf
= false;
1431 sal_Int16
nTransparency(0);
1433 sal_Int16
nGreen(0);
1437 sal_uInt16 nAngle
= 0;
1438 if ( rSource
== "MetaFile" )
1440 auto & aSeq
= *o3tl::doAccess
<css::uno::Sequence
<sal_Int8
>>(aAny
);
1441 const sal_Int8
* pAry
= aSeq
.getConstArray();
1442 sal_uInt32 nAryLen
= aSeq
.getLength();
1444 // the metafile is already rotated
1447 if ( pAry
&& nAryLen
)
1450 SvMemoryStream
aTemp( const_cast<sal_Int8
*>(pAry
), nAryLen
, StreamMode::READ
);
1451 sal_uInt32 nErrCode
= GraphicConverter::Import( aTemp
, aGraphic
, ConvertDataFormat::WMF
);
1452 if ( nErrCode
== ERRCODE_NONE
)
1454 aGraphicObject
= aGraphic
;
1455 aUniqueId
= aGraphicObject
.GetUniqueID();
1456 bIsGraphicMtf
= aGraphicObject
.GetType() == GraphicType::GdiMetafile
;
1460 else if ( rSource
== "Bitmap" )
1462 css::uno::Reference
< css::awt::XBitmap
>xBitmap(
1463 aAny
, css::uno::UNO_QUERY
);
1466 css::uno::Reference
< css::awt::XBitmap
> xBmp
;
1467 if ( aAny
>>= xBmp
)
1469 BitmapEx
aBitmapEx( VCLUnoHelper::GetBitmap( xBmp
) );
1470 Graphic
aGraphic( aBitmapEx
);
1471 aGraphicObject
= aGraphic
;
1472 aUniqueId
= aGraphicObject
.GetUniqueID();
1473 bIsGraphicMtf
= aGraphicObject
.GetType() == GraphicType::GdiMetafile
;
1477 else if ( rSource
== "FillBitmapURL" )
1479 aGraphicUrl
= *o3tl::doAccess
<OUString
>(aAny
);
1481 else if ( rSource
== "GraphicURL" )
1483 aGraphicUrl
= *o3tl::doAccess
<OUString
>(aAny
);
1484 bCreateFillStyles
= true;
1486 else if ( rSource
== "FillHatch" )
1488 css::drawing::Hatch aHatch
;
1489 if ( aAny
>>= aHatch
)
1492 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillColor" ) )
1494 aBackColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
), false );
1496 bool bFillBackground
= false;
1497 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBackground", true ) )
1499 aAny
>>= bFillBackground
;
1502 const Rectangle
aRect(Point(0, 0), pShapeBoundRect
? pShapeBoundRect
->GetSize() : Size(28000, 21000));
1503 aGraphicObject
= lclDrawHatch( aHatch
, aBackColor
, bFillBackground
, aRect
);
1504 aUniqueId
= aGraphicObject
.GetUniqueID();
1505 eBitmapMode
= css::drawing::BitmapMode_REPEAT
;
1506 bIsGraphicMtf
= aGraphicObject
.GetType() == GraphicType::GdiMetafile
;
1510 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "IsMirrored", true ) )
1513 // #121074# transparency of graphic is not supported in MS formats, get and apply it
1514 // in the GetTransformedGraphic call in GetBlibID
1515 if(EscherPropertyValueHelper::GetPropertyValue(aAny
, rXPropSet
, "Transparency"))
1517 aAny
>>= nTransparency
;
1520 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "AdjustRed" ) )
1525 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "AdjustGreen" ) )
1530 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "AdjustBlue" ) )
1535 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "Gamma" ) )
1540 if ( bCreateFillBitmap
&& bFillBitmapModeAllowed
)
1542 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBitmapMode", true ) )
1543 aAny
>>= eBitmapMode
;
1547 nAngle
= bRotate
&& EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "RotateAngle", true )
1548 ? (sal_uInt16
)( ( *o3tl::doAccess
<sal_Int32
>(aAny
) ) + 5 ) / 10
1552 if ( aGraphicUrl
.getLength() )
1554 OUString
aVndUrl( "vnd.sun.star.GraphicObject:" );
1555 sal_Int32 nIndex
= aGraphicUrl
.indexOf( aVndUrl
);
1558 nIndex
= nIndex
+ aVndUrl
.getLength();
1559 if ( aGraphicUrl
.getLength() > nIndex
)
1560 aUniqueId
= OUStringToOString(aGraphicUrl
.copy(nIndex
, aGraphicUrl
.getLength() - nIndex
), RTL_TEXTENCODING_UTF8
);
1564 // externally, linked graphic? convert to embedded
1565 // one, if transformations are needed. this is because
1566 // everything < msoxp cannot even handle rotated
1568 // And check whether the graphic link target is
1569 // actually supported by mso.
1570 INetURLObject
aTmp( aGraphicUrl
);
1571 GraphicDescriptor
aDescriptor(aTmp
);
1572 aDescriptor
.Detect();
1573 const GraphicFileFormat nFormat
= aDescriptor
.GetFileFormat();
1575 // can MSO handle it?
1576 if ( bMirrored
|| nAngle
|| nTransparency
|| nRed
|| nGreen
|| nBlue
|| (1.0 != fGamma
) ||
1577 (nFormat
!= GraphicFileFormat::BMP
&&
1578 nFormat
!= GraphicFileFormat::GIF
&&
1579 nFormat
!= GraphicFileFormat::JPG
&&
1580 nFormat
!= GraphicFileFormat::PNG
&&
1581 nFormat
!= GraphicFileFormat::TIF
&&
1582 nFormat
!= GraphicFileFormat::PCT
&&
1583 nFormat
!= GraphicFileFormat::WMF
&&
1584 nFormat
!= GraphicFileFormat::EMF
) )
1586 std::unique_ptr
<SvStream
> pIn(::utl::UcbStreamHelper::CreateStream(
1587 aTmp
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), StreamMode::READ
));
1591 sal_uInt32 nErrCode
= GraphicConverter::Import( *pIn
, aGraphic
);
1593 if ( nErrCode
== ERRCODE_NONE
)
1596 aGraphicObject
= aGraphic
;
1597 aUniqueId
= aGraphicObject
.GetUniqueID();
1599 // else: simply keep the graphic link
1602 if ( aUniqueId
.isEmpty() )
1604 if ( pGraphicProvider
)
1606 const OUString
& rBaseURI( pGraphicProvider
->GetBaseURI() );
1607 INetURLObject
aBaseURI( rBaseURI
);
1608 if( aBaseURI
.GetProtocol() == aTmp
.GetProtocol() )
1610 OUString
aRelUrl( INetURLObject::GetRelURL( rBaseURI
, aGraphicUrl
) );
1611 if ( !aRelUrl
.isEmpty() )
1612 aGraphicUrl
= aRelUrl
;
1619 if ( aGraphicUrl
.getLength() || !aUniqueId
.isEmpty() )
1621 if(bMirrored
|| nTransparency
|| nRed
|| nGreen
|| nBlue
|| (1.0 != fGamma
))
1623 pGraphicAttr
.reset(new GraphicAttr
);
1627 pGraphicAttr
->SetMirrorFlags(BmpMirrorFlags::Horizontal
);
1632 pGraphicAttr
->SetTransparency((nTransparency
* 255) / 100);
1637 pGraphicAttr
->SetChannelR(nRed
);
1642 pGraphicAttr
->SetChannelG(nGreen
);
1647 pGraphicAttr
->SetChannelB(nBlue
);
1652 pGraphicAttr
->SetGamma(fGamma
);
1656 if(nAngle
&& bIsGraphicMtf
)
1658 AddOpt( ESCHER_Prop_Rotation
, ( ( ((sal_Int32
)nAngle
<< 16 ) / 10 ) + 0x8000 ) &~ 0xffff );
1661 if ( eBitmapMode
== css::drawing::BitmapMode_REPEAT
)
1663 sal_Int32 nSizeX
= 0,nSizeY
= 0,nOffsetX
= 0,nOffsetY
= 0,nPosOffsetX
= 0,nPosOffsetY
= 0;
1664 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBitmapSizeX", true ) )
1668 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBitmapSizeY", true ) )
1672 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBitmapOffsetX", true ) )
1676 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBitmapOffsetY", true ) )
1680 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBitmapPositionOffsetX", true ) )
1682 aAny
>>= nPosOffsetX
;
1684 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "FillBitmapPositionOffsetY", true ) )
1686 aAny
>>= nPosOffsetY
;
1688 if(nSizeX
== -100 && nSizeY
== -100 && nOffsetX
== 0 && nOffsetY
== 0 && nPosOffsetX
== 0 && nPosOffsetY
== 0)
1689 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillPicture
);
1691 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillTexture
);
1694 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillPicture
);
1696 if ( !aUniqueId
.isEmpty() )
1698 // write out embedded graphic
1699 if ( pGraphicProvider
&& pPicOutStrm
&& pShapeBoundRect
)
1701 Rectangle
aRect( Point( 0, 0 ), pShapeBoundRect
->GetSize() );
1702 const sal_uInt32
nBlibId(pGraphicProvider
->GetBlibID(*pPicOutStrm
, aUniqueId
, aRect
, nullptr, pGraphicAttr
.get()));
1706 if(bCreateFillBitmap
)
1708 AddOpt(ESCHER_Prop_fillBlip
, nBlibId
, true);
1712 AddOpt( ESCHER_Prop_pib
, nBlibId
, true );
1713 ImplCreateGraphicAttributes( rXPropSet
, nBlibId
, bCreateCroppingAttributes
);
1721 EscherGraphicProvider aProvider
;
1722 SvMemoryStream aMemStrm
;
1725 if ( aProvider
.GetBlibID( aMemStrm
, aUniqueId
, aRect
, nullptr, pGraphicAttr
.get(), bOOxmlExport
) )
1727 // grab BLIP from stream and insert directly as complex property
1728 // ownership of stream memory goes to complex property
1729 aMemStrm
.ObjectOwnsMemory( false );
1730 sal_uInt8
const * pBuf
= static_cast<sal_uInt8
const *>(aMemStrm
.GetData());
1731 sal_uInt32 nSize
= aMemStrm
.Seek( STREAM_SEEK_TO_END
);
1732 AddOpt( ESCHER_Prop_fillBlip
, true, nSize
, const_cast<sal_uInt8
*>(pBuf
), nSize
);
1737 // write out link to graphic
1740 OSL_ASSERT(aGraphicUrl
.getLength());
1742 AddOpt( ESCHER_Prop_pibName
, aGraphicUrl
);
1743 sal_uInt32 nPibFlags
=0;
1744 GetOpt( ESCHER_Prop_pibFlags
, nPibFlags
);
1745 AddOpt( ESCHER_Prop_pibFlags
,
1746 ESCHER_BlipFlagLinkToFile
|ESCHER_BlipFlagFile
|ESCHER_BlipFlagDoNotSave
| nPibFlags
);
1750 pGraphicAttr
.reset();
1751 if ( bCreateFillStyles
)
1752 CreateFillProperties( rXPropSet
, true );
1757 tools::PolyPolygon
EscherPropertyContainer::GetPolyPolygon( const css::uno::Reference
< css::drawing::XShape
> & rXShape
)
1759 tools::PolyPolygon aRetPolyPoly
;
1760 css::uno::Reference
< css::beans::XPropertySet
> aXPropSet
;
1761 css::uno::Any
aAny( rXShape
->queryInterface(
1762 cppu::UnoType
<css::beans::XPropertySet
>::get()));
1764 OUString
sPolyPolygonBezier ( "PolyPolygonBezier" );
1765 OUString
sPolyPolygon ( "PolyPolygon" );
1766 OUString
sPolygon ( "Polygon" );
1768 if ( aAny
>>= aXPropSet
)
1770 bool bHasProperty
= EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, sPolyPolygonBezier
, true );
1771 if ( !bHasProperty
)
1772 bHasProperty
= EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, sPolyPolygon
, true );
1773 if ( !bHasProperty
)
1774 bHasProperty
= EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, sPolygon
, true );
1776 aRetPolyPoly
= GetPolyPolygon( aAny
);
1778 return aRetPolyPoly
;
1781 tools::PolyPolygon
EscherPropertyContainer::GetPolyPolygon( const css::uno::Any
& rAny
)
1783 bool bNoError
= true;
1785 tools::Polygon aPolygon
;
1786 tools::PolyPolygon aPolyPolygon
;
1788 if ( rAny
.getValueType() == cppu::UnoType
<css::drawing::PolyPolygonBezierCoords
>::get())
1790 auto pSourcePolyPolygon
1791 = o3tl::doAccess
<css::drawing::PolyPolygonBezierCoords
>(rAny
);
1792 sal_uInt16 nOuterSequenceCount
= (sal_uInt16
)pSourcePolyPolygon
->Coordinates
.getLength();
1794 // get pointer of inner sequences
1795 css::drawing::PointSequence
const * pOuterSequence
= pSourcePolyPolygon
->Coordinates
.getConstArray();
1796 css::drawing::FlagSequence
const * pOuterFlags
= pSourcePolyPolygon
->Flags
.getConstArray();
1798 bNoError
= pOuterSequence
&& pOuterFlags
;
1801 sal_uInt16 a
, b
, nInnerSequenceCount
;
1802 css::awt::Point
const * pArray
;
1804 // this will be a polygon set
1805 for ( a
= 0; a
< nOuterSequenceCount
; a
++ )
1807 css::drawing::PointSequence
const * pInnerSequence
= pOuterSequence
++;
1808 css::drawing::FlagSequence
const * pInnerFlags
= pOuterFlags
++;
1810 bNoError
= pInnerSequence
&& pInnerFlags
;
1813 // get pointer to arrays
1814 pArray
= pInnerSequence
->getConstArray();
1815 css::drawing::PolygonFlags
const * pFlags
= pInnerFlags
->getConstArray();
1817 if ( pArray
&& pFlags
)
1819 nInnerSequenceCount
= (sal_uInt16
)pInnerSequence
->getLength();
1820 aPolygon
= tools::Polygon( nInnerSequenceCount
);
1821 for( b
= 0; b
< nInnerSequenceCount
; b
++)
1823 css::drawing::PolygonFlags ePolyFlags
= *pFlags
++;
1824 css::awt::Point
aPoint( *(pArray
++) );
1825 aPolygon
[ b
] = Point( aPoint
.X
, aPoint
.Y
);
1826 aPolygon
.SetFlags( b
, static_cast<PolyFlags
>(ePolyFlags
) );
1828 if ( ePolyFlags
== css::drawing::PolygonFlags_CONTROL
)
1831 aPolyPolygon
.Insert( aPolygon
);
1837 else if ( auto pSourcePolyPolygon
= o3tl::tryAccess
<css::drawing::PointSequenceSequence
>(rAny
) )
1839 sal_uInt16 nOuterSequenceCount
= (sal_uInt16
)pSourcePolyPolygon
->getLength();
1841 // get pointer to inner sequences
1842 css::drawing::PointSequence
const * pOuterSequence
= pSourcePolyPolygon
->getConstArray();
1843 bNoError
= pOuterSequence
!= nullptr;
1846 sal_uInt16 a
, b
, nInnerSequenceCount
;
1848 // this will be a polygon set
1849 for( a
= 0; a
< nOuterSequenceCount
; a
++ )
1851 css::drawing::PointSequence
const * pInnerSequence
= pOuterSequence
++;
1852 bNoError
= pInnerSequence
!= nullptr;
1855 // get pointer to arrays
1856 css::awt::Point
const * pArray
=
1857 pInnerSequence
->getConstArray();
1858 if ( pArray
!= nullptr )
1860 nInnerSequenceCount
= (sal_uInt16
)pInnerSequence
->getLength();
1861 aPolygon
= tools::Polygon( nInnerSequenceCount
);
1862 for( b
= 0; b
< nInnerSequenceCount
; b
++)
1864 aPolygon
[ b
] = Point( pArray
->X
, pArray
->Y
);
1867 aPolyPolygon
.Insert( aPolygon
);
1873 else if ( auto pInnerSequence
= o3tl::tryAccess
<css::drawing::PointSequence
>(rAny
) )
1875 bNoError
= pInnerSequence
!= nullptr;
1878 sal_uInt16 a
, nInnerSequenceCount
;
1880 // get pointer to arrays
1881 css::awt::Point
const * pArray
= pInnerSequence
->getConstArray();
1882 if ( pArray
!= nullptr )
1884 nInnerSequenceCount
= (sal_uInt16
)pInnerSequence
->getLength();
1885 aPolygon
= tools::Polygon( nInnerSequenceCount
);
1886 for( a
= 0; a
< nInnerSequenceCount
; a
++)
1888 aPolygon
[ a
] = Point( pArray
->X
, pArray
->Y
);
1891 aPolyPolygon
.Insert( aPolygon
);
1895 return aPolyPolygon
;
1898 bool EscherPropertyContainer::CreatePolygonProperties(
1899 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
1902 css::awt::Rectangle
& rGeoRect
,
1903 tools::Polygon
* pPolygon
)
1905 bool bRetValue
= true;
1906 bool bLine
= ( nFlags
& ESCHER_CREATEPOLYGON_LINE
) != 0;
1908 tools::PolyPolygon aPolyPolygon
;
1911 aPolyPolygon
.Insert( *pPolygon
);
1915 bRetValue
= EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
,
1916 ( bBezier
) ? OUString("PolyPolygonBezier") : OUString("PolyPolygon"), true );
1919 aPolyPolygon
= GetPolyPolygon( aAny
);
1920 bRetValue
= aPolyPolygon
.Count() != 0;
1927 if ( ( aPolyPolygon
.Count() == 1 ) && ( aPolyPolygon
[ 0 ].GetSize() == 2 ) )
1929 const tools::Polygon
& rPoly
= aPolyPolygon
[ 0 ];
1930 rGeoRect
= css::awt::Rectangle(
1933 rPoly
[ 1 ].X() - rPoly
[ 0 ].X(),
1934 rPoly
[ 1 ].Y() - rPoly
[ 0 ].Y() );
1941 tools::Polygon aPolygon
;
1943 sal_uInt16 nPolyCount
= aPolyPolygon
.Count();
1944 sal_uInt32
nTotalPoints(0), nTotalBezPoints(0);
1945 Rectangle
aRect( aPolyPolygon
.GetBoundRect() );
1946 rGeoRect
= css::awt::Rectangle( aRect
.Left(), aRect
.Top(), aRect
.GetWidth(), aRect
.GetHeight() );
1948 for (sal_uInt16 i
= 0; i
< nPolyCount
; ++i
)
1950 sal_uInt16 k
= aPolyPolygon
[ i
].GetSize();
1952 for (sal_uInt16 j
= 0; j
< k
; ++j
)
1954 if ( aPolyPolygon
[ i
].GetFlags( j
) != PolyFlags::Control
)
1958 sal_uInt32 nVerticesBufSize
= ( nTotalPoints
<< 2 ) + 6;
1959 sal_uInt8
* pVerticesBuf
= new sal_uInt8
[ nVerticesBufSize
];
1962 sal_uInt32 nSegmentBufSize
= ( ( nTotalBezPoints
<< 2 ) + 8 );
1963 if ( nPolyCount
> 1 )
1964 nSegmentBufSize
+= ( nPolyCount
<< 1 );
1965 sal_uInt8
* pSegmentBuf
= new sal_uInt8
[ nSegmentBufSize
];
1967 sal_uInt8
* pPtr
= pVerticesBuf
;
1968 *pPtr
++ = (sal_uInt8
)( nTotalPoints
); // Little endian
1969 *pPtr
++ = (sal_uInt8
)( nTotalPoints
>> 8 );
1970 *pPtr
++ = (sal_uInt8
)( nTotalPoints
);
1971 *pPtr
++ = (sal_uInt8
)( nTotalPoints
>> 8 );
1972 *pPtr
++ = (sal_uInt8
)0xf0;
1973 *pPtr
++ = (sal_uInt8
)0xff;
1975 for (sal_uInt16 j
= 0; j
< nPolyCount
; ++j
)
1977 aPolygon
= aPolyPolygon
[ j
];
1978 sal_uInt16 nPoints
= aPolygon
.GetSize();
1979 for (sal_uInt16 i
= 0; i
< nPoints
; ++i
) // write points from polygon to buffer
1981 Point aPoint
= aPolygon
[ i
];
1982 aPoint
.X() -= rGeoRect
.X
;
1983 aPoint
.Y() -= rGeoRect
.Y
;
1985 *pPtr
++ = (sal_uInt8
)( aPoint
.X() );
1986 *pPtr
++ = (sal_uInt8
)( aPoint
.X() >> 8 );
1987 *pPtr
++ = (sal_uInt8
)( aPoint
.Y() );
1988 *pPtr
++ = (sal_uInt8
)( aPoint
.Y() >> 8 );
1993 *pPtr
++ = (sal_uInt8
)( ( nSegmentBufSize
- 6 ) >> 1 );
1994 *pPtr
++ = (sal_uInt8
)( ( nSegmentBufSize
- 6 ) >> 9 );
1995 *pPtr
++ = (sal_uInt8
)( ( nSegmentBufSize
- 6 ) >> 1 );
1996 *pPtr
++ = (sal_uInt8
)( ( nSegmentBufSize
- 6 ) >> 9 );
1997 *pPtr
++ = (sal_uInt8
)2;
1998 *pPtr
++ = (sal_uInt8
)0;
2000 for (sal_uInt16 j
= 0; j
< nPolyCount
; ++j
)
2002 *pPtr
++ = 0x0; // Polygon start
2004 aPolygon
= aPolyPolygon
[ j
];
2005 sal_uInt16 nPoints
= aPolygon
.GetSize();
2006 for (sal_uInt16 i
= 0; i
< nPoints
; ++i
) // write Polyflags to Buffer
2013 if ( ( i
+ 1 ) != nPoints
)
2016 if ( aPolygon
.GetFlags( i
+ 1 ) == PolyFlags::Control
)
2025 if ( nPolyCount
> 1 )
2027 *pPtr
++ = 1; // end of polygon
2034 AddOpt( ESCHER_Prop_geoRight
, rGeoRect
.Width
);
2035 AddOpt( ESCHER_Prop_geoBottom
, rGeoRect
.Height
);
2037 AddOpt( ESCHER_Prop_shapePath
, ESCHER_ShapeComplex
);
2038 AddOpt( ESCHER_Prop_pVertices
, true, nVerticesBufSize
- 6, pVerticesBuf
, nVerticesBufSize
);
2039 AddOpt( ESCHER_Prop_pSegmentInfo
, true, nSegmentBufSize
, pSegmentBuf
, nSegmentBufSize
);
2047 in MS,the connector including 9 types :
2048 "straightConnector1",
2049 "bentConnector2","bentConnector3","bentConnector4","bentConnector5"
2050 "curvedConnector2","curvedConnector3","curvedConnector4","curvedConnector5"
2051 in AOO,including 4 types:"standard","lines","line","curve"
2052 when save as MS file, the connector must be convert to corresponding type.
2053 "line" and "lines" <-> "straightConnector1"
2054 "standard" <-> "bentConnector2-5"
2055 "curve" <-> "curvedConnector2-5"
2057 sal_Int32
lcl_GetAdjustValueCount( const XPolygon
& rPoly
)
2060 switch ( rPoly
.GetSize() )
2073 if ( rPoly
.GetSize()>=6 )
2080 // Adjust value decide the position which connector should turn a corner
2081 sal_Int32
lcl_GetConnectorAdjustValue ( const XPolygon
& rPoly
, sal_uInt16 nIndex
)
2083 sal_uInt16 k
= rPoly
.GetSize();
2084 OSL_ASSERT ( k
>= ( 3 + nIndex
) );
2087 Point aStart
= rPoly
[0];
2088 Point aEnd
= rPoly
[k
-1];
2089 if ( aEnd
.Y() == aStart
.Y() )
2090 aEnd
.Y() = aStart
.Y() +4;
2091 if ( aEnd
.X() == aStart
.X() )
2092 aEnd
.X() = aStart
.X() +4;
2094 bool bVertical
= ( rPoly
[1].X()-aStart
.X() ) == 0 ;
2095 // vertical and horizon alternate
2096 if ( nIndex
%2 == 1 ) bVertical
= !bVertical
;
2097 aPt
= rPoly
[ nIndex
+ 1];
2099 sal_Int32 nAdjustValue
;
2101 nAdjustValue
= ( aPt
.Y()-aStart
.Y())* 21600 /(aEnd
.Y()-aStart
.Y());
2103 nAdjustValue
= ( aPt
.X()-aStart
.X() )* 21600 /(aEnd
.X()-aStart
.X());
2105 return nAdjustValue
;
2109 void lcl_Rotate(sal_Int32 nAngle
, Point center
, Point
& pt
)
2113 while (nAngle
>=36000)
2139 sal_Int32 x0
=pt
.X()-center
.X();
2140 sal_Int32 y0
=pt
.Y()-center
.Y();
2141 pt
.X()=center
.X()+ x0
*cs
-y0
*sn
;
2142 pt
.Y()=center
.Y()+ y0
*cs
+x0
*sn
;
2145 FlipV defines that the shape will be flipped vertically about the center of its bounding box.
2146 Generally, draw the connector from top to bottom, from left to right when meet the adjust value,
2147 but when (X1>X2 or Y1>Y2),the draw director must be reverse, FlipV or FlipH should be set to true.
2149 bool lcl_GetAngle(tools::Polygon
&rPoly
,sal_uInt16
& rShapeFlags
,sal_Int32
& nAngle
)
2151 Point aStart
= rPoly
[0];
2152 Point aEnd
= rPoly
[rPoly
.GetSize()-1];
2153 nAngle
= ( rPoly
[1].X() == aStart
.X() ) ? 9000: 0 ;
2154 Point
p1(aStart
.X(),aStart
.Y());
2155 Point
p2(aEnd
.X(),aEnd
.Y());
2158 Point
center((aEnd
.X()+aStart
.X())>>1,(aEnd
.Y()+aStart
.Y())>>1);
2159 lcl_Rotate(-nAngle
, center
,p1
);
2160 lcl_Rotate(-nAngle
, center
,p2
);
2162 if ( p1
.X() > p2
.X() )
2165 rShapeFlags
|= SHAPEFLAG_FLIPV
;
2167 rShapeFlags
|= SHAPEFLAG_FLIPH
;
2170 if ( p1
.Y() > p2
.Y() )
2173 rShapeFlags
|= SHAPEFLAG_FLIPH
;
2175 rShapeFlags
|= SHAPEFLAG_FLIPV
;
2178 if ( (rShapeFlags
&SHAPEFLAG_FLIPH
) && (rShapeFlags
&SHAPEFLAG_FLIPV
) )
2180 rShapeFlags
&= ~( SHAPEFLAG_FLIPH
| SHAPEFLAG_FLIPV
);
2186 // Set angle properties
2189 nAngle
&=~0xffff; // round nAngle to whole number of degrees
2194 bool EscherPropertyContainer::CreateConnectorProperties(
2195 const css::uno::Reference
< css::drawing::XShape
> & rXShape
,
2196 EscherSolverContainer
& rSolverContainer
, css::awt::Rectangle
& rGeoRect
,
2197 sal_uInt16
& rShapeType
, sal_uInt16
& rShapeFlags
)
2199 bool bRetValue
= false;
2200 rShapeType
= rShapeFlags
= 0;
2204 css::awt::Point aStartPoint
, aEndPoint
;
2205 css::uno::Reference
< css::beans::XPropertySet
> aXPropSet
;
2206 css::uno::Reference
< css::drawing::XShape
> aShapeA
, aShapeB
;
2207 css::uno::Any
aAny( rXShape
->queryInterface( cppu::UnoType
<css::beans::XPropertySet
>::get()));
2208 if ( aAny
>>= aXPropSet
)
2210 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "EdgeKind", true ) )
2212 css::drawing::ConnectorType eCt
;
2214 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "EdgeStartPoint" ) )
2216 aStartPoint
= *o3tl::doAccess
<css::awt::Point
>(aAny
);
2217 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "EdgeEndPoint" ) )
2219 aEndPoint
= *o3tl::doAccess
<css::awt::Point
>(aAny
);
2221 rShapeFlags
= SHAPEFLAG_HAVEANCHOR
| SHAPEFLAG_HAVESPT
| SHAPEFLAG_CONNECTOR
;
2222 rGeoRect
= css::awt::Rectangle( aStartPoint
.X
, aStartPoint
.Y
,
2223 ( aEndPoint
.X
- aStartPoint
.X
) + 1, ( aEndPoint
.Y
- aStartPoint
.Y
) + 1 );
2224 // set standard's FLIP in below code
2225 if ( eCt
!= css::drawing::ConnectorType_STANDARD
)
2227 if ( rGeoRect
.Height
< 0 ) // justify
2229 rShapeFlags
|= SHAPEFLAG_FLIPV
;
2230 rGeoRect
.Y
= aEndPoint
.Y
;
2231 rGeoRect
.Height
= -rGeoRect
.Height
;
2233 if ( rGeoRect
.Width
< 0 )
2235 rShapeFlags
|= SHAPEFLAG_FLIPH
;
2236 rGeoRect
.X
= aEndPoint
.X
;
2237 rGeoRect
.Width
= -rGeoRect
.Width
;
2240 sal_uInt32 nAdjustValue1
, nAdjustValue2
, nAdjustValue3
;
2241 nAdjustValue1
= nAdjustValue2
= nAdjustValue3
= 0x2a30;
2243 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "EdgeStartConnection" ) )
2245 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "EdgeEndConnection" ) )
2247 rSolverContainer
.AddConnector( rXShape
, aStartPoint
, aShapeA
, aEndPoint
, aShapeB
);
2250 case css::drawing::ConnectorType_CURVE
:
2252 rShapeType
= ESCHER_ShpInst_CurvedConnector3
;
2253 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleCurved
);
2254 AddOpt( ESCHER_Prop_adjustValue
, nAdjustValue1
);
2255 AddOpt( ESCHER_Prop_adjust2Value
, -(sal_Int32
)nAdjustValue2
);
2259 case css::drawing::ConnectorType_STANDARD
:// Connector 2->5
2261 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "PolyPolygonBezier" ) )
2263 tools::PolyPolygon aPolyPolygon
= GetPolyPolygon( aAny
);
2264 tools::Polygon aPoly
;
2265 if ( aPolyPolygon
.Count() > 0 )
2267 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleBent
);
2268 aPoly
= aPolyPolygon
[ 0 ];
2269 sal_Int32 nAdjCount
= lcl_GetAdjustValueCount( aPoly
);
2270 rShapeType
= ( sal_uInt16
)( ESCHER_ShpInst_BentConnector2
+ nAdjCount
);
2271 for ( sal_Int32 i
= 0 ; i
< nAdjCount
; ++ i
)
2272 AddOpt( (sal_uInt16
) ( ESCHER_Prop_adjustValue
+i
) , lcl_GetConnectorAdjustValue( aPoly
, i
) );
2275 if (lcl_GetAngle(aPoly
,rShapeFlags
,nAngle
))
2277 AddOpt( ESCHER_Prop_Rotation
, nAngle
);
2282 rShapeType
= ESCHER_ShpInst_BentConnector3
;
2283 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleBent
);
2288 case css::drawing::ConnectorType_LINE
:
2289 case css::drawing::ConnectorType_LINES
: // Connector 2->5
2291 rShapeType
= ESCHER_ShpInst_StraightConnector1
;
2292 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleStraight
);
2296 CreateLineProperties( aXPropSet
, false );
2306 void EscherPropertyContainer::CreateShadowProperties(
2307 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
)
2311 bool bHasShadow
= false; // shadow is possible only if at least a fillcolor, linecolor or graphic is set
2312 sal_uInt32 nLineFlags
= 0; // default : shape has no line
2313 sal_uInt32 nFillFlags
= 0x10; // shape is filled
2315 GetOpt( ESCHER_Prop_fNoLineDrawDash
, nLineFlags
);
2316 GetOpt( ESCHER_Prop_fNoFillHitTest
, nFillFlags
);
2319 bool bGraphic
= GetOpt( DFF_Prop_pib
, nDummy
) || GetOpt( DFF_Prop_pibName
, nDummy
) || GetOpt( DFF_Prop_pibFlags
, nDummy
);
2321 sal_uInt32 nShadowFlags
= 0x20000;
2322 if ( ( nLineFlags
& 8 ) || ( nFillFlags
& 0x10 ) || bGraphic
)
2324 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "Shadow", true ) )
2326 if ( aAny
>>= bHasShadow
)
2331 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "ShadowColor" ) )
2332 AddOpt( ESCHER_Prop_shadowColor
, ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
) ) );
2333 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "ShadowXDistance" ) )
2334 AddOpt( ESCHER_Prop_shadowOffsetX
, *o3tl::doAccess
<sal_Int32
>(aAny
) * 360 );
2335 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "ShadowYDistance" ) )
2336 AddOpt( ESCHER_Prop_shadowOffsetY
, *o3tl::doAccess
<sal_Int32
>(aAny
) * 360 );
2337 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, "ShadowTransparence" ) )
2338 AddOpt( ESCHER_Prop_shadowOpacity
, 0x10000 - (((sal_uInt32
)*o3tl::doAccess
<sal_uInt16
>(aAny
)) * 655 ) );
2343 AddOpt( ESCHER_Prop_fshadowObscured
, nShadowFlags
);
2346 sal_Int32
EscherPropertyContainer::GetValueForEnhancedCustomShapeParameter( const css::drawing::EnhancedCustomShapeParameter
& rParameter
,
2347 const std::vector
< sal_Int32
>& rEquationOrder
, bool bAdjustTrans
)
2349 sal_Int32 nValue
= 0;
2350 if ( rParameter
.Value
.getValueTypeClass() == uno::TypeClass_DOUBLE
)
2353 if ( rParameter
.Value
>>= fValue
)
2354 nValue
= (sal_Int32
)fValue
;
2357 rParameter
.Value
>>= nValue
;
2359 switch( rParameter
.Type
)
2361 case css::drawing::EnhancedCustomShapeParameterType::EQUATION
:
2363 size_t nIndex
= (size_t) nValue
;
2364 OSL_ASSERT(nIndex
< rEquationOrder
.size());
2365 if ( nIndex
< rEquationOrder
.size() )
2367 nValue
= (sal_uInt16
)rEquationOrder
[ nIndex
];
2368 nValue
|= (sal_uInt32
)0x80000000;
2372 case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT
:
2376 sal_uInt32 nAdjustValue
= 0;
2377 bool bGot
= GetOpt((sal_uInt16
)( DFF_Prop_adjustValue
+ nValue
), nAdjustValue
);
2378 if(bGot
) nValue
= (sal_Int32
)nAdjustValue
;
2382 case css::drawing::EnhancedCustomShapeParameterType::NORMAL
:
2385 /* not sure if it is allowed to set following values
2386 (but they are not yet used)
2387 case css::drawing::EnhancedCustomShapeParameterType::BOTTOM :
2388 case css::drawing::EnhancedCustomShapeParameterType::RIGHT :
2389 case css::drawing::EnhancedCustomShapeParameterType::TOP :
2390 case css::drawing::EnhancedCustomShapeParameterType::LEFT :
2396 bool GetValueForEnhancedCustomShapeHandleParameter( sal_Int32
& nRetValue
, const css::drawing::EnhancedCustomShapeParameter
& rParameter
)
2398 bool bSpecial
= false;
2400 if ( rParameter
.Value
.getValueTypeClass() == uno::TypeClass_DOUBLE
)
2403 if ( rParameter
.Value
>>= fValue
)
2404 nRetValue
= (sal_Int32
)fValue
;
2407 rParameter
.Value
>>= nRetValue
;
2409 switch( rParameter
.Type
)
2411 case css::drawing::EnhancedCustomShapeParameterType::EQUATION
:
2417 case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT
:
2423 case css::drawing::EnhancedCustomShapeParameterType::TOP
:
2424 case css::drawing::EnhancedCustomShapeParameterType::LEFT
:
2430 case css::drawing::EnhancedCustomShapeParameterType::RIGHT
:
2431 case css::drawing::EnhancedCustomShapeParameterType::BOTTOM
:
2437 case css::drawing::EnhancedCustomShapeParameterType::NORMAL
:
2446 void ConvertEnhancedCustomShapeEquation( SdrObjCustomShape
* pCustoShape
,
2447 std::vector
< EnhancedCustomShapeEquation
>& rEquations
, std::vector
< sal_Int32
>& rEquationOrder
)
2451 uno::Sequence
< OUString
> sEquationSource
;
2452 const SdrCustomShapeGeometryItem
& rGeometryItem
= static_cast<const SdrCustomShapeGeometryItem
&>(
2453 pCustoShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
));
2454 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( "Equations" );
2456 *pAny
>>= sEquationSource
;
2457 sal_Int32 nEquationSourceCount
= sEquationSource
.getLength();
2458 if ( nEquationSourceCount
&& (nEquationSourceCount
<= 128) )
2461 for ( i
= 0; i
< nEquationSourceCount
; i
++ )
2463 EnhancedCustomShape2d
aCustoShape2d( pCustoShape
);
2466 std::shared_ptr
< EnhancedCustomShape::ExpressionNode
> aExpressNode(
2467 EnhancedCustomShape::FunctionParser::parseFunction( sEquationSource
[ i
], aCustoShape2d
) );
2468 css::drawing::EnhancedCustomShapeParameter
aPara( aExpressNode
->fillNode( rEquations
, nullptr, 0 ) );
2469 if ( aPara
.Type
!= css::drawing::EnhancedCustomShapeParameterType::EQUATION
)
2471 EnhancedCustomShapeEquation aEquation
;
2472 aEquation
.nOperation
= 0;
2473 EnhancedCustomShape::FillEquationParameter( aPara
, 0, aEquation
);
2474 rEquations
.push_back( aEquation
);
2477 catch ( const EnhancedCustomShape::ParseError
& )
2479 EnhancedCustomShapeEquation aEquation
; // ups, we should not be here,
2480 aEquation
.nOperation
= 0; // creating a default equation with value 1
2481 aEquation
.nPara
[ 0 ] = 1; // hoping that this will not break anything
2482 rEquations
.push_back( aEquation
);
2486 EnhancedCustomShapeEquation aEquation
; // #i112309# EnhancedCustomShape::Parse error
2487 aEquation
.nOperation
= 0; // not catched on linux platform
2488 aEquation
.nPara
[ 0 ] = 1;
2489 rEquations
.push_back( aEquation
);
2491 rEquationOrder
.push_back( rEquations
.size() - 1 );
2493 // now updating our old equation indices, they are marked with a bit in the hiword of nOperation
2494 std::vector
< EnhancedCustomShapeEquation
>::iterator
aIter( rEquations
.begin() );
2495 std::vector
< EnhancedCustomShapeEquation
>::iterator
aEnd ( rEquations
.end() );
2496 while( aIter
!= aEnd
)
2498 sal_uInt32 nMask
= 0x20000000;
2499 for( i
= 0; i
< 3; i
++ )
2501 if ( aIter
->nOperation
& nMask
)
2503 aIter
->nOperation
^= nMask
;
2504 const size_t nIndex(aIter
->nPara
[ i
] & 0x3ff);
2506 // #i124661# check index access, there are cases where this is out of bound leading
2507 // to errors up to crashes when executed
2508 if(nIndex
< rEquationOrder
.size())
2510 aIter
->nPara
[ i
] = rEquationOrder
[ nIndex
] | 0x400;
2514 OSL_ENSURE(false, "Attempted out of bound access to rEquationOrder of CustomShape (!)");
2525 bool EscherPropertyContainer::IsDefaultObject( SdrObjCustomShape
* pCustoShape
, const MSO_SPT eShapeType
)
2527 bool bIsDefaultObject
= false;
2530 // if the custom shape is not default shape of ppt, return sal_Fasle;
2531 case mso_sptTearDrop
:
2532 return bIsDefaultObject
;
2540 if ( pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::Equations
)
2541 && pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::Viewbox
)
2542 && pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::Path
)
2543 && pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::Gluepoints
)
2544 && pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::Segments
)
2545 && pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchX
)
2546 && pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchY
)
2547 && pCustoShape
->IsDefaultGeometry( SdrObjCustomShape::DefaultType::TextFrames
) )
2548 bIsDefaultObject
= true;
2551 return bIsDefaultObject
;
2554 void EscherPropertyContainer::LookForPolarHandles( const MSO_SPT eShapeType
, sal_Int32
& nAdjustmentsWhichNeedsToBeConverted
)
2556 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent( eShapeType
);
2557 if ( pDefCustomShape
&& pDefCustomShape
->nHandles
&& pDefCustomShape
->pHandles
)
2559 sal_Int32 k
, nkCount
= pDefCustomShape
->nHandles
;
2560 const SvxMSDffHandle
* pData
= pDefCustomShape
->pHandles
;
2561 for ( k
= 0; k
< nkCount
; k
++, pData
++ )
2563 if ( pData
->nFlags
& SvxMSDffHandleFlags::POLAR
)
2565 if ( ( pData
->nPositionY
>= 0x256 ) || ( pData
->nPositionY
<= 0x107 ) )
2566 nAdjustmentsWhichNeedsToBeConverted
|= ( 1 << k
);
2572 bool EscherPropertyContainer::GetAdjustmentValue( const css::drawing::EnhancedCustomShapeAdjustmentValue
& rkProp
, sal_Int32 nIndex
, sal_Int32 nAdjustmentsWhichNeedsToBeConverted
, sal_Int32
& nValue
)
2574 if ( rkProp
.State
!= beans::PropertyState_DIRECT_VALUE
)
2577 bool bUseFixedFloat
= ( nAdjustmentsWhichNeedsToBeConverted
& ( 1 << nIndex
) ) != 0;
2578 if ( rkProp
.Value
.getValueTypeClass() == uno::TypeClass_DOUBLE
)
2581 rkProp
.Value
>>= fValue
;
2582 if ( bUseFixedFloat
)
2584 nValue
= (sal_Int32
)fValue
;
2588 rkProp
.Value
>>= nValue
;
2589 if ( bUseFixedFloat
)
2596 void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeType
, const uno::Reference
< drawing::XShape
> & rXShape
)
2598 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
2599 if ( aXPropSet
.is() )
2601 SdrObjCustomShape
* pCustoShape
= static_cast<SdrObjCustomShape
*>(GetSdrObjectFromXShape( rXShape
));
2602 if ( !pCustoShape
) return;
2603 const OUString
sCustomShapeGeometry( "CustomShapeGeometry" );
2604 uno::Any aGeoPropSet
= aXPropSet
->getPropertyValue( sCustomShapeGeometry
);
2605 uno::Sequence
< beans::PropertyValue
> aGeoPropSeq
;
2606 if ( aGeoPropSet
>>= aGeoPropSeq
)
2608 const OUString
sViewBox ( "ViewBox" );
2609 const OUString
sTextRotateAngle ( "TextRotateAngle" );
2610 const OUString
sExtrusion ( "Extrusion" );
2611 const OUString
sEquations ( "Equations" );
2612 const OUString
sPath ( "Path" );
2613 const OUString
sTextPath ( "TextPath" );
2614 const OUString
sHandles ( "Handles" );
2615 const OUString
sAdjustmentValues ( "AdjustmentValues" );
2617 bool bAdjustmentValuesProp
= false;
2618 uno::Any aAdjustmentValuesProp
;
2619 bool bPathCoordinatesProp
= false;
2620 uno::Any aPathCoordinatesProp
;
2622 sal_Int32 nAdjustmentsWhichNeedsToBeConverted
= 0;
2623 uno::Sequence
< beans::PropertyValues
> aHandlesPropSeq
;
2624 bool bPredefinedHandlesUsed
= true;
2625 bool bIsDefaultObject
= IsDefaultObject( pCustoShape
, eShapeType
);
2627 // convert property "Equations" into std::vector< EnhancedCustomShapeEquationEquation >
2628 std::vector
< EnhancedCustomShapeEquation
> aEquations
;
2629 std::vector
< sal_Int32
> aEquationOrder
;
2630 ConvertEnhancedCustomShapeEquation( pCustoShape
, aEquations
, aEquationOrder
);
2632 sal_Int32 i
, nCount
= aGeoPropSeq
.getLength();
2633 for ( i
= 0; i
< nCount
; i
++ )
2635 const beans::PropertyValue
& rProp
= aGeoPropSeq
[ i
];
2636 if ( rProp
.Name
.equals( sViewBox
) )
2638 if ( !bIsDefaultObject
)
2640 awt::Rectangle aViewBox
;
2641 if ( rProp
.Value
>>= aViewBox
)
2643 AddOpt( DFF_Prop_geoLeft
, aViewBox
.X
);
2644 AddOpt( DFF_Prop_geoTop
, aViewBox
.Y
);
2645 AddOpt( DFF_Prop_geoRight
, aViewBox
.X
+ aViewBox
.Width
);
2646 AddOpt( DFF_Prop_geoBottom
,aViewBox
.Y
+ aViewBox
.Height
);
2650 else if ( rProp
.Name
.equals( sTextRotateAngle
) )
2653 if ( rProp
.Value
>>= f
)
2655 double fTextRotateAngle
= fmod( f
, 360.0 );
2656 if ( fTextRotateAngle
< 0 )
2657 fTextRotateAngle
= 360 + fTextRotateAngle
;
2658 if ( ( fTextRotateAngle
< 271.0 ) && ( fTextRotateAngle
> 269.0 ) )
2659 AddOpt( DFF_Prop_cdirFont
, mso_cdir90
);
2660 else if ( ( fTextRotateAngle
< 181.0 ) && ( fTextRotateAngle
> 179.0 ) )
2661 AddOpt( DFF_Prop_cdirFont
, mso_cdir180
);
2662 else if ( ( fTextRotateAngle
< 91.0 ) && ( fTextRotateAngle
> 79.0 ) )
2663 AddOpt( DFF_Prop_cdirFont
, mso_cdir270
);
2666 else if ( rProp
.Name
.equals( sExtrusion
) )
2668 uno::Sequence
< beans::PropertyValue
> aExtrusionPropSeq
;
2669 if ( rProp
.Value
>>= aExtrusionPropSeq
)
2671 sal_uInt32 nLightFaceFlagsOrg
, nLightFaceFlags
;
2672 sal_uInt32 nFillHarshFlagsOrg
, nFillHarshFlags
;
2673 nLightFaceFlagsOrg
= nLightFaceFlags
= 0x000001;
2674 nFillHarshFlagsOrg
= nFillHarshFlags
= 0x00001e;
2675 if ( GetOpt( DFF_Prop_fc3DLightFace
, nLightFaceFlags
) )
2676 nLightFaceFlagsOrg
= nLightFaceFlags
;
2677 if ( GetOpt( DFF_Prop_fc3DFillHarsh
, nFillHarshFlags
) )
2678 nFillHarshFlagsOrg
= nFillHarshFlags
;
2680 sal_Int32 r
, nrCount
= aExtrusionPropSeq
.getLength();
2681 for ( r
= 0; r
< nrCount
; r
++ )
2683 const beans::PropertyValue
& rrProp
= aExtrusionPropSeq
[ r
];
2684 const OUString
sExtrusionBrightness ( "Brightness" );
2685 const OUString
sExtrusionDepth ( "Depth" );
2686 const OUString
sExtrusionDiffusion ( "Diffusion" );
2687 const OUString
sExtrusionNumberOfLineSegments ( "NumberOfLineSegments" );
2688 const OUString
sExtrusionLightFace ( "LightFace" );
2689 const OUString
sExtrusionFirstLightHarsh ( "FirstLightHarsh" );
2690 const OUString
sExtrusionSecondLightHarsh ( "SecondLightHarsh" );
2691 const OUString
sExtrusionFirstLightLevel ( "FirstLightLevel" );
2692 const OUString
sExtrusionSecondLightLevel ( "SecondLightLevel" );
2693 const OUString
sExtrusionFirstLightDirection ( "FirstLightDirection" );
2694 const OUString
sExtrusionSecondLightDirection ( "SecondLightDirection" );
2695 const OUString
sExtrusionMetal ( "Metal" );
2696 const OUString
sExtrusionShadeMode ( "ShadeMode" );
2697 const OUString
sExtrusionRotateAngle ( "RotateAngle" );
2698 const OUString
sExtrusionRotationCenter ( "RotationCenter" );
2699 const OUString
sExtrusionShininess ( "Shininess" );
2700 const OUString
sExtrusionSkew ( "Skew" );
2701 const OUString
sExtrusionSpecularity ( "Specularity" );
2702 const OUString
sExtrusionProjectionMode ( "ProjectionMode" );
2703 const OUString
sExtrusionViewPoint ( "ViewPoint" );
2704 const OUString
sExtrusionOrigin ( "Origin" );
2705 const OUString
sExtrusionColor ( "Color" );
2707 if ( rrProp
.Name
.equals( sExtrusion
) )
2710 if ( rrProp
.Value
>>= bExtrusionOn
)
2712 nLightFaceFlags
|= 0x80000;
2714 nLightFaceFlags
|= 8;
2716 nLightFaceFlags
&=~8;
2719 else if ( rrProp
.Name
.equals( sExtrusionBrightness
) )
2721 double fExtrusionBrightness
= 0;
2722 if ( rrProp
.Value
>>= fExtrusionBrightness
)
2723 AddOpt( DFF_Prop_c3DAmbientIntensity
, (sal_Int32
)( fExtrusionBrightness
* 655.36 ) );
2725 else if ( rrProp
.Name
.equals( sExtrusionDepth
) )
2728 double fFraction
= 0;
2729 css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair
;
2730 if ( ( rrProp
.Value
>>= aDepthParaPair
) && ( aDepthParaPair
.First
.Value
>>= fDepth
) && ( aDepthParaPair
.Second
.Value
>>= fFraction
) )
2732 double fForeDepth
= fDepth
* fFraction
;
2733 double fBackDepth
= fDepth
- fForeDepth
;
2735 fBackDepth
*= 360.0;
2736 AddOpt( DFF_Prop_c3DExtrudeBackward
, (sal_Int32
)fBackDepth
);
2738 if ( fForeDepth
!= 0.0 )
2740 fForeDepth
*= 360.0;
2741 AddOpt( DFF_Prop_c3DExtrudeForward
, (sal_Int32
)fForeDepth
);
2745 else if ( rrProp
.Name
.equals( sExtrusionDiffusion
) )
2747 double fExtrusionDiffusion
= 0;
2748 if ( rrProp
.Value
>>= fExtrusionDiffusion
)
2749 AddOpt( DFF_Prop_c3DDiffuseAmt
, (sal_Int32
)( fExtrusionDiffusion
* 655.36 ) );
2751 else if ( rrProp
.Name
.equals( sExtrusionNumberOfLineSegments
) )
2753 sal_Int32 nExtrusionNumberOfLineSegments
= 0;
2754 if ( rrProp
.Value
>>= nExtrusionNumberOfLineSegments
)
2755 AddOpt( DFF_Prop_c3DTolerance
, nExtrusionNumberOfLineSegments
);
2757 else if ( rrProp
.Name
.equals( sExtrusionLightFace
) )
2759 bool bExtrusionLightFace
;
2760 if ( rrProp
.Value
>>= bExtrusionLightFace
)
2762 nLightFaceFlags
|= 0x10000;
2763 if ( bExtrusionLightFace
)
2764 nLightFaceFlags
|= 1;
2766 nLightFaceFlags
&=~1;
2769 else if ( rrProp
.Name
.equals( sExtrusionFirstLightHarsh
) )
2771 bool bExtrusionFirstLightHarsh
;
2772 if ( rrProp
.Value
>>= bExtrusionFirstLightHarsh
)
2774 nFillHarshFlags
|= 0x20000;
2775 if ( bExtrusionFirstLightHarsh
)
2776 nFillHarshFlags
|= 2;
2778 nFillHarshFlags
&=~2;
2781 else if ( rrProp
.Name
.equals( sExtrusionSecondLightHarsh
) )
2783 bool bExtrusionSecondLightHarsh
;
2784 if ( rrProp
.Value
>>= bExtrusionSecondLightHarsh
)
2786 nFillHarshFlags
|= 0x10000;
2787 if ( bExtrusionSecondLightHarsh
)
2788 nFillHarshFlags
|= 1;
2790 nFillHarshFlags
&=~1;
2793 else if ( rrProp
.Name
.equals( sExtrusionFirstLightLevel
) )
2795 double fExtrusionFirstLightLevel
= 0;
2796 if ( rrProp
.Value
>>= fExtrusionFirstLightLevel
)
2797 AddOpt( DFF_Prop_c3DKeyIntensity
, (sal_Int32
)( fExtrusionFirstLightLevel
* 655.36 ) );
2799 else if ( rrProp
.Name
.equals( sExtrusionSecondLightLevel
) )
2801 double fExtrusionSecondLightLevel
= 0;
2802 if ( rrProp
.Value
>>= fExtrusionSecondLightLevel
)
2803 AddOpt( DFF_Prop_c3DFillIntensity
, (sal_Int32
)( fExtrusionSecondLightLevel
* 655.36 ) );
2805 else if ( rrProp
.Name
.equals( sExtrusionFirstLightDirection
) )
2807 drawing::Direction3D aExtrusionFirstLightDirection
;
2808 if ( rrProp
.Value
>>= aExtrusionFirstLightDirection
)
2810 AddOpt( DFF_Prop_c3DKeyX
, (sal_Int32
)aExtrusionFirstLightDirection
.DirectionX
);
2811 AddOpt( DFF_Prop_c3DKeyY
, (sal_Int32
)aExtrusionFirstLightDirection
.DirectionY
);
2812 AddOpt( DFF_Prop_c3DKeyZ
, (sal_Int32
)aExtrusionFirstLightDirection
.DirectionZ
);
2815 else if ( rrProp
.Name
.equals( sExtrusionSecondLightDirection
) )
2817 drawing::Direction3D aExtrusionSecondLightPosition
;
2818 if ( rrProp
.Value
>>= aExtrusionSecondLightPosition
)
2820 AddOpt( DFF_Prop_c3DFillX
, (sal_Int32
)aExtrusionSecondLightPosition
.DirectionX
);
2821 AddOpt( DFF_Prop_c3DFillY
, (sal_Int32
)aExtrusionSecondLightPosition
.DirectionY
);
2822 AddOpt( DFF_Prop_c3DFillZ
, (sal_Int32
)aExtrusionSecondLightPosition
.DirectionZ
);
2825 else if ( rrProp
.Name
.equals( sExtrusionMetal
) )
2827 bool bExtrusionMetal
;
2828 if ( rrProp
.Value
>>= bExtrusionMetal
)
2830 nLightFaceFlags
|= 0x40000;
2831 if ( bExtrusionMetal
)
2832 nLightFaceFlags
|= 4;
2834 nLightFaceFlags
&=~4;
2837 else if ( rrProp
.Name
.equals( sExtrusionShadeMode
) )
2839 drawing::ShadeMode eExtrusionShadeMode
;
2840 if ( rrProp
.Value
>>= eExtrusionShadeMode
)
2842 sal_uInt32 nRenderMode
;
2843 switch( eExtrusionShadeMode
)
2846 case drawing::ShadeMode_FLAT
:
2847 case drawing::ShadeMode_PHONG
:
2848 case drawing::ShadeMode_SMOOTH
:
2849 nRenderMode
= mso_FullRender
;
2851 case drawing::ShadeMode_DRAFT
:
2853 nRenderMode
= mso_Wireframe
;
2857 AddOpt( DFF_Prop_c3DRenderMode
, nRenderMode
);
2860 else if ( rrProp
.Name
.equals( sExtrusionRotateAngle
) )
2862 double fExtrusionAngleX
= 0;
2863 double fExtrusionAngleY
= 0;
2864 css::drawing::EnhancedCustomShapeParameterPair aRotateAnglePair
;
2865 if ( ( rrProp
.Value
>>= aRotateAnglePair
) && ( aRotateAnglePair
.First
.Value
>>= fExtrusionAngleX
) && ( aRotateAnglePair
.Second
.Value
>>= fExtrusionAngleY
) )
2867 fExtrusionAngleX
*= 65536;
2868 fExtrusionAngleY
*= 65536;
2869 AddOpt( DFF_Prop_c3DXRotationAngle
, (sal_Int32
)fExtrusionAngleX
);
2870 AddOpt( DFF_Prop_c3DYRotationAngle
, (sal_Int32
)fExtrusionAngleY
);
2873 else if ( rrProp
.Name
.equals( sExtrusionRotationCenter
) )
2875 drawing::Direction3D aExtrusionRotationCenter
;
2876 if ( rrProp
.Value
>>= aExtrusionRotationCenter
)
2878 AddOpt( DFF_Prop_c3DRotationCenterX
, (sal_Int32
)( aExtrusionRotationCenter
.DirectionX
* 360.0 ) );
2879 AddOpt( DFF_Prop_c3DRotationCenterY
, (sal_Int32
)( aExtrusionRotationCenter
.DirectionY
* 360.0 ) );
2880 AddOpt( DFF_Prop_c3DRotationCenterZ
, (sal_Int32
)( aExtrusionRotationCenter
.DirectionZ
* 360.0 ) );
2881 nFillHarshFlags
&=~8; // don't use AutoRotationCenter;
2884 else if ( rrProp
.Name
.equals( sExtrusionShininess
) )
2886 double fExtrusionShininess
= 0;
2887 if ( rrProp
.Value
>>= fExtrusionShininess
)
2888 AddOpt( DFF_Prop_c3DShininess
, (sal_Int32
)( fExtrusionShininess
* 655.36 ) );
2890 else if ( rrProp
.Name
.equals( sExtrusionSkew
) )
2892 double fSkewAmount
= 0;
2893 double fSkewAngle
= 0;
2894 css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair
;
2895 if ( ( rrProp
.Value
>>= aSkewParaPair
) && ( aSkewParaPair
.First
.Value
>>= fSkewAmount
) && ( aSkewParaPair
.Second
.Value
>>= fSkewAngle
) )
2897 AddOpt( DFF_Prop_c3DSkewAmount
, (sal_Int32
)fSkewAmount
);
2898 AddOpt( DFF_Prop_c3DSkewAngle
, (sal_Int32
)( fSkewAngle
* 65536 ) );
2901 else if ( rrProp
.Name
.equals( sExtrusionSpecularity
) )
2903 double fExtrusionSpecularity
= 0;
2904 if ( rrProp
.Value
>>= fExtrusionSpecularity
)
2905 AddOpt( DFF_Prop_c3DSpecularAmt
, (sal_Int32
)( fExtrusionSpecularity
* 1333 ) );
2907 else if ( rrProp
.Name
.equals( sExtrusionProjectionMode
) )
2909 drawing::ProjectionMode eExtrusionProjectionMode
;
2910 if ( rrProp
.Value
>>= eExtrusionProjectionMode
)
2912 nFillHarshFlags
|= 0x40000;
2913 if ( eExtrusionProjectionMode
== drawing::ProjectionMode_PARALLEL
)
2914 nFillHarshFlags
|= 4;
2916 nFillHarshFlags
&=~4;
2919 else if ( rrProp
.Name
.equals( sExtrusionViewPoint
) )
2921 drawing::Position3D aExtrusionViewPoint
;
2922 if ( rrProp
.Value
>>= aExtrusionViewPoint
)
2924 aExtrusionViewPoint
.PositionX
*= 360.0;
2925 aExtrusionViewPoint
.PositionY
*= 360.0;
2926 aExtrusionViewPoint
.PositionZ
*= 360.0;
2927 AddOpt( DFF_Prop_c3DXViewpoint
, (sal_Int32
)aExtrusionViewPoint
.PositionX
);
2928 AddOpt( DFF_Prop_c3DYViewpoint
, (sal_Int32
)aExtrusionViewPoint
.PositionY
);
2929 AddOpt( DFF_Prop_c3DZViewpoint
, (sal_Int32
)aExtrusionViewPoint
.PositionZ
);
2932 else if ( rrProp
.Name
.equals( sExtrusionOrigin
) )
2934 double fExtrusionOriginX
= 0;
2935 double fExtrusionOriginY
= 0;
2936 css::drawing::EnhancedCustomShapeParameterPair aOriginPair
;
2937 if ( ( rrProp
.Value
>>= aOriginPair
) && ( aOriginPair
.First
.Value
>>= fExtrusionOriginX
) && ( aOriginPair
.Second
.Value
>>= fExtrusionOriginY
) )
2939 AddOpt( DFF_Prop_c3DOriginX
, (sal_Int32
)( fExtrusionOriginX
* 65536 ) );
2940 AddOpt( DFF_Prop_c3DOriginY
, (sal_Int32
)( fExtrusionOriginY
* 65536 ) );
2943 else if ( rrProp
.Name
.equals( sExtrusionColor
) )
2945 bool bExtrusionColor
;
2946 if ( rrProp
.Value
>>= bExtrusionColor
)
2948 nLightFaceFlags
|= 0x20000;
2949 if ( bExtrusionColor
)
2951 nLightFaceFlags
|= 2;
2952 uno::Any aFillColor2
;
2953 if ( EscherPropertyValueHelper::GetPropertyValue( aFillColor2
, aXPropSet
, "FillColor2", true ) )
2955 sal_uInt32 nFillColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aFillColor2
) );
2956 AddOpt( DFF_Prop_c3DExtrusionColor
, nFillColor
);
2960 nLightFaceFlags
&=~2;
2964 if ( nLightFaceFlags
!= nLightFaceFlagsOrg
)
2965 AddOpt( DFF_Prop_fc3DLightFace
, nLightFaceFlags
);
2966 if ( nFillHarshFlags
!= nFillHarshFlagsOrg
)
2967 AddOpt( DFF_Prop_fc3DFillHarsh
, nFillHarshFlags
);
2970 else if ( rProp
.Name
.equals( sEquations
) )
2972 if ( !bIsDefaultObject
)
2974 sal_uInt16 nElements
= (sal_uInt16
)aEquations
.size();
2977 sal_uInt16 nElementSize
= 8;
2978 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
2979 SvMemoryStream
aOut( nStreamSize
);
2980 aOut
.WriteUInt16( nElements
)
2981 .WriteUInt16( nElements
)
2982 .WriteUInt16( nElementSize
);
2984 std::vector
< EnhancedCustomShapeEquation
>::const_iterator
aIter( aEquations
.begin() );
2985 std::vector
< EnhancedCustomShapeEquation
>::const_iterator
aEnd ( aEquations
.end() );
2986 while( aIter
!= aEnd
)
2988 aOut
.WriteUInt16( aIter
->nOperation
)
2989 .WriteInt16( aIter
->nPara
[ 0 ] )
2990 .WriteInt16( aIter
->nPara
[ 1 ] )
2991 .WriteInt16( aIter
->nPara
[ 2 ] );
2994 sal_uInt8
* pBuf
= new sal_uInt8
[ nStreamSize
];
2995 memcpy( pBuf
, aOut
.GetData(), nStreamSize
);
2996 AddOpt( DFF_Prop_pFormulas
, true, nStreamSize
- 6, pBuf
, nStreamSize
);
3000 sal_uInt8
* pBuf
= new sal_uInt8
[ 1 ];
3001 AddOpt( DFF_Prop_pFormulas
, true, 0, pBuf
, 0 );
3005 else if ( rProp
.Name
.equals( sPath
) )
3007 uno::Sequence
< beans::PropertyValue
> aPathPropSeq
;
3008 if ( rProp
.Value
>>= aPathPropSeq
)
3010 sal_uInt32 nPathFlags
, nPathFlagsOrg
;
3011 nPathFlagsOrg
= nPathFlags
= 0x39;
3012 if ( GetOpt( DFF_Prop_fFillOK
, nPathFlags
) )
3013 nPathFlagsOrg
= nPathFlags
;
3015 sal_Int32 r
, nrCount
= aPathPropSeq
.getLength();
3016 for ( r
= 0; r
< nrCount
; r
++ )
3018 const beans::PropertyValue
& rrProp
= aPathPropSeq
[ r
];
3019 const OUString
sPathExtrusionAllowed ( "ExtrusionAllowed" );
3020 const OUString
sPathConcentricGradientFillAllowed ( "ConcentricGradientFillAllowed" );
3021 const OUString
sPathTextPathAllowed ( "TextPathAllowed" );
3022 const OUString
sPathCoordinates ( "Coordinates" );
3023 const OUString
sPathGluePoints ( "GluePoints" );
3024 const OUString
sPathGluePointType ( "GluePointType" );
3025 const OUString
sPathSegments ( "Segments" );
3026 const OUString
sPathStretchX ( "StretchX" );
3027 const OUString
sPathStretchY ( "StretchY" );
3028 const OUString
sPathTextFrames ( "TextFrames" );
3030 if ( rrProp
.Name
.equals( sPathExtrusionAllowed
) )
3032 bool bExtrusionAllowed
;
3033 if ( rrProp
.Value
>>= bExtrusionAllowed
)
3035 nPathFlags
|= 0x100000;
3036 if ( bExtrusionAllowed
)
3042 else if ( rrProp
.Name
.equals( sPathConcentricGradientFillAllowed
) )
3044 bool bConcentricGradientFillAllowed
;
3045 if ( rrProp
.Value
>>= bConcentricGradientFillAllowed
)
3047 nPathFlags
|= 0x20000;
3048 if ( bConcentricGradientFillAllowed
)
3054 else if ( rrProp
.Name
.equals( sPathTextPathAllowed
) )
3056 bool bTextPathAllowed
;
3057 if ( rrProp
.Value
>>= bTextPathAllowed
)
3059 nPathFlags
|= 0x40000;
3060 if ( bTextPathAllowed
)
3066 else if ( rrProp
.Name
.equals( sPathCoordinates
) )
3068 if ( !bIsDefaultObject
)
3070 aPathCoordinatesProp
= rrProp
.Value
;
3071 bPathCoordinatesProp
= true;
3074 else if ( rrProp
.Name
.equals( sPathGluePoints
) )
3076 if ( !bIsDefaultObject
)
3078 css::uno::Sequence
< css::drawing::EnhancedCustomShapeParameterPair
> aGluePoints
;
3079 if ( rrProp
.Value
>>= aGluePoints
)
3081 // creating the vertices
3082 sal_uInt16 nElements
= (sal_uInt16
)aGluePoints
.getLength();
3085 sal_uInt16 j
, nElementSize
= 8;
3086 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3087 SvMemoryStream
aOut( nStreamSize
);
3088 aOut
.WriteUInt16( nElements
)
3089 .WriteUInt16( nElements
)
3090 .WriteUInt16( nElementSize
);
3091 for( j
= 0; j
< nElements
; j
++ )
3093 sal_Int32 X
= GetValueForEnhancedCustomShapeParameter( aGluePoints
[ j
].First
, aEquationOrder
);
3094 sal_Int32 Y
= GetValueForEnhancedCustomShapeParameter( aGluePoints
[ j
].Second
, aEquationOrder
);
3095 aOut
.WriteInt32( X
)
3098 sal_uInt8
* pBuf
= new sal_uInt8
[ nStreamSize
];
3099 memcpy( pBuf
, aOut
.GetData(), nStreamSize
);
3100 AddOpt( DFF_Prop_connectorPoints
, true, nStreamSize
- 6, pBuf
, nStreamSize
); // -6
3104 sal_uInt8
* pBuf
= new sal_uInt8
[ 1 ];
3105 AddOpt( DFF_Prop_connectorPoints
, true, 0, pBuf
, 0 );
3110 else if ( rrProp
.Name
.equals( sPathGluePointType
) )
3112 sal_Int16 nGluePointType
= sal_Int16();
3113 if ( rrProp
.Value
>>= nGluePointType
)
3114 AddOpt( DFF_Prop_connectorType
, (sal_uInt16
)nGluePointType
);
3116 else if ( rrProp
.Name
.equals( sPathSegments
) )
3118 if ( !bIsDefaultObject
)
3120 css::uno::Sequence
< css::drawing::EnhancedCustomShapeSegment
> aSegments
;
3121 if ( rrProp
.Value
>>= aSegments
)
3124 if ( (sal_uInt16
)aSegments
.getLength() )
3126 sal_uInt16 j
, nElements
= (sal_uInt16
)aSegments
.getLength();
3127 sal_uInt16 nElementSize
= 2;
3128 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3129 SvMemoryStream
aOut( nStreamSize
);
3130 aOut
.WriteUInt16( nElements
)
3131 .WriteUInt16( nElements
)
3132 .WriteUInt16( nElementSize
);
3133 for ( j
= 0; j
< nElements
; j
++ )
3135 // The segment type is stored in the upper 3 bits
3136 // and segment count is stored in the lower 13
3139 // If the segment type is msopathEscape, the lower 13 bits
3140 // are divided in a 5 bit escape code and 8 bit
3141 // vertex count (not segment count!)
3142 sal_uInt16 nVal
= (sal_uInt16
)aSegments
[ j
].Count
;
3143 switch( aSegments
[ j
].Command
)
3145 case css::drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN
:
3146 case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO
:
3148 case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO
:
3149 nVal
= (msopathMoveTo
<< 13);
3151 case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO
:
3153 nVal
|= (msopathCurveTo
<< 13);
3156 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
:
3159 nVal
|= (msopathClose
<< 13);
3162 case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH
:
3164 nVal
= (msopathEnd
<< 13);
3167 case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL
:
3169 nVal
= (msopathEscape
<< 13) | (5 << 8);
3172 case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE
:
3174 nVal
= (msopathEscape
<< 13) | (11 << 8);
3177 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO
:
3180 nVal
|= (msopathEscape
<< 13) | (1 << 8);
3183 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE
:
3186 nVal
|= (msopathEscape
<< 13) | (2 << 8);
3189 case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO
:
3192 nVal
|= (msopathEscape
<< 13) | (3 << 8);
3195 case css::drawing::EnhancedCustomShapeSegmentCommand::ARC
:
3198 nVal
|= (msopathEscape
<< 13) | (4 << 8);
3201 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO
:
3204 nVal
|= (msopathEscape
<< 13) | (5 << 8);
3207 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC
:
3210 nVal
|= (msopathEscape
<< 13) | (6 << 8);
3213 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX
:
3215 nVal
|= (msopathEscape
<< 13) | (7 << 8);
3218 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY
:
3220 nVal
|= (msopathEscape
<< 13) | (8 << 8);
3224 aOut
.WriteUInt16( nVal
);
3226 sal_uInt8
* pBuf
= new sal_uInt8
[ nStreamSize
];
3227 memcpy( pBuf
, aOut
.GetData(), nStreamSize
);
3228 AddOpt( DFF_Prop_pSegmentInfo
, false, nStreamSize
- 6, pBuf
, nStreamSize
);
3232 sal_uInt8
* pBuf
= new sal_uInt8
[ 1 ];
3233 AddOpt( DFF_Prop_pSegmentInfo
, true, 0, pBuf
, 0 );
3238 else if ( rrProp
.Name
.equals( sPathStretchX
) )
3240 if ( !bIsDefaultObject
)
3242 sal_Int32 nStretchX
= 0;
3243 if ( rrProp
.Value
>>= nStretchX
)
3244 AddOpt( DFF_Prop_stretchPointX
, nStretchX
);
3247 else if ( rrProp
.Name
.equals( sPathStretchY
) )
3249 if ( !bIsDefaultObject
)
3251 sal_Int32 nStretchY
= 0;
3252 if ( rrProp
.Value
>>= nStretchY
)
3253 AddOpt( DFF_Prop_stretchPointY
, nStretchY
);
3256 else if ( rrProp
.Name
.equals( sPathTextFrames
) )
3258 if ( !bIsDefaultObject
)
3260 css::uno::Sequence
< css::drawing::EnhancedCustomShapeTextFrame
> aPathTextFrames
;
3261 if ( rrProp
.Value
>>= aPathTextFrames
)
3263 if ( (sal_uInt16
)aPathTextFrames
.getLength() )
3265 sal_uInt16 j
, nElements
= (sal_uInt16
)aPathTextFrames
.getLength();
3266 sal_uInt16 nElementSize
= 16;
3267 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3268 SvMemoryStream
aOut( nStreamSize
);
3269 aOut
.WriteUInt16( nElements
)
3270 .WriteUInt16( nElements
)
3271 .WriteUInt16( nElementSize
);
3272 for ( j
= 0; j
< nElements
; j
++ )
3274 sal_Int32 nLeft
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].TopLeft
.First
, aEquationOrder
);
3275 sal_Int32 nTop
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].TopLeft
.Second
, aEquationOrder
);
3276 sal_Int32 nRight
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].BottomRight
.First
, aEquationOrder
);
3277 sal_Int32 nBottom
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].BottomRight
.Second
, aEquationOrder
);
3279 aOut
.WriteInt32( nLeft
)
3281 .WriteInt32( nRight
)
3282 .WriteInt32( nBottom
);
3284 sal_uInt8
* pBuf
= new sal_uInt8
[ nStreamSize
];
3285 memcpy( pBuf
, aOut
.GetData(), nStreamSize
);
3286 AddOpt( DFF_Prop_textRectangles
, true, nStreamSize
- 6, pBuf
, nStreamSize
);
3290 sal_uInt8
* pBuf
= new sal_uInt8
[ 1 ];
3291 AddOpt( DFF_Prop_textRectangles
, true, 0, pBuf
, 0 );
3297 if ( nPathFlags
!= nPathFlagsOrg
)
3298 AddOpt( DFF_Prop_fFillOK
, nPathFlags
);
3301 else if ( rProp
.Name
.equals( sTextPath
) )
3303 uno::Sequence
< beans::PropertyValue
> aTextPathPropSeq
;
3304 if ( rProp
.Value
>>= aTextPathPropSeq
)
3306 sal_uInt32 nTextPathFlagsOrg
, nTextPathFlags
;
3307 nTextPathFlagsOrg
= nTextPathFlags
= 0xffff1000; // default
3308 if ( GetOpt( DFF_Prop_gtextFStrikethrough
, nTextPathFlags
) )
3309 nTextPathFlagsOrg
= nTextPathFlags
;
3311 sal_Int32 r
, nrCount
= aTextPathPropSeq
.getLength();
3312 for ( r
= 0; r
< nrCount
; r
++ )
3314 const beans::PropertyValue
& rrProp
= aTextPathPropSeq
[ r
];
3315 const OUString
sTextPathMode ( "TextPathMode" );
3316 const OUString
sTextPathScaleX ( "ScaleX" );
3317 const OUString
sSameLetterHeights ( "SameLetterHeights" );
3319 if ( rrProp
.Name
.equals( sTextPath
) )
3322 if ( rrProp
.Value
>>= bTextPathOn
)
3324 nTextPathFlags
|= 0x40000000;
3327 nTextPathFlags
|= 0x4000;
3329 sal_uInt32 nPathFlags
= 0x39;
3330 GetOpt( DFF_Prop_fFillOK
, nPathFlags
); // SJ: can be removed if we are supporting the TextPathAllowed property in XML
3331 nPathFlags
|= 0x40004;
3332 AddOpt( DFF_Prop_fFillOK
, nPathFlags
);
3335 nTextPathFlags
&=~0x4000;
3338 else if ( rrProp
.Name
.equals( sTextPathMode
) )
3340 css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode
;
3341 if ( rrProp
.Value
>>= eTextPathMode
)
3343 nTextPathFlags
|= 0x05000000;
3344 nTextPathFlags
&=~0x500; // TextPathMode_NORMAL
3345 if ( eTextPathMode
== css::drawing::EnhancedCustomShapeTextPathMode_PATH
)
3346 nTextPathFlags
|= 0x100;
3347 else if ( eTextPathMode
== css::drawing::EnhancedCustomShapeTextPathMode_SHAPE
)
3348 nTextPathFlags
|= 0x500;
3351 else if ( rrProp
.Name
.equals( sTextPathScaleX
) )
3353 bool bTextPathScaleX
;
3354 if ( rrProp
.Value
>>= bTextPathScaleX
)
3356 nTextPathFlags
|= 0x00400000;
3357 if ( bTextPathScaleX
)
3358 nTextPathFlags
|= 0x40;
3360 nTextPathFlags
&=~0x40;
3363 else if ( rrProp
.Name
.equals( sSameLetterHeights
) )
3365 bool bSameLetterHeights
;
3366 if ( rrProp
.Value
>>= bSameLetterHeights
)
3368 nTextPathFlags
|= 0x00800000;
3369 if ( bSameLetterHeights
)
3370 nTextPathFlags
|= 0x80;
3372 nTextPathFlags
&=~0x80;
3376 if ( nTextPathFlags
& 0x4000 ) // Is FontWork ?
3380 uno::Reference
< text::XSimpleText
> xText( rXShape
, uno::UNO_QUERY
);
3382 aText
= xText
->getString();
3383 if ( aText
.isEmpty() )
3384 aText
= "your text"; // TODO: moving into a resource
3385 AddOpt( DFF_Prop_gtextUNICODE
, aText
);
3389 const OUString
sCharFontName( "CharFontName" );
3390 uno::Any aAny
= aXPropSet
->getPropertyValue( sCharFontName
);
3392 if ( aFontName
.isEmpty() )
3393 aFontName
= "Arial Black";
3394 AddOpt( DFF_Prop_gtextFont
, aFontName
);
3396 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "CharScaleWidth", true ) )
3398 sal_Int16 nCharScaleWidth
= 100;
3399 if ( aAny
>>= nCharScaleWidth
)
3401 if ( nCharScaleWidth
!= 100 )
3403 sal_Int32 nVal
= nCharScaleWidth
* 655;
3404 AddOpt( DFF_Prop_gtextSpacing
, nVal
);
3408 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "CharHeight", true ) )
3410 float fCharHeight
= 0.0;
3411 if ( aAny
>>= fCharHeight
)
3413 sal_Int32 nTextSize
= static_cast< sal_Int32
> ( fCharHeight
* 65536 );
3414 AddOpt(ESCHER_Prop_gtextSize
, nTextSize
);
3417 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "CharKerning", true ) )
3419 sal_Int16 nCharKerning
= sal_Int16();
3420 if ( aAny
>>= nCharKerning
)
3422 nTextPathFlags
|= 0x10000000;
3424 nTextPathFlags
|= 0x1000;
3426 nTextPathFlags
&=~0x1000;
3429 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "CharPosture", true ) )
3431 awt::FontSlant eFontSlant
;
3432 if ( aAny
>>= eFontSlant
)
3434 nTextPathFlags
|= 0x100010;
3435 if ( eFontSlant
!= awt::FontSlant_NONE
)
3436 nTextPathFlags
|= 0x10;
3438 nTextPathFlags
&=~0x10;
3441 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "CharWeight", true ) )
3443 float fFontWidth
= 0;
3444 if ( aAny
>>= fFontWidth
)
3446 nTextPathFlags
|= 0x200020;
3447 if ( fFontWidth
> awt::FontWeight::NORMAL
)
3448 nTextPathFlags
|= 0x20;
3450 nTextPathFlags
&=~0x20;
3453 // export gTextAlign attr
3454 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, "TextHorizontalAdjust", true ) )
3456 MSO_GeoTextAlign gTextAlign
= mso_alignTextCenter
;
3457 drawing::TextHorizontalAdjust
eHA( drawing::TextHorizontalAdjust_LEFT
);
3461 case drawing::TextHorizontalAdjust_LEFT
:
3462 gTextAlign
= mso_alignTextLeft
;
3464 case drawing::TextHorizontalAdjust_CENTER
:
3465 gTextAlign
= mso_alignTextCenter
;
3467 case drawing::TextHorizontalAdjust_RIGHT
:
3468 gTextAlign
= mso_alignTextRight
;
3470 case drawing::TextHorizontalAdjust_BLOCK
:
3472 SdrFitToSizeType
eFTS( static_cast<const SdrTextFitToSizeTypeItem
&>(pCustoShape
->GetMergedItem( SDRATTR_TEXT_FITTOSIZE
)).GetValue() );
3473 if (eFTS
== SdrFitToSizeType::AllLines
||
3474 eFTS
== SdrFitToSizeType::Proportional
)
3476 gTextAlign
= mso_alignTextStretch
;
3480 gTextAlign
= mso_alignTextWordJust
;
3487 AddOpt(DFF_Prop_gtextAlign
,gTextAlign
);
3490 if((nTextPathFlags
& 0x4000) != 0) // Is Font work
3492 OutlinerParaObject
* pOutlinerParaObject
= pCustoShape
->GetOutlinerParaObject();
3493 if ( pOutlinerParaObject
&& pOutlinerParaObject
->IsVertical() )
3494 nTextPathFlags
|= 0x2000;
3497 // Use gtextFStretch for Watermark like MSO does
3498 nTextPathFlags
|= use_gtextFBestFit
| gtextFBestFit
3499 | use_gtextFStretch
| gtextFStretch
3500 | use_gtextFShrinkFit
| gtextFShrinkFit
;
3502 if ( nTextPathFlags
!= nTextPathFlagsOrg
)
3503 AddOpt( DFF_Prop_gtextFStrikethrough
, nTextPathFlags
);
3506 else if ( rProp
.Name
.equals( sHandles
) )
3508 if ( !bIsDefaultObject
)
3510 bPredefinedHandlesUsed
= false;
3511 if ( rProp
.Value
>>= aHandlesPropSeq
)
3513 sal_uInt16 nElements
= (sal_uInt16
)aHandlesPropSeq
.getLength();
3516 sal_uInt16 k
, j
, nElementSize
= 36;
3517 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3518 SvMemoryStream
aOut( nStreamSize
);
3519 aOut
.WriteUInt16( nElements
)
3520 .WriteUInt16( nElements
)
3521 .WriteUInt16( nElementSize
);
3523 for ( k
= 0; k
< nElements
; k
++ )
3525 sal_uInt32 nFlags
= 0;
3526 sal_Int32 nXPosition
= 0;
3527 sal_Int32 nYPosition
= 0;
3528 sal_Int32 nXMap
= 0;
3529 sal_Int32 nYMap
= 0;
3530 sal_Int32 nXRangeMin
= 0x80000000;
3531 sal_Int32 nXRangeMax
= 0x7fffffff;
3532 sal_Int32 nYRangeMin
= 0x80000000;
3533 sal_Int32 nYRangeMax
= 0x7fffffff;
3535 const uno::Sequence
< beans::PropertyValue
>& rPropSeq
= aHandlesPropSeq
[ k
];
3536 for ( j
= 0; j
< rPropSeq
.getLength(); j
++ )
3538 const beans::PropertyValue
& rPropVal
= rPropSeq
[ j
];
3540 const OUString
sPosition ( "Position" );
3541 const OUString
sMirroredX ( "MirroredX" );
3542 const OUString
sMirroredY ( "MirroredY" );
3543 const OUString
sSwitched ( "Switched" );
3544 const OUString
sPolar ( "Polar" );
3545 const OUString
sRadiusRangeMinimum ( "RadiusRangeMinimum" );
3546 const OUString
sRadiusRangeMaximum ( "RadiusRangeMaximum" );
3547 const OUString
sRangeXMinimum ( "RangeXMinimum" );
3548 const OUString
sRangeXMaximum ( "RangeXMaximum" );
3549 const OUString
sRangeYMinimum ( "RangeYMinimum" );
3550 const OUString
sRangeYMaximum ( "RangeYMaximum" );
3552 if ( rPropVal
.Name
.equals( sPosition
) )
3554 css::drawing::EnhancedCustomShapeParameterPair aPosition
;
3555 if ( rPropVal
.Value
>>= aPosition
)
3557 GetValueForEnhancedCustomShapeHandleParameter( nXPosition
, aPosition
.First
);
3558 GetValueForEnhancedCustomShapeHandleParameter( nYPosition
, aPosition
.Second
);
3561 else if ( rPropVal
.Name
.equals( sMirroredX
) )
3564 if ( rPropVal
.Value
>>= bMirroredX
)
3570 else if ( rPropVal
.Name
.equals( sMirroredY
) )
3573 if ( rPropVal
.Value
>>= bMirroredY
)
3579 else if ( rPropVal
.Name
.equals( sSwitched
) )
3582 if ( rPropVal
.Value
>>= bSwitched
)
3588 else if ( rPropVal
.Name
.equals( sPolar
) )
3590 css::drawing::EnhancedCustomShapeParameterPair aPolar
;
3591 if ( rPropVal
.Value
>>= aPolar
)
3593 if ( GetValueForEnhancedCustomShapeHandleParameter( nXMap
, aPolar
.First
) )
3595 if ( GetValueForEnhancedCustomShapeHandleParameter( nYMap
, aPolar
.Second
) )
3600 else if ( rPropVal
.Name
.equals( sRadiusRangeMinimum
) )
3602 nYRangeMin
= (sal_Int32
)0xff4c0000; // the range of angles seems to be a not
3603 nYRangeMax
= (sal_Int32
)0x00b40000; // used feature, so we are defaulting this
3605 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum
;
3606 if ( rPropVal
.Value
>>= aRadiusRangeMinimum
)
3608 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin
, aRadiusRangeMinimum
) )
3613 else if ( rPropVal
.Name
.equals( sRadiusRangeMaximum
) )
3615 nYRangeMin
= (sal_Int32
)0xff4c0000; // the range of angles seems to be a not
3616 nYRangeMax
= (sal_Int32
)0x00b40000; // used feature, so we are defaulting this
3618 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum
;
3619 if ( rPropVal
.Value
>>= aRadiusRangeMaximum
)
3621 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax
, aRadiusRangeMaximum
) )
3626 else if ( rPropVal
.Name
.equals( sRangeXMinimum
) )
3628 css::drawing::EnhancedCustomShapeParameter aXRangeMinimum
;
3629 if ( rPropVal
.Value
>>= aXRangeMinimum
)
3631 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin
, aXRangeMinimum
) )
3636 else if ( rPropVal
.Name
.equals( sRangeXMaximum
) )
3638 css::drawing::EnhancedCustomShapeParameter aXRangeMaximum
;
3639 if ( rPropVal
.Value
>>= aXRangeMaximum
)
3641 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax
, aXRangeMaximum
) )
3646 else if ( rPropVal
.Name
.equals( sRangeYMinimum
) )
3648 css::drawing::EnhancedCustomShapeParameter aYRangeMinimum
;
3649 if ( rPropVal
.Value
>>= aYRangeMinimum
)
3651 if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMin
, aYRangeMinimum
) )
3656 else if ( rPropVal
.Name
.equals( sRangeYMaximum
) )
3658 css::drawing::EnhancedCustomShapeParameter aYRangeMaximum
;
3659 if ( rPropVal
.Value
>>= aYRangeMaximum
)
3661 if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMax
, aYRangeMaximum
) )
3667 aOut
.WriteUInt32( nFlags
)
3668 .WriteInt32( nXPosition
)
3669 .WriteInt32( nYPosition
)
3670 .WriteInt32( nXMap
)
3671 .WriteInt32( nYMap
)
3672 .WriteInt32( nXRangeMin
)
3673 .WriteInt32( nXRangeMax
)
3674 .WriteInt32( nYRangeMin
)
3675 .WriteInt32( nYRangeMax
);
3678 nAdjustmentsWhichNeedsToBeConverted
|= ( 1 << ( nYPosition
- 0x100 ) );
3680 sal_uInt8
* pBuf
= new sal_uInt8
[ nStreamSize
];
3681 memcpy( pBuf
, aOut
.GetData(), nStreamSize
);
3682 AddOpt( DFF_Prop_Handles
, true, nStreamSize
- 6, pBuf
, nStreamSize
);
3686 sal_uInt8
* pBuf
= new sal_uInt8
[ 1 ];
3687 AddOpt( DFF_Prop_Handles
, true, 0, pBuf
, 0 );
3692 else if ( rProp
.Name
.equals( sAdjustmentValues
) )
3694 // it is required, that the information which handle is polar has already be read,
3695 // so we are able to change the polar value to a fixed float
3696 aAdjustmentValuesProp
= rProp
.Value
;
3697 bAdjustmentValuesProp
= true;
3700 if ( bAdjustmentValuesProp
)
3702 uno::Sequence
< css::drawing::EnhancedCustomShapeAdjustmentValue
> aAdjustmentSeq
;
3703 if ( aAdjustmentValuesProp
>>= aAdjustmentSeq
)
3705 if ( bPredefinedHandlesUsed
)
3706 LookForPolarHandles( eShapeType
, nAdjustmentsWhichNeedsToBeConverted
);
3708 sal_Int32 k
, nValue
= 0, nAdjustmentValues
= aAdjustmentSeq
.getLength();
3709 for ( k
= 0; k
< nAdjustmentValues
; k
++ )
3710 if( GetAdjustmentValue( aAdjustmentSeq
[ k
], k
, nAdjustmentsWhichNeedsToBeConverted
, nValue
) )
3711 AddOpt( (sal_uInt16
)( DFF_Prop_adjustValue
+ k
), (sal_uInt32
)nValue
);
3714 if( bPathCoordinatesProp
)
3716 css::uno::Sequence
< css::drawing::EnhancedCustomShapeParameterPair
> aCoordinates
;
3717 if ( aPathCoordinatesProp
>>= aCoordinates
)
3719 // creating the vertices
3720 if (aCoordinates
.getLength() > 0)
3722 sal_uInt16 j
, nElements
= (sal_uInt16
)aCoordinates
.getLength();
3723 sal_uInt16 nElementSize
= 8;
3724 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3725 SvMemoryStream
aOut( nStreamSize
);
3726 aOut
.WriteUInt16( nElements
)
3727 .WriteUInt16( nElements
)
3728 .WriteUInt16( nElementSize
);
3729 for( j
= 0; j
< nElements
; j
++ )
3731 sal_Int32 X
= GetValueForEnhancedCustomShapeParameter( aCoordinates
[ j
].First
, aEquationOrder
, true );
3732 sal_Int32 Y
= GetValueForEnhancedCustomShapeParameter( aCoordinates
[ j
].Second
, aEquationOrder
, true );
3733 aOut
.WriteInt32( X
)
3736 sal_uInt8
* pBuf
= new sal_uInt8
[ nStreamSize
];
3737 memcpy( pBuf
, aOut
.GetData(), nStreamSize
);
3738 AddOpt( DFF_Prop_pVertices
, true, nStreamSize
- 6, pBuf
, nStreamSize
); // -6
3742 sal_uInt8
* pBuf
= new sal_uInt8
[ 1 ];
3743 AddOpt( DFF_Prop_pVertices
, true, 0, pBuf
, 0 );
3751 MSO_SPT
EscherPropertyContainer::GetCustomShapeType( const uno::Reference
< drawing::XShape
> & rXShape
, sal_uInt32
& nMirrorFlags
, OUString
& rShapeType
, bool bOOXML
)
3753 MSO_SPT eShapeType
= mso_sptNil
;
3755 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
3756 if ( aXPropSet
.is() )
3760 const OUString
sCustomShapeGeometry( "CustomShapeGeometry" );
3761 uno::Any aGeoPropSet
= aXPropSet
->getPropertyValue( sCustomShapeGeometry
);
3762 uno::Sequence
< beans::PropertyValue
> aGeoPropSeq
;
3763 if ( aGeoPropSet
>>= aGeoPropSeq
)
3765 sal_Int32 i
, nCount
= aGeoPropSeq
.getLength();
3766 for ( i
= 0; i
< nCount
; i
++ )
3768 const beans::PropertyValue
& rProp
= aGeoPropSeq
[ i
];
3769 if ( rProp
.Name
== "Type" )
3771 if ( rProp
.Value
>>= rShapeType
)
3775 // In case of VML export, try to handle the
3776 // ooxml- prefix in rShapeType. If that fails,
3777 // just do the same as the binary export.
3778 OString aType
= OUStringToOString(rShapeType
, RTL_TEXTENCODING_UTF8
);
3779 eShapeType
= msfilter::util::GETVMLShapeType(aType
);
3780 if (eShapeType
== mso_sptNil
)
3781 eShapeType
= EnhancedCustomShapeTypeNames::Get(rShapeType
);
3784 eShapeType
= EnhancedCustomShapeTypeNames::Get( rShapeType
);
3787 else if ( rProp
.Name
== "MirroredX" )
3790 if ( ( rProp
.Value
>>= bMirroredX
) && bMirroredX
)
3791 nMirrorFlags
|= SHAPEFLAG_FLIPH
;
3793 else if ( rProp
.Name
== "MirroredY" )
3796 if ( ( rProp
.Value
>>= bMirroredY
) && bMirroredY
)
3797 nMirrorFlags
|= SHAPEFLAG_FLIPV
;
3802 catch( const css::uno::Exception
& )
3810 // Implement for form control export
3811 bool EscherPropertyContainer::CreateBlipPropertiesforOLEControl(const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
, const css::uno::Reference
< css::drawing::XShape
> & rXShape
)
3813 SdrObject
* pShape
= GetSdrObjectFromXShape( rXShape
);
3816 SdrModel
* pMod
= pShape
->GetModel();
3817 Graphic
aGraphic(SdrExchangeView::GetObjGraphic( pMod
, pShape
));
3819 GraphicObject aGraphicObject
= aGraphic
;
3820 OString aUniqueId
= aGraphicObject
.GetUniqueID();
3821 if ( aUniqueId
.getLength() )
3823 if ( pGraphicProvider
&& pPicOutStrm
&& pShapeBoundRect
)
3825 Rectangle
aRect( Point( 0, 0 ), pShapeBoundRect
->GetSize() );
3827 sal_uInt32 nBlibId
= pGraphicProvider
->GetBlibID( *pPicOutStrm
, aUniqueId
, aRect
);
3830 AddOpt( ESCHER_Prop_pib
, nBlibId
, true );
3831 ImplCreateGraphicAttributes( rXPropSet
, nBlibId
, false );
3841 EscherPersistTable::EscherPersistTable()
3845 EscherPersistTable::~EscherPersistTable()
3847 for(EscherPersistEntry
* i
: maPersistTable
) {
3852 bool EscherPersistTable::PtIsID( sal_uInt32 nID
)
3854 for(EscherPersistEntry
* pPtr
: maPersistTable
) {
3855 if ( pPtr
->mnID
== nID
) {
3862 void EscherPersistTable::PtInsert( sal_uInt32 nID
, sal_uInt32 nOfs
)
3864 maPersistTable
.push_back( new EscherPersistEntry( nID
, nOfs
) );
3867 void EscherPersistTable::PtDelete( sal_uInt32 nID
)
3869 ::std::vector
< EscherPersistEntry
* >::iterator it
= maPersistTable
.begin();
3870 for( ; it
!= maPersistTable
.end() ; ++it
)
3872 if ( (*it
)->mnID
== nID
) {
3874 maPersistTable
.erase( it
);
3880 sal_uInt32
EscherPersistTable::PtGetOffsetByID( sal_uInt32 nID
)
3882 for(EscherPersistEntry
* pPtr
: maPersistTable
) {
3883 if ( pPtr
->mnID
== nID
) {
3884 return pPtr
->mnOffset
;
3890 void EscherPersistTable::PtReplace( sal_uInt32 nID
, sal_uInt32 nOfs
)
3892 for(EscherPersistEntry
* pPtr
: maPersistTable
) {
3893 if ( pPtr
->mnID
== nID
) {
3894 pPtr
->mnOffset
= nOfs
;
3900 void EscherPersistTable::PtReplaceOrInsert( sal_uInt32 nID
, sal_uInt32 nOfs
)
3902 for(EscherPersistEntry
* pPtr
: maPersistTable
) {
3903 if ( pPtr
->mnID
== nID
) {
3904 pPtr
->mnOffset
= nOfs
;
3908 PtInsert( nID
, nOfs
);
3911 bool EscherPropertyValueHelper::GetPropertyValue(
3912 css::uno::Any
& rAny
,
3913 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
3914 const OUString
& rString
,
3915 bool bTestPropertyAvailability
)
3917 bool bRetValue
= true;
3918 if ( bTestPropertyAvailability
)
3923 css::uno::Reference
< css::beans::XPropertySetInfo
>
3924 aXPropSetInfo( rXPropSet
->getPropertySetInfo() );
3925 if ( aXPropSetInfo
.is() )
3926 bRetValue
= aXPropSetInfo
->hasPropertyByName( rString
);
3928 catch( const css::uno::Exception
& )
3937 rAny
= rXPropSet
->getPropertyValue( rString
);
3938 if ( !rAny
.hasValue() )
3941 catch( const css::uno::Exception
& )
3949 css::beans::PropertyState
EscherPropertyValueHelper::GetPropertyState(
3950 const css::uno::Reference
< css::beans::XPropertySet
> & rXPropSet
,
3951 const OUString
& rPropertyName
)
3953 css::beans::PropertyState eRetValue
= css::beans::PropertyState_AMBIGUOUS_VALUE
;
3956 css::uno::Reference
< css::beans::XPropertyState
> aXPropState
3957 ( rXPropSet
, css::uno::UNO_QUERY
);
3958 if ( aXPropState
.is() )
3959 eRetValue
= aXPropState
->getPropertyState( rPropertyName
);
3961 catch( const css::uno::Exception
& )
3967 EscherBlibEntry::EscherBlibEntry( sal_uInt32 nPictureOffset
, const GraphicObject
& rObject
, const OString
& rId
,
3968 const GraphicAttr
* pGraphicAttr
) :
3969 mnPictureOffset ( nPictureOffset
),
3972 maPrefSize ( rObject
.GetPrefSize() ),
3973 maPrefMapMode ( rObject
.GetPrefMapMode() ),
3976 mbIsNativeGraphicPossible
= ( pGraphicAttr
== nullptr );
3977 meBlibType
= UNKNOWN
;
3980 sal_uInt32 nLen
= static_cast<sal_uInt32
>(rId
.getLength());
3981 const sal_Char
* pData
= rId
.getStr();
3982 GraphicType
eType( rObject
.GetType() );
3983 if ( nLen
&& pData
&& ( eType
!= GraphicType::NONE
) )
3985 mnIdentifier
[ 0 ] = rtl_crc32( 0,pData
, nLen
);
3986 mnIdentifier
[ 1 ] = 0;
3990 if ( pGraphicAttr
->IsSpecialDrawMode()
3991 || pGraphicAttr
->IsMirrored()
3992 || pGraphicAttr
->IsCropped()
3993 || pGraphicAttr
->IsRotated()
3994 || pGraphicAttr
->IsTransparent()
3995 || pGraphicAttr
->IsAdjusted() )
3997 SvMemoryStream
aSt( sizeof( GraphicAttr
) );
3998 aSt
.WriteUInt16( pGraphicAttr
->GetDrawMode() )
3999 .WriteUInt32( static_cast<sal_uInt32
>(pGraphicAttr
->GetMirrorFlags()) )
4000 .WriteInt32( pGraphicAttr
->GetLeftCrop() )
4001 .WriteInt32( pGraphicAttr
->GetTopCrop() )
4002 .WriteInt32( pGraphicAttr
->GetRightCrop() )
4003 .WriteInt32( pGraphicAttr
->GetBottomCrop() )
4004 .WriteUInt16( pGraphicAttr
->GetRotation() )
4005 .WriteInt16( pGraphicAttr
->GetLuminance() )
4006 .WriteInt16( pGraphicAttr
->GetContrast() )
4007 .WriteInt16( pGraphicAttr
->GetChannelR() )
4008 .WriteInt16( pGraphicAttr
->GetChannelG() )
4009 .WriteInt16( pGraphicAttr
->GetChannelB() )
4010 .WriteDouble( pGraphicAttr
->GetGamma() );
4011 aSt
.WriteBool( pGraphicAttr
->IsInvert() )
4012 .WriteUChar( pGraphicAttr
->GetTransparency() );
4013 mnIdentifier
[ 1 ] = rtl_crc32( 0, aSt
.GetData(), aSt
.Tell() );
4016 mbIsNativeGraphicPossible
= true;
4018 sal_uInt32 i
, nTmp
, n1
, n2
;
4020 for ( i
= 0; i
< nLen
; i
++ )
4022 nTmp
= n2
>> 28; // rotating 4 bit
4027 n1
^= *pData
++ - '0';
4029 mnIdentifier
[ 2 ] = n1
;
4030 mnIdentifier
[ 3 ] = n2
;
4035 void EscherBlibEntry::WriteBlibEntry( SvStream
& rSt
, bool bWritePictureOffset
, sal_uInt32 nResize
)
4037 sal_uInt32 nPictureOffset
= ( bWritePictureOffset
) ? mnPictureOffset
: 0;
4039 rSt
.WriteUInt32( ( ESCHER_BSE
<< 16 ) | ( ( (sal_uInt16
)meBlibType
<< 4 ) | 2 ) )
4040 .WriteUInt32( 36 + nResize
)
4041 .WriteUChar( meBlibType
);
4043 switch ( meBlibType
)
4046 case WMF
: // converting EMF/WMF on OS2 to Pict
4047 rSt
.WriteUChar( PICT
);
4050 rSt
.WriteUChar( meBlibType
);
4053 rSt
.WriteBytes(&mnIdentifier
[0], 16);
4054 rSt
.WriteUInt16( 0 )
4055 .WriteUInt32( mnSize
+ mnSizeExtra
)
4056 .WriteUInt32( mnRefCount
)
4057 .WriteUInt32( nPictureOffset
)
4061 EscherBlibEntry::~EscherBlibEntry()
4065 bool EscherBlibEntry::operator==( const EscherBlibEntry
& rEscherBlibEntry
) const
4067 for ( int i
= 0; i
< 3; i
++ )
4069 if ( mnIdentifier
[ i
] != rEscherBlibEntry
.mnIdentifier
[ i
] )
4075 EscherGraphicProvider::EscherGraphicProvider( sal_uInt32 nFlags
) :
4077 mpBlibEntrys ( nullptr ),
4078 mnBlibBufSize ( 0 ),
4083 EscherGraphicProvider::~EscherGraphicProvider()
4085 for ( sal_uInt32 i
= 0; i
< mnBlibEntrys
; delete mpBlibEntrys
[ i
++ ] ) ;
4086 delete[] mpBlibEntrys
;
4089 void EscherGraphicProvider::SetNewBlipStreamOffset( sal_Int32 nOffset
)
4091 for( sal_uInt32 i
= 0; i
< mnBlibEntrys
; i
++ )
4093 EscherBlibEntry
* pBlibEntry
= mpBlibEntrys
[ i
];
4094 pBlibEntry
->mnPictureOffset
+= nOffset
;
4098 sal_uInt32
EscherGraphicProvider::ImplInsertBlib( EscherBlibEntry
* p_EscherBlibEntry
)
4100 if ( mnBlibBufSize
== mnBlibEntrys
)
4102 mnBlibBufSize
+= 64;
4103 EscherBlibEntry
** pTemp
= new EscherBlibEntry
*[ mnBlibBufSize
];
4104 for ( sal_uInt32 i
= 0; i
< mnBlibEntrys
; i
++ )
4106 pTemp
[ i
] = mpBlibEntrys
[ i
];
4108 delete[] mpBlibEntrys
;
4109 mpBlibEntrys
= pTemp
;
4111 mpBlibEntrys
[ mnBlibEntrys
++ ] = p_EscherBlibEntry
;
4112 return mnBlibEntrys
;
4115 sal_uInt32
EscherGraphicProvider::GetBlibStoreContainerSize( SvStream
* pMergePicStreamBSE
) const
4117 sal_uInt32 nSize
= 44 * mnBlibEntrys
+ 8;
4118 if ( pMergePicStreamBSE
)
4120 for ( sal_uInt32 i
= 0; i
< mnBlibEntrys
; i
++ )
4121 nSize
+= mpBlibEntrys
[ i
]->mnSize
+ mpBlibEntrys
[ i
]->mnSizeExtra
;
4126 void EscherGraphicProvider::WriteBlibStoreEntry(SvStream
& rSt
,
4127 sal_uInt32 nBlipId
, bool bWritePictureOffSet
, sal_uInt32 nResize
)
4129 if (nBlipId
> mnBlibEntrys
|| nBlipId
== 0)
4131 mpBlibEntrys
[nBlipId
-1]->WriteBlibEntry(rSt
, bWritePictureOffSet
, nResize
);
4134 void EscherGraphicProvider::WriteBlibStoreContainer( SvStream
& rSt
, SvStream
* pMergePicStreamBSE
)
4136 sal_uInt32 nSize
= GetBlibStoreContainerSize( pMergePicStreamBSE
);
4139 rSt
.WriteUInt32( ( ESCHER_BstoreContainer
<< 16 ) | 0x1f )
4140 .WriteUInt32( nSize
- 8 );
4142 if ( pMergePicStreamBSE
)
4144 sal_uInt32 i
, nBlipSize
, nOldPos
= pMergePicStreamBSE
->Tell();
4145 const sal_uInt32 nBuf
= 0x40000; // 256KB buffer
4146 std::unique_ptr
<sal_uInt8
[]> pBuf(new sal_uInt8
[ nBuf
]);
4148 for ( i
= 0; i
< mnBlibEntrys
; i
++ )
4150 EscherBlibEntry
* pBlibEntry
= mpBlibEntrys
[ i
];
4152 ESCHER_BlibType nBlibType
= pBlibEntry
->meBlibType
;
4153 nBlipSize
= pBlibEntry
->mnSize
+ pBlibEntry
->mnSizeExtra
;
4154 pBlibEntry
->WriteBlibEntry( rSt
, false, nBlipSize
);
4157 pMergePicStreamBSE
->Seek( pBlibEntry
->mnPictureOffset
);
4159 // record version and instance
4160 pMergePicStreamBSE
->ReadUInt16( n16
);
4161 rSt
.WriteUInt16( n16
);
4163 pMergePicStreamBSE
->ReadUInt16( n16
);
4164 rSt
.WriteUInt16( ESCHER_BlipFirst
+ nBlibType
);
4165 DBG_ASSERT( n16
== ESCHER_BlipFirst
+ nBlibType
, "EscherGraphicProvider::WriteBlibStoreContainer: BLIP record types differ" );
4168 pMergePicStreamBSE
->ReadUInt32( n32
);
4170 rSt
.WriteUInt32( nBlipSize
);
4171 DBG_ASSERT( nBlipSize
== n32
, "EscherGraphicProvider::WriteBlibStoreContainer: BLIP sizes differ" );
4175 sal_uInt32 nBytes
= ( nBlipSize
> nBuf
? nBuf
: nBlipSize
);
4176 pMergePicStreamBSE
->ReadBytes(pBuf
.get(), nBytes
);
4177 rSt
.WriteBytes(pBuf
.get(), nBytes
);
4178 nBlipSize
-= nBytes
;
4181 pMergePicStreamBSE
->Seek( nOldPos
);
4185 for ( sal_uInt32 i
= 0; i
< mnBlibEntrys
; i
++ )
4186 mpBlibEntrys
[ i
]->WriteBlibEntry( rSt
, true );
4191 bool EscherGraphicProvider::GetPrefSize( const sal_uInt32 nBlibId
, Size
& rPrefSize
, MapMode
& rPrefMapMode
)
4193 bool bInRange
= nBlibId
&& ( ( nBlibId
- 1 ) < mnBlibEntrys
);
4196 EscherBlibEntry
* pEntry
= mpBlibEntrys
[ nBlibId
- 1 ];
4197 rPrefSize
= pEntry
->maPrefSize
;
4198 rPrefMapMode
= pEntry
->maPrefMapMode
;
4203 sal_uInt32
EscherGraphicProvider::GetBlibID( SvStream
& rPicOutStrm
, const OString
& rId
,
4204 const Rectangle
& /* rBoundRect */, const css::awt::Rectangle
* pVisArea
,
4205 const GraphicAttr
* pGraphicAttr
, const bool bOOxmlExport
)
4207 sal_uInt32 nBlibId
= 0;
4208 GraphicObject
aGraphicObject( rId
);
4210 EscherBlibEntry
* p_EscherBlibEntry
= new EscherBlibEntry( rPicOutStrm
.Tell(), aGraphicObject
, rId
, pGraphicAttr
);
4211 if ( !p_EscherBlibEntry
->IsEmpty() )
4213 for ( sal_uInt32 i
= 0; i
< mnBlibEntrys
; i
++ )
4215 if ( *( mpBlibEntrys
[ i
] ) == *p_EscherBlibEntry
)
4217 mpBlibEntrys
[ i
]->mnRefCount
++;
4218 delete p_EscherBlibEntry
;
4223 bool bUseNativeGraphic( false );
4225 Graphic
aGraphic( aGraphicObject
.GetTransformedGraphic( pGraphicAttr
) );
4226 GfxLink aGraphicLink
;
4227 SvMemoryStream aStream
;
4229 const sal_uInt8
* pGraphicAry
= nullptr;
4231 if ( p_EscherBlibEntry
->mbIsNativeGraphicPossible
&& aGraphic
.IsLink() )
4233 aGraphicLink
= aGraphic
.GetLink();
4235 p_EscherBlibEntry
->mnSize
= aGraphicLink
.GetDataSize();
4236 pGraphicAry
= aGraphicLink
.GetData();
4238 if ( p_EscherBlibEntry
->mnSize
&& pGraphicAry
)
4240 switch ( aGraphicLink
.GetType() )
4242 case GfxLinkType::NativeJpg
: p_EscherBlibEntry
->meBlibType
= PEG
; break;
4243 case GfxLinkType::NativePng
: p_EscherBlibEntry
->meBlibType
= PNG
; break;
4245 // #i15508# added BMP type for better exports; need to check this
4246 // checked - does not work that way, so keep out for now. It may
4247 // work somehow with direct DIB data, but that would need to be checked
4249 // for more comments please check RtfAttributeOutput::FlyFrameGraphic
4251 // case GfxLinkType::NativeBmp : p_EscherBlibEntry->meBlibType = DIB; break;
4253 case GfxLinkType::NativeWmf
:
4255 if ( pGraphicAry
&& ( p_EscherBlibEntry
->mnSize
> 0x2c ) )
4257 if ( ( pGraphicAry
[ 0x28 ] == 0x20 ) && ( pGraphicAry
[ 0x29 ] == 0x45 ) // check the magic
4258 && ( pGraphicAry
[ 0x2a ] == 0x4d ) && ( pGraphicAry
[ 0x2b ] == 0x46 ) ) // number ( emf detection )
4260 p_EscherBlibEntry
->meBlibType
= EMF
;
4264 p_EscherBlibEntry
->meBlibType
= WMF
;
4265 if ( ( pGraphicAry
[ 0 ] == 0xd7 ) && ( pGraphicAry
[ 1 ] == 0xcd )
4266 && ( pGraphicAry
[ 2 ] == 0xc6 ) && ( pGraphicAry
[ 3 ] == 0x9a ) )
4267 { // we have to get rid of the metafileheader
4269 p_EscherBlibEntry
->mnSize
-= 22;
4277 if ( p_EscherBlibEntry
->meBlibType
!= UNKNOWN
)
4278 bUseNativeGraphic
= true;
4281 if ( !bUseNativeGraphic
)
4283 GraphicType eGraphicType
= aGraphic
.GetType();
4284 if ( ( eGraphicType
== GraphicType::Bitmap
) || ( eGraphicType
== GraphicType::GdiMetafile
) )
4286 sal_uInt32 nErrCode
;
4287 if ( !aGraphic
.IsAnimated() )
4288 nErrCode
= GraphicConverter::Export( aStream
, aGraphic
, ( eGraphicType
== GraphicType::Bitmap
) ? ConvertDataFormat::PNG
: ConvertDataFormat::EMF
);
4290 { // to store a animation, a gif has to be included into the msOG chunk of a png #I5583#
4291 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
4292 SvMemoryStream aGIFStream
;
4293 const char* pString
= "MSOFFICE9.0";
4294 aGIFStream
.WriteBytes(pString
, strlen(pString
));
4295 nErrCode
= rFilter
.ExportGraphic( aGraphic
, OUString(), aGIFStream
,
4296 rFilter
.GetExportFormatNumberForShortName( "GIF" ) );
4298 nErrCode
!= ERRCODE_NONE
, "filter.ms",
4299 "ExportGraphic to GIF failed with " << nErrCode
);
4300 if (nErrCode
== ERRCODE_NONE
)
4302 css::uno::Sequence
< css::beans::PropertyValue
> aFilterData( 1 );
4303 css::uno::Sequence
< css::beans::PropertyValue
> aAdditionalChunkSequence( 1 );
4304 sal_uInt32 nGIFSreamLen
= aGIFStream
.Tell();
4305 css::uno::Sequence
< sal_Int8
> aGIFSeq( nGIFSreamLen
);
4306 sal_Int8
* pSeq
= aGIFSeq
.getArray();
4307 aGIFStream
.Seek( STREAM_SEEK_TO_BEGIN
);
4308 aGIFStream
.ReadBytes(pSeq
, nGIFSreamLen
);
4309 css::beans::PropertyValue aChunkProp
, aFilterProp
;
4310 aChunkProp
.Name
= "msOG";
4311 aChunkProp
.Value
<<= aGIFSeq
;
4312 aAdditionalChunkSequence
[ 0 ] = aChunkProp
;
4313 aFilterProp
.Name
= "AdditionalChunks";
4314 aFilterProp
.Value
<<= aAdditionalChunkSequence
;
4315 aFilterData
[ 0 ] = aFilterProp
;
4316 nErrCode
= rFilter
.ExportGraphic( aGraphic
, OUString(), aStream
,
4317 rFilter
.GetExportFormatNumberForShortName( "PNG" ), &aFilterData
);
4320 if ( nErrCode
== ERRCODE_NONE
)
4322 p_EscherBlibEntry
->meBlibType
= ( eGraphicType
== GraphicType::Bitmap
) ? PNG
: EMF
;
4323 aStream
.Seek( STREAM_SEEK_TO_END
);
4324 p_EscherBlibEntry
->mnSize
= aStream
.Tell();
4325 pGraphicAry
= static_cast<sal_uInt8
const *>(aStream
.GetData());
4330 ESCHER_BlibType eBlibType
= p_EscherBlibEntry
->meBlibType
;
4331 if ( p_EscherBlibEntry
->mnSize
&& pGraphicAry
&& ( eBlibType
!= UNKNOWN
) )
4333 sal_uInt32 nExtra
, nAtomSize
= 0;
4334 sal_uInt32 nInstance
, nUncompressedSize
= p_EscherBlibEntry
->mnSize
;
4336 if ( mnFlags
& E_GRAPH_PROV_USE_INSTANCES
)
4338 rPicOutStrm
.WriteUInt32( 0x7f90000 | (sal_uInt16
)( mnBlibEntrys
<< 4 ) )
4340 nAtomSize
= rPicOutStrm
.Tell();
4341 if ( eBlibType
== PNG
)
4342 rPicOutStrm
.WriteUInt16( 0x0606 );
4343 else if ( eBlibType
== WMF
)
4344 rPicOutStrm
.WriteUInt16( 0x0403 );
4345 else if ( eBlibType
== EMF
)
4346 rPicOutStrm
.WriteUInt16( 0x0402 );
4347 else if ( eBlibType
== PEG
)
4348 rPicOutStrm
.WriteUInt16( 0x0505 );
4351 // fdo#69607 do not compress WMF files if we are in OOXML export
4352 if ( ( eBlibType
== PEG
) || ( eBlibType
== PNG
) // || ( eBlibType == DIB )) // #i15508#
4353 || ( ( ( eBlibType
== WMF
) || ( eBlibType
== EMF
) ) && bOOxmlExport
) )
4356 p_EscherBlibEntry
->mnSizeExtra
= nExtra
+ 8;
4358 // #i15508# type see SvxMSDffManager::GetBLIPDirect (checked, does not work this way)
4359 // see RtfAttributeOutput::FlyFrameGraphic for more comments
4360 // maybe it would work with direct DIB data, but that would need thorough testing
4361 if( eBlibType
== PNG
)
4363 nInstance
= 0xf01e6e00;
4365 else // if( eBlibType == PEG )
4367 nInstance
= 0xf01d46a0;
4369 //else // eBlibType == DIB
4371 // nInstance = 0xf01d7A80;
4375 //nInstance = ( eBlibType == PNG ) ? 0xf01e6e00 : 0xf01d46a0;
4378 rPicOutStrm
.WriteUInt32( nInstance
).WriteUInt32( p_EscherBlibEntry
->mnSize
+ nExtra
);
4379 rPicOutStrm
.WriteBytes(p_EscherBlibEntry
->mnIdentifier
, 16);
4380 rPicOutStrm
.WriteUChar( 0xff );
4381 rPicOutStrm
.WriteBytes(pGraphicAry
, p_EscherBlibEntry
->mnSize
);
4385 ZCodec
aZCodec( 0x8000, 0x8000 );
4386 aZCodec
.BeginCompression();
4387 SvMemoryStream aDestStrm
;
4388 aZCodec
.Write( aDestStrm
, pGraphicAry
, p_EscherBlibEntry
->mnSize
);
4389 aZCodec
.EndCompression();
4390 aDestStrm
.Seek( STREAM_SEEK_TO_END
);
4391 p_EscherBlibEntry
->mnSize
= aDestStrm
.Tell();
4392 pGraphicAry
= static_cast<sal_uInt8
const *>(aDestStrm
.GetData());
4393 if ( p_EscherBlibEntry
->mnSize
&& pGraphicAry
)
4395 nExtra
= eBlibType
== WMF
? 0x42 : 0x32; // !EMF -> no change
4396 p_EscherBlibEntry
->mnSizeExtra
= nExtra
+ 8;
4397 nInstance
= ( eBlibType
== WMF
) ? 0xf01b2170 : 0xf01a3d40; // !EMF -> no change
4398 rPicOutStrm
.WriteUInt32( nInstance
).WriteUInt32( p_EscherBlibEntry
->mnSize
+ nExtra
);
4399 if ( eBlibType
== WMF
) // !EMF -> no change
4400 rPicOutStrm
.WriteBytes(p_EscherBlibEntry
->mnIdentifier
, 16);
4401 rPicOutStrm
.WriteBytes(p_EscherBlibEntry
->mnIdentifier
, 16);
4405 For Word the stored size of the graphic is critical the
4406 metafile boundaries must match the actual graphics
4407 boundaries, and the width and height must be in EMU's
4409 If you don't do it this way then objects edited in the
4410 msoffice app may show strange behaviour as the size jumps
4411 around, and the original size and scaling factor in word
4412 will be a very strange figure
4414 sal_uInt32 nPrefWidth
= p_EscherBlibEntry
->maPrefSize
.Width();
4415 sal_uInt32 nPrefHeight
= p_EscherBlibEntry
->maPrefSize
.Height();
4416 sal_uInt32 nWidth
, nHeight
;
4419 nWidth
= pVisArea
->Width
* 360;
4420 nHeight
= pVisArea
->Height
* 360;
4424 Size
aPrefSize(lcl_SizeToEmu(p_EscherBlibEntry
->maPrefSize
, p_EscherBlibEntry
->maPrefMapMode
));
4425 nWidth
= aPrefSize
.Width() * 360;
4426 nHeight
= aPrefSize
.Height() * 360;
4428 rPicOutStrm
.WriteUInt32( nUncompressedSize
) // WMFSize without FileHeader
4429 .WriteInt32( 0 ) // since we can't find out anymore what the original size of
4430 .WriteInt32( 0 ) // the WMF (without Fileheader) was we write 10cm / x
4431 .WriteUInt32( nPrefWidth
)
4432 .WriteUInt32( nPrefHeight
)
4433 .WriteUInt32( nWidth
)
4434 .WriteUInt32( nHeight
)
4435 .WriteUInt32( p_EscherBlibEntry
->mnSize
)
4436 .WriteUInt16( 0xfe00 ); // compression Flags
4437 rPicOutStrm
.WriteBytes(pGraphicAry
, p_EscherBlibEntry
->mnSize
);
4442 sal_uInt32 nPos
= rPicOutStrm
.Tell();
4443 rPicOutStrm
.Seek( nAtomSize
- 4 );
4444 rPicOutStrm
.WriteUInt32( nPos
- nAtomSize
);
4445 rPicOutStrm
.Seek( nPos
);
4447 nBlibId
= ImplInsertBlib( p_EscherBlibEntry
);
4448 p_EscherBlibEntry
= nullptr;
4451 delete p_EscherBlibEntry
;
4455 struct EscherConnectorRule
4458 sal_uInt32 nShapeA
; // SPID of shape A
4459 sal_uInt32 nShapeB
; // SPID of shape B
4460 sal_uInt32 nShapeC
; // SPID of connector shape
4461 sal_uInt32 ncptiA
; // Connection site Index of shape A
4462 sal_uInt32 ncptiB
; // Connection site Index of shape B
4465 struct EscherShapeListEntry
4467 css::uno::Reference
< css::drawing::XShape
> aXShape
;
4468 sal_uInt32 n_EscherId
;
4470 EscherShapeListEntry( const css::uno::Reference
4471 < css::drawing::XShape
> & rShape
, sal_uInt32 nId
) :
4473 n_EscherId ( nId
) {}
4476 sal_uInt32
EscherConnectorListEntry::GetClosestPoint( const tools::Polygon
& rPoly
, const css::awt::Point
& rPoint
)
4478 sal_uInt16 nCount
= rPoly
.GetSize();
4479 sal_uInt16 nClosest
= nCount
;
4480 double fDist
= (sal_uInt32
)0xffffffff;
4483 double fDistance
= hypot( rPoint
.X
- rPoly
[ nCount
].X(), rPoint
.Y
- rPoly
[ nCount
].Y() );
4484 if ( fDistance
< fDist
)
4494 // for rectangles for ellipses for polygons
4496 // nRule = 0 ->Top 0 ->Top nRule = Index auf ein (Poly)Polygon Punkt
4497 // 1 ->Left 2 ->Left
4498 // 2 ->Bottom 4 ->Bottom
4499 // 3 ->Right 6 ->Right
4501 sal_uInt32
EscherConnectorListEntry::GetConnectorRule( bool bFirst
)
4503 sal_uInt32 nRule
= 0;
4506 css::awt::Point
aRefPoint( ( bFirst
) ? maPointA
: maPointB
);
4507 css::uno::Reference
< css::drawing::XShape
>
4508 aXShape( ( bFirst
) ? mXConnectToA
: mXConnectToB
);
4510 OUString
aString(aXShape
->getShapeType());
4511 OStringBuffer
aBuf(OUStringToOString(aString
, RTL_TEXTENCODING_UTF8
));
4512 aBuf
.remove( 0, 13 ); // removing "com.sun.star."
4513 sal_Int16 nPos
= aBuf
.toString().indexOf("Shape");
4514 aBuf
.remove(nPos
, 5);
4515 OString aType
= aBuf
.makeStringAndClear();
4517 css::uno::Reference
< css::beans::XPropertySet
>
4518 aPropertySet( aXShape
, css::uno::UNO_QUERY
);
4520 if ((aType
== OString( "drawing.PolyPolygon" )) || (aType
== OString( "drawing.PolyLine" )))
4522 if ( aPropertySet
.is() )
4524 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aPropertySet
, "PolyPolygon" ) )
4526 auto pSourcePolyPolygon
=
4527 o3tl::doAccess
<css::drawing::PointSequenceSequence
>(aAny
);
4528 sal_Int32 nOuterSequenceCount
= pSourcePolyPolygon
->getLength();
4529 css::drawing::PointSequence
const * pOuterSequence
= pSourcePolyPolygon
->getConstArray();
4531 if ( pOuterSequence
)
4533 sal_Int32 a
, b
, nIndex
= 0;
4534 sal_uInt32 nDistance
= 0xffffffff;
4535 for( a
= 0; a
< nOuterSequenceCount
; a
++ )
4537 css::drawing::PointSequence
const * pInnerSequence
= pOuterSequence
++;
4538 if ( pInnerSequence
)
4540 css::awt::Point
const * pArray
= pInnerSequence
->getConstArray();
4543 for ( b
= 0; b
< pInnerSequence
->getLength(); b
++, nIndex
++, pArray
++ )
4545 sal_uInt32 nDist
= (sal_uInt32
)hypot( aRefPoint
.X
- pArray
->X
, aRefPoint
.Y
- pArray
->Y
);
4546 if ( nDist
< nDistance
)
4559 else if ((aType
== OString( "drawing.OpenBezier" )) || (aType
== OString( "drawing.OpenFreeHand" )) || (aType
== OString( "drawing.PolyLinePath" ))
4560 || (aType
== OString( "drawing.ClosedBezier" )) || ( aType
== OString( "drawing.ClosedFreeHand" )) || (aType
== OString( "drawing.PolyPolygonPath" )) )
4562 css::uno::Reference
< css::beans::XPropertySet
>
4563 aPropertySet2( aXShape
, css::uno::UNO_QUERY
);
4564 if ( aPropertySet2
.is() )
4566 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aPropertySet2
, "PolyPolygonBezier" ) )
4568 auto pSourcePolyPolygon
=
4569 o3tl::doAccess
<css::drawing::PolyPolygonBezierCoords
>(aAny
);
4570 sal_Int32 nOuterSequenceCount
= pSourcePolyPolygon
->Coordinates
.getLength();
4572 // Zeiger auf innere sequences holen
4573 css::drawing::PointSequence
const * pOuterSequence
=
4574 pSourcePolyPolygon
->Coordinates
.getConstArray();
4575 css::drawing::FlagSequence
const * pOuterFlags
=
4576 pSourcePolyPolygon
->Flags
.getConstArray();
4578 if ( pOuterSequence
&& pOuterFlags
)
4580 sal_Int32 a
, b
, nIndex
= 0;
4581 sal_uInt32 nDistance
= 0xffffffff;
4583 for ( a
= 0; a
< nOuterSequenceCount
; a
++ )
4585 css::drawing::PointSequence
const * pInnerSequence
= pOuterSequence
++;
4586 css::drawing::FlagSequence
const * pInnerFlags
= pOuterFlags
++;
4587 if ( pInnerSequence
&& pInnerFlags
)
4589 css::awt::Point
const * pArray
= pInnerSequence
->getConstArray();
4590 css::drawing::PolygonFlags
const * pFlags
= pInnerFlags
->getConstArray();
4591 if ( pArray
&& pFlags
)
4593 for ( b
= 0; b
< pInnerSequence
->getLength(); b
++, pArray
++ )
4595 css::drawing::PolygonFlags ePolyFlags
= *pFlags
++;
4596 if ( ePolyFlags
== css::drawing::PolygonFlags_CONTROL
)
4598 sal_uInt32 nDist
= (sal_uInt32
)hypot( aRefPoint
.X
- pArray
->X
, aRefPoint
.Y
- pArray
->Y
);
4599 if ( nDist
< nDistance
)
4615 bool bRectangularConnection
= true;
4617 if (aType
== "drawing.Custom")
4619 SdrObject
* pCustoShape( GetSdrObjectFromXShape( aXShape
) );
4620 if ( dynamic_cast<const SdrObjCustomShape
* >(pCustoShape
) != nullptr )
4622 const SdrCustomShapeGeometryItem
& rGeometryItem
= static_cast<const SdrCustomShapeGeometryItem
&>(
4623 pCustoShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
));
4625 const OUString
sPath( "Path" );
4626 const OUString
sType( "Type" );
4627 const OUString
sGluePointType( "GluePointType" );
4629 OUString sShapeType
;
4630 const uno::Any
* pType
= rGeometryItem
.GetPropertyValueByName( sType
);
4632 *pType
>>= sShapeType
;
4633 MSO_SPT eSpType
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
4635 uno::Any
* pGluePointType
= ((SdrCustomShapeGeometryItem
&)rGeometryItem
).GetPropertyValueByName( sPath
, sGluePointType
);
4637 sal_Int16 nGluePointType
= sal_Int16();
4638 if ( !( pGluePointType
&&
4639 ( *pGluePointType
>>= nGluePointType
) ) )
4640 nGluePointType
= GetCustomShapeConnectionTypeDefault( eSpType
);
4642 if ( nGluePointType
== css::drawing::EnhancedCustomShapeGluePointType::CUSTOM
)
4644 const SdrGluePointList
* pList
= pCustoShape
->GetGluePointList();
4647 tools::Polygon aPoly
;
4648 sal_uInt16 nNum
, nAnz
= pList
->GetCount();
4651 for ( nNum
= 0; nNum
< nAnz
; nNum
++ )
4653 const SdrGluePoint
& rGP
= (*pList
)[ nNum
];
4654 Point
aPt( rGP
.GetAbsolutePos( *pCustoShape
) );
4655 aPoly
.Insert( POLY_APPEND
, aPt
);
4657 nRule
= GetClosestPoint( aPoly
, aRefPoint
);
4658 bRectangularConnection
= false;
4662 else if ( nGluePointType
== css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS
)
4664 SdrObject
* pPoly
= pCustoShape
->DoConvertToPolyObj( true, true );
4665 if ( dynamic_cast<const SdrPathObj
* >( pPoly
) != nullptr )
4667 sal_Int16 a
, b
, nIndex
= 0;
4668 sal_uInt32 nDistance
= 0xffffffff;
4670 // #i74631# use explicit constructor here. Also XPolyPolygon is not necessary,
4671 // reducing to PolyPolygon
4672 const tools::PolyPolygon
aPolyPoly(static_cast<SdrPathObj
*>(pPoly
)->GetPathPoly());
4674 for ( a
= 0; a
< aPolyPoly
.Count(); a
++ )
4676 const tools::Polygon
& rPoly
= aPolyPoly
.GetObject( a
);
4677 for ( b
= 0; b
< rPoly
.GetSize(); b
++ )
4679 if ( rPoly
.GetFlags( b
) != PolyFlags::Normal
)
4681 const Point
& rPt
= rPoly
[ b
];
4682 sal_uInt32 nDist
= (sal_uInt32
)hypot( aRefPoint
.X
- rPt
.X(), aRefPoint
.Y
- rPt
.Y() );
4683 if ( nDist
< nDistance
)
4691 if ( nDistance
!= 0xffffffff )
4692 bRectangularConnection
= false;
4697 if ( bRectangularConnection
)
4699 css::awt::Point
aPoint( aXShape
->getPosition() );
4700 css::awt::Size
aSize( aXShape
->getSize() );
4702 Rectangle
aRect( Point( aPoint
.X
, aPoint
.Y
), Size( aSize
.Width
, aSize
.Height
) );
4703 Point
aCenter( aRect
.Center() );
4704 tools::Polygon
aPoly( 4 );
4706 aPoly
[ 0 ] = Point( aCenter
.X(), aRect
.Top() );
4707 aPoly
[ 1 ] = Point( aRect
.Left(), aCenter
.Y() );
4708 aPoly
[ 2 ] = Point( aCenter
.X(), aRect
.Bottom() );
4709 aPoly
[ 3 ] = Point( aRect
.Right(), aCenter
.Y() );
4711 sal_Int32 nAngle
= ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aPropertySet
, "RotateAngle", true ) )
4712 ? *o3tl::doAccess
<sal_Int32
>(aAny
) : 0;
4714 aPoly
.Rotate( aRect
.TopLeft(), (sal_uInt16
)( ( nAngle
+ 5 ) / 10 ) );
4715 nRule
= GetClosestPoint( aPoly
, aRefPoint
);
4717 if (aType
== OString( "drawing.Ellipse" ))
4718 nRule
<<= 1; // In PPT an ellipse has 8 ways to connect
4724 EscherSolverContainer::~EscherSolverContainer()
4726 for(EscherShapeListEntry
* i
: maShapeList
) {
4729 for(EscherConnectorListEntry
* i
: maConnectorList
) {
4734 void EscherSolverContainer::AddShape( const css::uno::Reference
< css::drawing::XShape
> & rXShape
, sal_uInt32 nId
)
4736 maShapeList
.push_back( new EscherShapeListEntry( rXShape
, nId
) );
4739 void EscherSolverContainer::AddConnector(
4740 const css::uno::Reference
< css::drawing::XShape
> & rConnector
,
4741 const css::awt::Point
& rPA
,
4742 css::uno::Reference
< css::drawing::XShape
> & rConA
,
4743 const css::awt::Point
& rPB
,
4744 css::uno::Reference
< css::drawing::XShape
> & rConB
4747 maConnectorList
.push_back( new EscherConnectorListEntry( rConnector
, rPA
, rConA
, rPB
, rConB
) );
4750 sal_uInt32
EscherSolverContainer::GetShapeId( const css::uno::Reference
< css::drawing::XShape
> & rXShape
) const
4752 for (EscherShapeListEntry
* pPtr
: maShapeList
)
4754 if ( rXShape
== pPtr
->aXShape
)
4755 return pPtr
->n_EscherId
;
4760 void EscherSolverContainer::WriteSolver( SvStream
& rStrm
)
4762 sal_uInt32 nCount
= maConnectorList
.size();
4765 sal_uInt32 nRecHdPos
, nCurrentPos
, nSize
;
4766 rStrm
.WriteUInt16( ( nCount
<< 4 ) | 0xf ) // open an ESCHER_SolverContainer
4767 .WriteUInt16( ESCHER_SolverContainer
)
4770 nRecHdPos
= rStrm
.Tell() - 4;
4772 EscherConnectorRule aConnectorRule
;
4773 aConnectorRule
.nRuleId
= 2;
4774 for (EscherConnectorListEntry
* pPtr
: maConnectorList
)
4776 aConnectorRule
.ncptiA
= aConnectorRule
.ncptiB
= 0xffffffff;
4777 aConnectorRule
.nShapeC
= GetShapeId( pPtr
->mXConnector
);
4778 aConnectorRule
.nShapeA
= GetShapeId( pPtr
->mXConnectToA
);
4779 aConnectorRule
.nShapeB
= GetShapeId( pPtr
->mXConnectToB
);
4781 if ( aConnectorRule
.nShapeC
)
4783 if ( aConnectorRule
.nShapeA
)
4784 aConnectorRule
.ncptiA
= pPtr
->GetConnectorRule( true );
4785 if ( aConnectorRule
.nShapeB
)
4786 aConnectorRule
.ncptiB
= pPtr
->GetConnectorRule( false );
4788 rStrm
.WriteUInt32( ( ESCHER_ConnectorRule
<< 16 ) | 1 ) // atom hd
4790 .WriteUInt32( aConnectorRule
.nRuleId
)
4791 .WriteUInt32( aConnectorRule
.nShapeA
)
4792 .WriteUInt32( aConnectorRule
.nShapeB
)
4793 .WriteUInt32( aConnectorRule
.nShapeC
)
4794 .WriteUInt32( aConnectorRule
.ncptiA
)
4795 .WriteUInt32( aConnectorRule
.ncptiB
);
4797 aConnectorRule
.nRuleId
+= 2;
4800 nCurrentPos
= rStrm
.Tell(); // close the ESCHER_SolverContainer
4801 nSize
= ( nCurrentPos
- nRecHdPos
) - 4;
4802 rStrm
.Seek( nRecHdPos
);
4803 rStrm
.WriteUInt32( nSize
);
4804 rStrm
.Seek( nCurrentPos
);
4808 EscherExGlobal::EscherExGlobal( sal_uInt32 nGraphicProvFlags
) :
4809 EscherGraphicProvider( nGraphicProvFlags
),
4810 mpPicStrm( nullptr ),
4811 mbHasDggCont( false ),
4812 mbPicStrmQueried( false )
4816 EscherExGlobal::~EscherExGlobal()
4820 sal_uInt32
EscherExGlobal::GenerateDrawingId()
4822 // new drawing starts a new cluster in the cluster table (cluster identifiers are one-based)
4823 sal_uInt32 nClusterId
= static_cast< sal_uInt32
>( maClusterTable
.size() + 1 );
4824 // drawing identifiers are one-based
4825 sal_uInt32 nDrawingId
= static_cast< sal_uInt32
>( maDrawingInfos
.size() + 1 );
4826 // prepare new entries in the tables
4827 maClusterTable
.push_back( ClusterEntry( nDrawingId
) );
4828 maDrawingInfos
.push_back( DrawingInfo( nClusterId
) );
4829 // return the new drawing identifier
4833 sal_uInt32
EscherExGlobal::GenerateShapeId( sal_uInt32 nDrawingId
, bool bIsInSpgr
)
4835 // drawing identifier is one-based
4836 // make sure the drawing is valid (bnc#656503)
4837 if ( nDrawingId
== 0 )
4839 // create index from the identifier
4840 size_t nDrawingIdx
= nDrawingId
- 1;
4841 OSL_ENSURE( nDrawingIdx
< maDrawingInfos
.size(), "EscherExGlobal::GenerateShapeId - invalid drawing ID" );
4842 if( nDrawingIdx
>= maDrawingInfos
.size() )
4844 DrawingInfo
& rDrawingInfo
= maDrawingInfos
[ nDrawingIdx
];
4846 // cluster identifier in drawing info struct is one-based
4847 ClusterEntry
* pClusterEntry
= &maClusterTable
[ rDrawingInfo
.mnClusterId
- 1 ];
4849 // check cluster overflow, create new cluster entry
4850 if( pClusterEntry
->mnNextShapeId
== DFF_DGG_CLUSTER_SIZE
)
4852 // start a new cluster in the cluster table
4853 maClusterTable
.push_back( ClusterEntry( nDrawingId
) );
4854 pClusterEntry
= &maClusterTable
.back();
4855 // new size of maClusterTable is equal to one-based identifier of the new cluster
4856 rDrawingInfo
.mnClusterId
= static_cast< sal_uInt32
>( maClusterTable
.size() );
4859 // build shape identifier from cluster identifier and next free cluster shape identifier
4860 rDrawingInfo
.mnLastShapeId
= static_cast< sal_uInt32
>( rDrawingInfo
.mnClusterId
* DFF_DGG_CLUSTER_SIZE
+ pClusterEntry
->mnNextShapeId
);
4861 // update free shape identifier in cluster entry
4862 ++pClusterEntry
->mnNextShapeId
;
4863 /* Old code has counted the shapes only, if we are in a SPGRCONTAINER. Is
4864 this really intended? Maybe it's always true... */
4866 ++rDrawingInfo
.mnShapeCount
;
4868 // return the new shape identifier
4869 return rDrawingInfo
.mnLastShapeId
;
4872 sal_uInt32
EscherExGlobal::GetDrawingShapeCount( sal_uInt32 nDrawingId
) const
4874 size_t nDrawingIdx
= nDrawingId
- 1;
4875 OSL_ENSURE( nDrawingIdx
< maDrawingInfos
.size(), "EscherExGlobal::GetDrawingShapeCount - invalid drawing ID" );
4876 return (nDrawingIdx
< maDrawingInfos
.size()) ? maDrawingInfos
[ nDrawingIdx
].mnShapeCount
: 0;
4879 sal_uInt32
EscherExGlobal::GetLastShapeId( sal_uInt32 nDrawingId
) const
4881 size_t nDrawingIdx
= nDrawingId
- 1;
4882 OSL_ENSURE( nDrawingIdx
< maDrawingInfos
.size(), "EscherExGlobal::GetLastShapeId - invalid drawing ID" );
4883 return (nDrawingIdx
< maDrawingInfos
.size()) ? maDrawingInfos
[ nDrawingIdx
].mnLastShapeId
: 0;
4886 sal_uInt32
EscherExGlobal::GetDggAtomSize() const
4888 // 8 bytes header, 16 bytes fixed DGG data, 8 bytes for each cluster
4889 return static_cast< sal_uInt32
>( 24 + 8 * maClusterTable
.size() );
4892 void EscherExGlobal::WriteDggAtom( SvStream
& rStrm
) const
4894 sal_uInt32 nDggSize
= GetDggAtomSize();
4896 // write the DGG record header (do not include the 8 bytes of the header in the data size)
4897 rStrm
.WriteUInt32( ESCHER_Dgg
<< 16 ).WriteUInt32( nDggSize
- 8 );
4899 // calculate and write the fixed DGG data
4900 sal_uInt32 nShapeCount
= 0;
4901 sal_uInt32 nLastShapeId
= 0;
4902 for( DrawingInfoVector::const_iterator aIt
= maDrawingInfos
.begin(), aEnd
= maDrawingInfos
.end(); aIt
!= aEnd
; ++aIt
)
4904 nShapeCount
+= aIt
->mnShapeCount
;
4905 nLastShapeId
= ::std::max( nLastShapeId
, aIt
->mnLastShapeId
);
4907 // the non-existing cluster with index #0 is counted too
4908 sal_uInt32 nClusterCount
= static_cast< sal_uInt32
>( maClusterTable
.size() + 1 );
4909 sal_uInt32 nDrawingCount
= static_cast< sal_uInt32
>( maDrawingInfos
.size() );
4910 rStrm
.WriteUInt32( nLastShapeId
).WriteUInt32( nClusterCount
).WriteUInt32( nShapeCount
).WriteUInt32( nDrawingCount
);
4912 // write the cluster table
4913 for( ClusterTable::const_iterator aIt
= maClusterTable
.begin(), aEnd
= maClusterTable
.end(); aIt
!= aEnd
; ++aIt
)
4914 rStrm
.WriteUInt32( aIt
->mnDrawingId
).WriteUInt32( aIt
->mnNextShapeId
);
4917 SvStream
* EscherExGlobal::QueryPictureStream()
4919 if( !mbPicStrmQueried
)
4921 mpPicStrm
= ImplQueryPictureStream();
4922 mbPicStrmQueried
= true;
4927 SvStream
* EscherExGlobal::ImplQueryPictureStream()
4932 // Implementation of an empty stream that silently succeeds, but does nothing.
4934 // In fact, this is a hack. The right solution is to abstract EscherEx to be
4935 // able to work without SvStream; but at the moment it is better to live with
4937 class SvNullStream
: public SvStream
4940 virtual std::size_t GetData( void* pData
, std::size_t nSize
) override
{ memset( pData
, 0, nSize
); return nSize
; }
4941 virtual std::size_t PutData( const void*, std::size_t nSize
) override
{ return nSize
; }
4942 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
{ return nPos
; }
4943 virtual void SetSize( sal_uInt64
) override
{}
4944 virtual void FlushData() override
{}
4947 SvNullStream() : SvStream() {}
4948 virtual ~SvNullStream() override
{}
4951 EscherEx::EscherEx(const std::shared_ptr
<EscherExGlobal
>& rxGlobal
, SvStream
* pOutStrm
, bool bOOXML
)
4952 : mxGlobal(rxGlobal
)
4953 , mpOutStrm(pOutStrm
)
4958 , mnHellLayerId(USHRT_MAX
)
4959 , mbEscherSpgr(false)
4965 mpOutStrm
= new SvNullStream();
4968 mnStrmStartOfs
= mpOutStrm
->Tell();
4969 mpImplEESdrWriter
.reset( new ImplEESdrWriter( *this ) );
4972 EscherEx::~EscherEx()
4978 void EscherEx::Flush( SvStream
* pPicStreamMergeBSE
/* = NULL */ )
4980 if ( mxGlobal
->HasDggContainer() )
4982 // store the current stream position at ESCHER_Persist_CurrentPosition key
4983 PtReplaceOrInsert( ESCHER_Persist_CurrentPosition
, mpOutStrm
->Tell() );
4984 if ( DoSeek( ESCHER_Persist_Dgg
) )
4986 /* The DGG record is still not written. ESCHER_Persist_Dgg seeks
4987 to the place where the complete record has to be inserted. */
4988 InsertAtCurrentPos( mxGlobal
->GetDggAtomSize() );
4989 mxGlobal
->WriteDggAtom( *mpOutStrm
);
4991 if ( mxGlobal
->HasGraphics() )
4993 /* Calculate the total size of the BSTORECONTAINER including
4994 all BSE records containing the picture data contained in
4995 the passed in pPicStreamMergeBSE. */
4996 sal_uInt32 nBSCSize
= mxGlobal
->GetBlibStoreContainerSize( pPicStreamMergeBSE
);
4999 InsertAtCurrentPos( nBSCSize
);
5000 mxGlobal
->WriteBlibStoreContainer( *mpOutStrm
, pPicStreamMergeBSE
);
5004 /* Forget the stream position stored for the DGG which is invalid
5005 after the call to InsertAtCurrentPos() anyway. */
5006 PtDelete( ESCHER_Persist_Dgg
);
5008 // seek to initial position (may be different due to inserted DGG and BLIPs)
5009 mpOutStrm
->Seek( PtGetOffsetByID( ESCHER_Persist_CurrentPosition
) );
5013 void EscherEx::InsertAtCurrentPos( sal_uInt32 nBytes
)
5015 sal_uInt32 nSize
, nType
, nSource
, nBufSize
, nToCopy
, nCurPos
= mpOutStrm
->Tell();
5017 // adjust persist table
5018 for(EscherPersistEntry
* pPtr
: maPersistTable
) {
5019 sal_uInt32 nOfs
= pPtr
->mnOffset
;
5020 if ( nOfs
>= nCurPos
) {
5021 pPtr
->mnOffset
+= nBytes
;
5025 // adapt container and atom sizes
5026 mpOutStrm
->Seek( mnStrmStartOfs
);
5027 while ( mpOutStrm
->Tell() < nCurPos
)
5029 mpOutStrm
->ReadUInt32( nType
).ReadUInt32( nSize
);
5030 sal_uInt32 nEndOfRecord
= mpOutStrm
->Tell() + nSize
;
5031 bool bContainer
= (nType
& 0x0F) == 0x0F;
5032 /* Expand the record, if the insertion position is inside, or if the
5033 position is at the end of a container (expands always), or at the
5034 end of an atom and bExpandEndOfAtom is set. */
5035 if ( (nCurPos
< nEndOfRecord
) || ((nCurPos
== nEndOfRecord
) && bContainer
) )
5037 mpOutStrm
->SeekRel( -4 );
5038 mpOutStrm
->WriteUInt32( nSize
+ nBytes
);
5040 mpOutStrm
->SeekRel( nSize
);
5043 mpOutStrm
->SeekRel( nSize
);
5045 for (std::vector
< sal_uInt32
>::iterator
aIter( mOffsets
.begin() ), aEnd( mOffsets
.end() ); aIter
!= aEnd
; ++aIter
)
5047 if ( *aIter
> nCurPos
)
5050 mpOutStrm
->Seek( STREAM_SEEK_TO_END
);
5051 nSource
= mpOutStrm
->Tell();
5052 nToCopy
= nSource
- nCurPos
; // increase the size of the tream by nBytes
5053 std::unique_ptr
<sal_uInt8
[]> pBuf(new sal_uInt8
[ 0x40000 ]); // 256KB Buffer
5056 nBufSize
= ( nToCopy
>= 0x40000 ) ? 0x40000 : nToCopy
;
5057 nToCopy
-= nBufSize
;
5058 nSource
-= nBufSize
;
5059 mpOutStrm
->Seek( nSource
);
5060 mpOutStrm
->ReadBytes(pBuf
.get(), nBufSize
);
5061 mpOutStrm
->Seek( nSource
+ nBytes
);
5062 mpOutStrm
->WriteBytes(pBuf
.get(), nBufSize
);
5064 mpOutStrm
->Seek( nCurPos
);
5067 void EscherEx::InsertPersistOffset( sal_uInt32 nKey
, sal_uInt32 nOffset
)
5069 PtInsert( ESCHER_Persist_PrivateEntry
| nKey
, nOffset
);
5072 void EscherEx::ReplacePersistOffset( sal_uInt32 nKey
, sal_uInt32 nOffset
)
5074 PtReplace( ESCHER_Persist_PrivateEntry
| nKey
, nOffset
);
5077 void EscherEx::SetEditAs( const OUString
& rEditAs
)
5082 sal_uInt32
EscherEx::GetPersistOffset( sal_uInt32 nKey
)
5084 return PtGetOffsetByID( ESCHER_Persist_PrivateEntry
| nKey
);
5087 bool EscherEx::DoSeek( sal_uInt32 nKey
)
5089 sal_uInt32 nPos
= PtGetOffsetByID( nKey
);
5091 mpOutStrm
->Seek( nPos
);
5094 if (! PtIsID( nKey
) )
5096 mpOutStrm
->Seek( 0 );
5101 bool EscherEx::SeekToPersistOffset( sal_uInt32 nKey
)
5103 return DoSeek( ESCHER_Persist_PrivateEntry
| nKey
);
5106 void EscherEx::InsertAtPersistOffset( sal_uInt32 nKey
, sal_uInt32 nValue
)
5108 sal_uInt32 nOldPos
= mpOutStrm
->Tell();
5109 bool bRetValue
= SeekToPersistOffset( nKey
);
5112 mpOutStrm
->WriteUInt32( nValue
);
5113 mpOutStrm
->Seek( nOldPos
);
5117 void EscherEx::OpenContainer( sal_uInt16 nEscherContainer
, int nRecInstance
)
5119 mpOutStrm
->WriteUInt16( ( nRecInstance
<< 4 ) | 0xf ).WriteUInt16( nEscherContainer
).WriteUInt32( 0 );
5120 mOffsets
.push_back( mpOutStrm
->Tell() - 4 );
5121 mRecTypes
.push_back( nEscherContainer
);
5122 switch( nEscherContainer
)
5124 case ESCHER_DggContainer
:
5126 mxGlobal
->SetDggContainer();
5128 /* Remember the current position as start position of the DGG
5129 record and BSTORECONTAINER, but do not write them actually.
5130 This will be done later in Flush() when the number of drawings,
5131 the size and contents of the FIDCL cluster table, and the size
5132 of the BLIP container are known. */
5133 PtReplaceOrInsert( ESCHER_Persist_Dgg
, mpOutStrm
->Tell() );
5137 case ESCHER_DgContainer
:
5139 if ( mxGlobal
->HasDggContainer() )
5144 mnCurrentDg
= mxGlobal
->GenerateDrawingId();
5145 AddAtom( 8, ESCHER_Dg
, 0, mnCurrentDg
);
5146 PtReplaceOrInsert( ESCHER_Persist_Dg
| mnCurrentDg
, mpOutStrm
->Tell() );
5147 mpOutStrm
->WriteUInt32( 0 ) // The number of shapes in this drawing
5148 .WriteUInt32( 0 ); // The last MSOSPID given to an SP in this DG
5154 case ESCHER_SpgrContainer
:
5158 mbEscherSpgr
= true;
5163 case ESCHER_SpContainer
:
5173 void EscherEx::CloseContainer()
5175 sal_uInt32 nSize
, nPos
= mpOutStrm
->Tell();
5176 nSize
= ( nPos
- mOffsets
.back() ) - 4;
5177 mpOutStrm
->Seek( mOffsets
.back() );
5178 mpOutStrm
->WriteUInt32( nSize
);
5180 switch( mRecTypes
.back() )
5182 case ESCHER_DgContainer
:
5187 if ( DoSeek( ESCHER_Persist_Dg
| mnCurrentDg
) )
5188 mpOutStrm
->WriteUInt32( mxGlobal
->GetDrawingShapeCount( mnCurrentDg
) ).WriteUInt32( mxGlobal
->GetLastShapeId( mnCurrentDg
) );
5193 case ESCHER_SpgrContainer
:
5197 mbEscherSpgr
= false;
5206 mOffsets
.pop_back();
5207 mRecTypes
.pop_back();
5208 mpOutStrm
->Seek( nPos
);
5211 void EscherEx::BeginAtom()
5213 mnCountOfs
= mpOutStrm
->Tell();
5214 mpOutStrm
->WriteUInt32( 0 ).WriteUInt32( 0 ); // record header wird spaeter geschrieben
5217 void EscherEx::EndAtom( sal_uInt16 nRecType
, int nRecVersion
, int nRecInstance
)
5219 sal_uInt32 nOldPos
= mpOutStrm
->Tell();
5220 mpOutStrm
->Seek( mnCountOfs
);
5221 sal_uInt32 nSize
= nOldPos
- mnCountOfs
;
5222 mpOutStrm
->WriteUInt16( ( nRecInstance
<< 4 ) | ( nRecVersion
& 0xf ) ).WriteUInt16( nRecType
).WriteUInt32( nSize
- 8 );
5223 mpOutStrm
->Seek( nOldPos
);
5226 void EscherEx::AddAtom( sal_uInt32 nAtomSize
, sal_uInt16 nRecType
, int nRecVersion
, int nRecInstance
)
5228 mpOutStrm
->WriteUInt16( ( nRecInstance
<< 4 ) | ( nRecVersion
& 0xf ) ).WriteUInt16( nRecType
).WriteUInt32( nAtomSize
);
5231 void EscherEx::AddChildAnchor( const Rectangle
& rRect
)
5233 AddAtom( 16, ESCHER_ChildAnchor
);
5234 mpOutStrm
->WriteInt32( rRect
.Left() )
5235 .WriteInt32( rRect
.Top() )
5236 .WriteInt32( rRect
.Right() )
5237 .WriteInt32( rRect
.Bottom() );
5240 void EscherEx::AddClientAnchor( const Rectangle
& rRect
)
5242 AddAtom( 8, ESCHER_ClientAnchor
);
5243 mpOutStrm
->WriteInt16( rRect
.Top() )
5244 .WriteInt16( rRect
.Left() )
5245 .WriteInt16( rRect
.GetWidth() + rRect
.Left() )
5246 .WriteInt16( rRect
.GetHeight() + rRect
.Top() );
5249 EscherExHostAppData
* EscherEx::EnterAdditionalTextGroup()
5254 sal_uInt32
EscherEx::EnterGroup( const OUString
& rShapeName
, const Rectangle
* pBoundRect
)
5258 aRect
= *pBoundRect
;
5260 OpenContainer( ESCHER_SpgrContainer
);
5261 OpenContainer( ESCHER_SpContainer
);
5262 AddAtom( 16, ESCHER_Spgr
, 1 );
5263 PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap
| mnGroupLevel
,
5264 mpOutStrm
->Tell() );
5265 mpOutStrm
->WriteInt32( aRect
.Left() ) // Bounding box for the grouped shapes to which they will be attached
5266 .WriteInt32( aRect
.Top() )
5267 .WriteInt32( aRect
.Right() )
5268 .WriteInt32( aRect
.Bottom() );
5270 sal_uInt32 nShapeId
= GenerateShapeId();
5271 if ( !mnGroupLevel
)
5272 AddShape( ESCHER_ShpInst_Min
, 5, nShapeId
); // Flags: Group | Patriarch
5275 AddShape( ESCHER_ShpInst_Min
, 0x201, nShapeId
); // Flags: Group | HaveAnchor
5276 EscherPropertyContainer aPropOpt
;
5277 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x00040004 );
5278 aPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistLeft
, 0 );
5279 aPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistRight
, 0 );
5281 // #i51348# shape name
5282 if( rShapeName
.getLength() > 0 )
5283 aPropOpt
.AddOpt( ESCHER_Prop_wzName
, rShapeName
);
5285 Commit( aPropOpt
, aRect
);
5286 if ( mnGroupLevel
> 1 )
5287 AddChildAnchor( aRect
);
5289 EscherExHostAppData
* pAppData
= mpImplEESdrWriter
->ImplGetHostData();
5292 if ( mnGroupLevel
<= 1 )
5293 pAppData
->WriteClientAnchor( *this, aRect
);
5294 pAppData
->WriteClientData( *this );
5297 CloseContainer(); // ESCHER_SpContainer
5302 sal_uInt32
EscherEx::EnterGroup( const Rectangle
* pBoundRect
)
5304 return EnterGroup( OUString(), pBoundRect
);
5307 void EscherEx::SetGroupSnapRect( sal_uInt32 nGroupLevel
, const Rectangle
& rRect
)
5311 sal_uInt32 nCurrentPos
= mpOutStrm
->Tell();
5312 if ( DoSeek( ESCHER_Persist_Grouping_Snap
| ( nGroupLevel
- 1 ) ) )
5314 mpOutStrm
->WriteInt32( rRect
.Left() ) // Bounding box for the grouped shapes to which they will be attached
5315 .WriteInt32( rRect
.Top() )
5316 .WriteInt32( rRect
.Right() )
5317 .WriteInt32( rRect
.Bottom() );
5318 mpOutStrm
->Seek( nCurrentPos
);
5323 void EscherEx::SetGroupLogicRect( sal_uInt32 nGroupLevel
, const Rectangle
& rRect
)
5327 sal_uInt32 nCurrentPos
= mpOutStrm
->Tell();
5328 if ( DoSeek( ESCHER_Persist_Grouping_Logic
| ( nGroupLevel
- 1 ) ) )
5330 mpOutStrm
->WriteInt16( rRect
.Top() ).WriteInt16( rRect
.Left() ).WriteInt16( rRect
.Right() ).WriteInt16( rRect
.Bottom() );
5331 mpOutStrm
->Seek( nCurrentPos
);
5336 void EscherEx::LeaveGroup()
5339 PtDelete( ESCHER_Persist_Grouping_Snap
| mnGroupLevel
);
5340 PtDelete( ESCHER_Persist_Grouping_Logic
| mnGroupLevel
);
5344 void EscherEx::AddShape( sal_uInt32 nShpInstance
, sal_uInt32 nFlags
, sal_uInt32 nShapeID
)
5346 AddAtom( 8, ESCHER_Sp
, 2, nShpInstance
);
5349 nShapeID
= GenerateShapeId();
5351 if ( nFlags
^ 1 ) // is this a group shape ?
5353 if ( mnGroupLevel
> 1 )
5354 nFlags
|= 2; // this not a topmost shape
5356 mpOutStrm
->WriteUInt32( nShapeID
).WriteUInt32( nFlags
);
5359 void EscherEx::Commit( EscherPropertyContainer
& rProps
, const Rectangle
& )
5361 rProps
.Commit( GetStream() );
5364 sal_uInt32
EscherEx::GetColor( const sal_uInt32 nSOColor
)
5366 sal_uInt32 nColor
= nSOColor
& 0xff00; // Green
5367 nColor
|= (sal_uInt8
)( nSOColor
) << 16; // Red
5368 nColor
|= (sal_uInt8
)( nSOColor
>> 16 ); // Blue
5372 sal_uInt32
EscherEx::GetColor( const Color
& rSOColor
, bool bSwap
)
5374 sal_uInt32 nColor
= ( rSOColor
.GetRed() << 16 );
5375 nColor
|= ( rSOColor
.GetGreen() << 8 );
5376 nColor
|= rSOColor
.GetBlue();
5379 nColor
= GetColor( nColor
);
5384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */