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 <o3tl/string_view.hxx>
23 #include <svx/svdxcgv.hxx>
24 #include <svx/svdomedia.hxx>
25 #include <svx/xflftrit.hxx>
26 #include <filter/msfilter/escherex.hxx>
27 #include <filter/msfilter/util.hxx>
28 #include <svx/unoapi.hxx>
29 #include <svx/svdobj.hxx>
30 #include <svx/svdoashp.hxx>
31 #include <svx/svdoole2.hxx>
32 #include <svx/sdtfsitm.hxx>
33 #include <editeng/outlobj.hxx>
35 #include <vcl/graph.hxx>
36 #include <vcl/cvtgrf.hxx>
37 #include <vcl/svapp.hxx>
38 #include <tools/debug.hxx>
39 #include <tools/stream.hxx>
40 #include <tools/zcodec.hxx>
41 #include <tools/urlobj.hxx>
42 #include <svx/svdopath.hxx>
44 #include <vcl/graphicfilter.hxx>
45 #include <svx/EnhancedCustomShapeTypeNames.hxx>
46 #include <svx/EnhancedCustomShapeGeometry.hxx>
47 #include <svx/EnhancedCustomShapeFunctionParser.hxx>
48 #include <svx/EnhancedCustomShape2d.hxx>
49 #include <com/sun/star/beans/PropertyValues.hpp>
50 #include <com/sun/star/beans/XPropertySet.hpp>
51 #include <com/sun/star/beans/XPropertyState.hpp>
52 #include <com/sun/star/awt/GradientStyle.hpp>
53 #include <com/sun/star/awt/Gradient.hpp>
54 #include <com/sun/star/drawing/LineStyle.hpp>
55 #include <com/sun/star/drawing/LineJoint.hpp>
56 #include <com/sun/star/drawing/LineCap.hpp>
57 #include <com/sun/star/drawing/FillStyle.hpp>
58 #include <com/sun/star/drawing/LineDash.hpp>
59 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
60 #include <com/sun/star/drawing/ConnectorType.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/FontSlant.hpp>
81 #include <com/sun/star/awt/FontWeight.hpp>
82 #include <com/sun/star/drawing/ColorMode.hpp>
83 #include <com/sun/star/drawing/Position3D.hpp>
84 #include <com/sun/star/drawing/Direction3D.hpp>
85 #include <com/sun/star/drawing/Hatch.hpp>
86 #include <com/sun/star/graphic/XGraphic.hpp>
87 #include <com/sun/star/text/GraphicCrop.hpp>
88 #include <unotools/ucbstreamhelper.hxx>
89 #include <comphelper/string.hxx>
90 #include <vcl/virdev.hxx>
92 #include <rtl/strbuf.hxx>
93 #include <sal/log.hxx>
94 #include <basegfx/polygon/b2dpolypolygontools.hxx>
95 #include <basegfx/polygon/b2dpolygontools.hxx>
96 #include <basegfx/numeric/ftools.hxx>
97 #include <osl/diagnose.h>
104 EscherExContainer::EscherExContainer( SvStream
& rSt
, const sal_uInt16 nRecType
, const sal_uInt16 nInstance
) :
107 rStrm
.WriteUInt32( ( 0xf | ( nInstance
<< 4 ) ) | ( nRecType
<< 16 ) ).WriteUInt32( 0 );
108 nContPos
= rStrm
.Tell();
110 EscherExContainer::~EscherExContainer()
112 sal_uInt64 nPos
= rStrm
.Tell();
113 sal_uInt32 nSize
= nPos
- nContPos
;
116 rStrm
.Seek( nContPos
- 4 );
117 rStrm
.WriteUInt32( nSize
);
122 EscherExAtom::EscherExAtom( SvStream
& rSt
, const sal_uInt16 nRecType
, const sal_uInt16 nInstance
, const sal_uInt8 nVersion
) :
125 rStrm
.WriteUInt32( ( nVersion
| ( nInstance
<< 4 ) ) | ( nRecType
<< 16 ) ).WriteUInt32( 0 );
126 nContPos
= rStrm
.Tell();
128 EscherExAtom::~EscherExAtom()
130 sal_uInt64 nPos
= rStrm
.Tell();
131 sal_uInt32 nSize
= nPos
- nContPos
;
134 rStrm
.Seek( nContPos
- 4 );
135 rStrm
.WriteUInt32( nSize
);
140 EscherExClientRecord_Base::~EscherExClientRecord_Base()
144 EscherExClientAnchor_Base::~EscherExClientAnchor_Base()
148 EscherPropertyContainer::EscherPropertyContainer(
149 EscherGraphicProvider
* pGraphProv
, SvStream
* pPiOutStrm
,
150 tools::Rectangle
* pBoundRect
):
151 pGraphicProvider(pGraphProv
),
152 pPicOutStrm(pPiOutStrm
),
153 pShapeBoundRect(pBoundRect
),
156 bHasComplexData(false)
158 pSortStruct
.reserve(64);
161 EscherPropertyContainer::EscherPropertyContainer()
162 : EscherPropertyContainer(nullptr, nullptr, nullptr)
165 EscherPropertyContainer::EscherPropertyContainer(
166 EscherGraphicProvider
& rGraphProv
,
167 SvStream
* pPiOutStrm
,
168 tools::Rectangle
& rBoundRect
) :
169 EscherPropertyContainer(&rGraphProv
, pPiOutStrm
, &rBoundRect
)
172 EscherPropertyContainer::~EscherPropertyContainer()
176 void EscherPropertyContainer::AddOpt(
179 sal_uInt32 nSizeReduction
,
180 SvMemoryStream
& rStream
)
182 sal_uInt8
const* pBuf(static_cast<sal_uInt8
const *>(rStream
.GetData()));
183 const sal_uInt64
nSize(rStream
.GetSize());
184 std::vector
<sal_uInt8
> aBuf
;
187 for(sal_uInt64
a(0); a
< nSize
; a
++)
189 aBuf
.push_back(*pBuf
++);
192 sal_uInt32
nPropValue(static_cast<sal_uInt32
>(nSize
));
194 if(0 != nSizeReduction
&& nPropValue
> nSizeReduction
)
196 nPropValue
-= nSizeReduction
;
199 AddOpt(nPropID
, bBlib
, nPropValue
, aBuf
);
202 void EscherPropertyContainer::AddOpt(
204 sal_uInt32 nPropValue
,
207 AddOpt(nPropID
, bBlib
, nPropValue
, std::vector
<sal_uInt8
>());
210 void EscherPropertyContainer::AddOpt(
212 std::u16string_view rString
)
214 std::vector
<sal_uInt8
> aBuf
;
215 aBuf
.reserve(rString
.size() * 2 + 2);
217 for(const sal_Unicode nUnicode
: rString
)
219 aBuf
.push_back(static_cast<sal_uInt8
>(nUnicode
));
220 aBuf
.push_back(static_cast<sal_uInt8
>(nUnicode
>> 8));
226 AddOpt(nPropID
, true, aBuf
.size(), aBuf
);
229 void EscherPropertyContainer::AddOpt(
232 sal_uInt32 nPropValue
,
233 const std::vector
<sal_uInt8
>& rProp
)
235 if ( bBlib
) // bBlib is only valid when fComplex = 0
237 if ( !rProp
.empty() )
238 nPropID
|= 0x8000; // fComplex = sal_True;
240 for( size_t i
= 0; i
< pSortStruct
.size(); i
++ )
242 if ( ( pSortStruct
[ i
].nPropId
&~0xc000 ) == ( nPropID
&~0xc000 ) ) // check, whether the Property only gets replaced
244 pSortStruct
[ i
].nPropId
= nPropID
;
245 if ( !pSortStruct
[ i
].nProp
.empty() )
247 nCountSize
-= pSortStruct
[ i
].nProp
.size();
249 pSortStruct
[ i
].nProp
= rProp
;
250 pSortStruct
[ i
].nPropValue
= nPropValue
;
251 if ( !rProp
.empty() )
252 nCountSize
+= rProp
.size();
258 pSortStruct
.emplace_back();
259 pSortStruct
.back().nPropId
= nPropID
; // insert property
260 pSortStruct
.back().nProp
= rProp
;
261 pSortStruct
.back().nPropValue
= nPropValue
;
263 if ( !rProp
.empty() )
265 nCountSize
+= rProp
.size();
266 bHasComplexData
= true;
270 bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId
, sal_uInt32
& rPropValue
) const
272 EscherPropSortStruct aPropStruct
;
274 if ( GetOpt( nPropId
, aPropStruct
) )
276 rPropValue
= aPropStruct
.nPropValue
;
282 bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId
, EscherPropSortStruct
& rPropValue
) const
284 for( size_t i
= 0; i
< pSortStruct
.size(); i
++ )
286 if ( ( pSortStruct
[ i
].nPropId
&~0xc000 ) == ( nPropId
&~0xc000 ) )
288 rPropValue
= pSortStruct
[ i
];
295 const EscherProperties
& EscherPropertyContainer::GetOpts() const
302 static int EscherPropSortFunc( const void* p1
, const void* p2
)
304 sal_Int16 nID1
= static_cast<EscherPropSortStruct
const *>(p1
)->nPropId
&~0xc000;
305 sal_Int16 nID2
= static_cast<EscherPropSortStruct
const *>(p2
)->nPropId
&~0xc000;
309 else if( nID1
> nID2
)
317 void EscherPropertyContainer::Commit( SvStream
& rSt
, sal_uInt16 nVersion
, sal_uInt16 nRecType
)
319 rSt
.WriteUInt16( ( nCountCount
<< 4 ) | ( nVersion
& 0xf ) ).WriteUInt16( nRecType
).WriteUInt32( nCountSize
);
320 if ( pSortStruct
.empty() )
323 qsort( pSortStruct
.data(), pSortStruct
.size(), sizeof( EscherPropSortStruct
), EscherPropSortFunc
);
325 for ( size_t i
= 0; i
< pSortStruct
.size(); i
++ )
327 sal_uInt32 nPropValue
= pSortStruct
[ i
].nPropValue
;
328 sal_uInt16 nPropId
= pSortStruct
[ i
].nPropId
;
330 rSt
.WriteUInt16( nPropId
)
331 .WriteUInt32( nPropValue
);
333 if ( bHasComplexData
)
335 for ( size_t i
= 0; i
< pSortStruct
.size(); i
++ )
337 if ( !pSortStruct
[ i
].nProp
.empty() )
339 pSortStruct
[i
].nProp
.data(),
340 pSortStruct
[i
].nProp
.size());
345 bool EscherPropertyContainer::IsFontWork() const
347 sal_uInt32 nTextPathFlags
= 0;
348 GetOpt( DFF_Prop_gtextFStrikethrough
, nTextPathFlags
);
349 return ( nTextPathFlags
& 0x4000 ) != 0;
352 sal_uInt32
EscherPropertyContainer::ImplGetColor( const sal_uInt32 nSOColor
, bool bSwap
)
356 sal_uInt32 nColor
= nSOColor
& 0xff00; // green
357 nColor
|= static_cast<sal_uInt8
>(nSOColor
) << 16; // red
358 nColor
|= static_cast<sal_uInt8
>( nSOColor
>> 16 ); // blue
362 return nSOColor
& 0xffffff;
365 sal_uInt32
EscherPropertyContainer::GetGradientColor(
366 const awt::Gradient
* pGradient
,
367 sal_uInt32 nStartColor
)
369 sal_uInt32 nIntensity
= 100;
374 if ( nStartColor
& 1 )
376 nIntensity
= pGradient
->StartIntensity
;
377 aColor
= Color(ColorTransparency
, pGradient
->StartColor
);
381 nIntensity
= pGradient
->EndIntensity
;
382 aColor
= Color(ColorTransparency
, pGradient
->EndColor
);
385 sal_uInt32 nRed
= ( aColor
.GetRed() * nIntensity
) / 100;
386 sal_uInt32 nGreen
= ( ( aColor
.GetGreen() * nIntensity
) / 100 ) << 8;
387 sal_uInt32 nBlue
= ( ( aColor
.GetBlue() * nIntensity
) / 100 ) << 16;
388 return nRed
| nGreen
| nBlue
;
391 void EscherPropertyContainer::CreateGradientProperties(
392 const awt::Gradient
& rGradient
)
394 sal_uInt32 nFillType
= ESCHER_FillShadeScale
;
395 sal_uInt32 nAngle
= 0;
396 sal_uInt32 nFillFocus
= 0;
397 sal_uInt32 nFillLR
= 0;
398 sal_uInt32 nFillTB
= 0;
399 sal_uInt32 nFirstColor
= 0;
400 bool bWriteFillTo
= false;
402 switch ( rGradient
.Style
)
404 case awt::GradientStyle_LINEAR
:
405 case awt::GradientStyle_AXIAL
:
407 nFillType
= ESCHER_FillShadeScale
;
408 nAngle
= (rGradient
.Angle
* 0x10000) / 10;
409 nFillFocus
= (sal::static_int_cast
<int>(rGradient
.Style
) ==
410 sal::static_int_cast
<int>(css::awt::GradientStyle_LINEAR
)) ? 0 : 50;
413 case awt::GradientStyle_RADIAL
:
414 case awt::GradientStyle_ELLIPTICAL
:
415 case awt::GradientStyle_SQUARE
:
416 case awt::GradientStyle_RECT
:
418 nFillLR
= (rGradient
.XOffset
* 0x10000) / 100;
419 nFillTB
= (rGradient
.YOffset
* 0x10000) / 100;
420 if ( ((nFillLR
> 0) && (nFillLR
< 0x10000)) || ((nFillTB
> 0) && (nFillTB
< 0x10000)) )
421 nFillType
= ESCHER_FillShadeShape
;
423 nFillType
= ESCHER_FillShadeCenter
;
428 case awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE
: break;
430 AddOpt( ESCHER_Prop_fillType
, nFillType
);
431 AddOpt( ESCHER_Prop_fillAngle
, nAngle
);
432 AddOpt( ESCHER_Prop_fillColor
, GetGradientColor( &rGradient
, nFirstColor
) );
433 AddOpt( ESCHER_Prop_fillBackColor
, GetGradientColor( &rGradient
, nFirstColor
^ 1 ) );
434 AddOpt( ESCHER_Prop_fillFocus
, nFillFocus
);
437 AddOpt( ESCHER_Prop_fillToLeft
, nFillLR
);
438 AddOpt( ESCHER_Prop_fillToTop
, nFillTB
);
439 AddOpt( ESCHER_Prop_fillToRight
, nFillLR
);
440 AddOpt( ESCHER_Prop_fillToBottom
, nFillTB
);
444 void EscherPropertyContainer::CreateGradientProperties(
445 const uno::Reference
<beans::XPropertySet
> & rXPropSet
, bool bTransparentGradient
)
448 awt::Gradient
const * pGradient
= nullptr;
450 sal_uInt32 nFillType
= ESCHER_FillShadeScale
;
451 sal_Int32 nAngle
= 0;
452 sal_uInt32 nFillFocus
= 0;
453 sal_uInt32 nFillLR
= 0;
454 sal_uInt32 nFillTB
= 0;
455 sal_uInt32 nFirstColor
= 0;// like the control var nChgColors in import logic
456 bool bWriteFillTo
= false;
458 // Transparency gradient: Means the third setting in transparency page is set
459 if (bTransparentGradient
&& EscherPropertyValueHelper::GetPropertyValue(
460 aAny
, rXPropSet
, u
"FillTransparenceGradient"_ustr
) )
462 pGradient
= o3tl::doAccess
<awt::Gradient
>(aAny
);
465 if ( EscherPropertyValueHelper::GetPropertyValue(
466 aAnyTemp
, rXPropSet
, u
"FillStyle"_ustr
) )
468 drawing::FillStyle eFS
;
469 if ( ! ( aAnyTemp
>>= eFS
) )
470 eFS
= drawing::FillStyle_SOLID
;
471 // solid and transparency
472 if ( eFS
== drawing::FillStyle_SOLID
)
474 if ( EscherPropertyValueHelper::GetPropertyValue(
475 aAnyTemp
, rXPropSet
, u
"FillColor"_ustr
) )
477 const_cast<awt::Gradient
*>(pGradient
)->StartColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAnyTemp
), false );
478 const_cast<awt::Gradient
*>(pGradient
)->EndColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAnyTemp
), false );
481 // gradient and transparency.
482 else if( eFS
== drawing::FillStyle_GRADIENT
)
484 if ( EscherPropertyValueHelper::GetPropertyValue(
485 aAny
, rXPropSet
, u
"FillGradient"_ustr
) )
486 pGradient
= o3tl::doAccess
<awt::Gradient
>(aAny
);
491 // Not transparency gradient
492 else if ( EscherPropertyValueHelper::GetPropertyValue(
493 aAny
, rXPropSet
, u
"FillGradient"_ustr
) )
495 pGradient
= o3tl::doAccess
<awt::Gradient
>(aAny
);
500 switch ( pGradient
->Style
)
502 case awt::GradientStyle_LINEAR
:
503 case awt::GradientStyle_AXIAL
:
505 nFillType
= ESCHER_FillShadeScale
;
506 nAngle
= pGradient
->Angle
;
507 while ( nAngle
> 0 ) nAngle
-= 3600;
508 while ( nAngle
<= -3600 ) nAngle
+= 3600;
509 // Value of the real number = Integral + (Fractional / 65536.0)
510 nAngle
= ( nAngle
* 0x10000) / 10;
512 nFillFocus
= (pGradient
->Style
== awt::GradientStyle_LINEAR
) ?
513 ( pGradient
->XOffset
+ pGradient
->YOffset
)/2 : -50;
515 nFirstColor
=nFirstColor
^ 1;
517 nFirstColor
=nFirstColor
^ 1;
520 case awt::GradientStyle_RADIAL
:
521 case awt::GradientStyle_ELLIPTICAL
:
522 case awt::GradientStyle_SQUARE
:
523 case awt::GradientStyle_RECT
:
525 // according to the import logic and rect type fill** value
526 nFillLR
= (pGradient
->XOffset
* 0x10000) / 100;
527 nFillTB
= (pGradient
->YOffset
* 0x10000) / 100;
528 if ( ((nFillLR
> 0) && (nFillLR
< 0x10000)) || ((nFillTB
> 0) && (nFillTB
< 0x10000)) )
529 nFillType
= ESCHER_FillShadeShape
;
531 nFillType
= ESCHER_FillShadeCenter
;
540 AddOpt( ESCHER_Prop_fillType
, nFillType
);
541 AddOpt( ESCHER_Prop_fillAngle
, nAngle
);
542 AddOpt( ESCHER_Prop_fillColor
, GetGradientColor( pGradient
, nFirstColor
) );
543 AddOpt( ESCHER_Prop_fillBackColor
, GetGradientColor( pGradient
, nFirstColor
^ 1 ) );
544 AddOpt( ESCHER_Prop_fillFocus
, nFillFocus
);
547 // according to rect type fillTo** value
550 AddOpt( ESCHER_Prop_fillToLeft
, nFillLR
);
551 AddOpt( ESCHER_Prop_fillToRight
, nFillLR
);
555 AddOpt( ESCHER_Prop_fillToTop
, nFillTB
);
556 AddOpt( ESCHER_Prop_fillToBottom
, nFillTB
);
560 // Transparency gradient
561 if (bTransparentGradient
&& EscherPropertyValueHelper::GetPropertyValue(
562 aAny
, rXPropSet
, u
"FillTransparenceGradient"_ustr
) )
564 pGradient
= o3tl::doAccess
<awt::Gradient
>(aAny
);
567 sal_uInt32 nBlue
= GetGradientColor( pGradient
, nFirstColor
) >> 16;
568 AddOpt( ESCHER_Prop_fillOpacity
,( ( 100 - ( nBlue
* 100 / 255 ) ) << 16 ) / 100 );
569 nBlue
= GetGradientColor( pGradient
, nFirstColor
^ 1 ) >>16 ;
570 AddOpt( ESCHER_Prop_fillBackOpacity
,( ( 100 - ( nBlue
* 100 / 255 ) ) << 16 )/ 100 );
575 void EscherPropertyContainer::CreateFillProperties(
576 const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
577 bool bEdge
, const uno::Reference
<drawing::XShape
> & rXShape
)
581 SdrObject
* pObj
= SdrObject::getSdrObjectFromXShape(rXShape
);
584 const SfxItemSet
& aAttr( pObj
->GetMergedItemSet() );
585 // transparency with gradient. Means the third setting in transparency page is set
586 bool bTransparentGradient
= ( aAttr
.GetItemState( XATTR_FILLFLOATTRANSPARENCE
) == SfxItemState::SET
) &&
587 aAttr
.Get( XATTR_FILLFLOATTRANSPARENCE
).IsEnabled();
588 CreateFillProperties( rXPropSet
, bEdge
, bTransparentGradient
);
593 void EscherPropertyContainer::CreateFillProperties(
594 const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
595 bool bEdge
, bool bTransparentGradient
)
599 AddOpt( ESCHER_Prop_WrapText
, ESCHER_WrapNone
);
600 AddOpt( ESCHER_Prop_AnchorText
, ESCHER_AnchorMiddle
);
601 static constexpr OUString
aPropName( u
"FillStyle"_ustr
);
603 if ( EscherPropertyValueHelper::GetPropertyValue(
604 aAny
, rXPropSet
, aPropName
) )
606 drawing::FillStyle eFS
;
607 if ( ! ( aAny
>>= eFS
) )
608 eFS
= drawing::FillStyle_SOLID
;
609 sal_uInt32 nFillBackColor
= 0;
612 case drawing::FillStyle_GRADIENT
:
614 CreateGradientProperties( rXPropSet
, bTransparentGradient
);
615 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x140014 );
619 case drawing::FillStyle_BITMAP
:
621 CreateGraphicProperties(rXPropSet
, u
"FillBitmap"_ustr
, true);
622 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x140014 );
623 AddOpt( ESCHER_Prop_fillBackColor
, nFillBackColor
);
626 case drawing::FillStyle_HATCH
:
628 CreateGraphicProperties( rXPropSet
, u
"FillHatch"_ustr
, true );
631 case drawing::FillStyle_SOLID
:
634 if ( bTransparentGradient
)
635 CreateGradientProperties( rXPropSet
, bTransparentGradient
);
638 beans::PropertyState ePropState
= EscherPropertyValueHelper::GetPropertyState(
639 rXPropSet
, aPropName
);
640 if ( ePropState
== beans::PropertyState_DIRECT_VALUE
)
641 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillSolid
);
643 if ( EscherPropertyValueHelper::GetPropertyValue(
644 aAny
, rXPropSet
, u
"FillColor"_ustr
) )
646 sal_uInt32 nFillColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
) );
647 nFillBackColor
= nFillColor
^ 0xffffff;
648 AddOpt( ESCHER_Prop_fillColor
, nFillColor
);
650 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100010 );
651 AddOpt( ESCHER_Prop_fillBackColor
, nFillBackColor
);
655 case drawing::FillStyle_NONE
:
656 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100000 );
659 if ( eFS
!= drawing::FillStyle_NONE
)
661 sal_uInt16 nTransparency
= ( EscherPropertyValueHelper::GetPropertyValue(
662 aAny
, rXPropSet
, u
"FillTransparence"_ustr
, true ) )
663 ? *o3tl::doAccess
<sal_Int16
>(aAny
) : 0;
665 AddOpt( ESCHER_Prop_fillOpacity
, ( ( 100 - nTransparency
) << 16 ) / 100 );
668 CreateLineProperties( rXPropSet
, bEdge
);
671 void EscherPropertyContainer::CreateTextProperties(
672 const uno::Reference
< beans::XPropertySet
> & rXPropSet
, sal_uInt32 nTextId
,
673 const bool bIsCustomShape
, const bool bIsTextFrame
)
676 text::WritingMode
eWM( text::WritingMode_LR_TB
);
677 drawing::TextVerticalAdjust
eVA( drawing::TextVerticalAdjust_TOP
);
678 drawing::TextHorizontalAdjust
eHA( drawing::TextHorizontalAdjust_LEFT
);
680 sal_Int32
nLeft ( 0 );
681 sal_Int32
nTop ( 0 );
682 sal_Int32
nRight ( 0 );
683 sal_Int32
nBottom ( 0 );
685 // used with normal shapes:
686 bool bAutoGrowWidth ( false );
687 const bool bAutoGrowHeight ( false ); //#ii63936 not setting autogrowheight, because minframeheight would be ignored
688 // used with ashapes:
689 bool bWordWrap ( false );
690 bool bAutoGrowSize ( false );
692 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextWritingMode"_ustr
, true ) )
694 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextVerticalAdjust"_ustr
, true ) )
696 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextHorizontalAdjust"_ustr
, true ) )
698 if ( bIsCustomShape
)
700 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextWordWrap"_ustr
) )
702 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextAutoGrowHeight"_ustr
, true ) )
703 aAny
>>= bAutoGrowSize
;
705 else if ( bIsTextFrame
)
707 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextAutoGrowWidth"_ustr
, true ) )
708 aAny
>>= bAutoGrowWidth
;
710 // i63936 not setting autogrowheight, because otherwise
711 // the minframeheight of the text will be ignored
713 // if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", sal_True ) )
714 // aAny >>= bAutoGrowHeight;
716 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextLeftDistance"_ustr
) )
718 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextUpperDistance"_ustr
) )
720 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextRightDistance"_ustr
) )
722 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"TextLowerDistance"_ustr
) )
725 ESCHER_AnchorText eAnchor
= ESCHER_AnchorTop
;
726 ESCHER_WrapMode eWrapMode
= ESCHER_WrapSquare
;
727 sal_uInt32 nTextAttr
= 0x40004; // rotate text with shape
729 if ( eWM
== text::WritingMode_TB_RL
)
730 { // vertical writing
733 case drawing::TextHorizontalAdjust_LEFT
:
734 eAnchor
= ESCHER_AnchorBottom
;
736 case drawing::TextHorizontalAdjust_CENTER
:
737 eAnchor
= ESCHER_AnchorMiddle
;
740 case drawing::TextHorizontalAdjust_BLOCK
:
741 case drawing::TextHorizontalAdjust_RIGHT
:
742 eAnchor
= ESCHER_AnchorTop
;
745 if ( eVA
== drawing::TextVerticalAdjust_CENTER
)
749 case ESCHER_AnchorMiddle
:
750 eAnchor
= ESCHER_AnchorMiddleCentered
;
752 case ESCHER_AnchorBottom
:
753 eAnchor
= ESCHER_AnchorBottomCentered
;
756 case ESCHER_AnchorTop
:
757 eAnchor
= ESCHER_AnchorTopCentered
;
761 if ( bIsCustomShape
)
764 eWrapMode
= ESCHER_WrapSquare
;
766 eWrapMode
= ESCHER_WrapNone
;
768 nTextAttr
|= 0x20002;
772 if ( bAutoGrowHeight
)
773 eWrapMode
= ESCHER_WrapNone
;
774 if ( bAutoGrowWidth
)
775 nTextAttr
|= 0x20002;
778 AddOpt( ESCHER_Prop_txflTextFlow
, ESCHER_txflTtoBA
); // rotate text within shape by 90
781 { // normal from left to right
784 case drawing::TextVerticalAdjust_CENTER
:
785 eAnchor
= ESCHER_AnchorMiddle
;
788 case drawing::TextVerticalAdjust_BOTTOM
:
789 eAnchor
= ESCHER_AnchorBottom
;
793 case drawing::TextVerticalAdjust_TOP
:
794 eAnchor
= ESCHER_AnchorTop
;
797 if ( eHA
== drawing::TextHorizontalAdjust_CENTER
)
801 case ESCHER_AnchorMiddle
:
802 eAnchor
= ESCHER_AnchorMiddleCentered
;
804 case ESCHER_AnchorBottom
:
805 eAnchor
= ESCHER_AnchorBottomCentered
;
807 case ESCHER_AnchorTop
:
808 eAnchor
= ESCHER_AnchorTopCentered
;
813 if ( bIsCustomShape
)
816 eWrapMode
= ESCHER_WrapSquare
;
818 eWrapMode
= ESCHER_WrapNone
;
820 nTextAttr
|= 0x20002;
824 if ( bAutoGrowWidth
)
825 eWrapMode
= ESCHER_WrapNone
;
826 if ( bAutoGrowHeight
)
827 nTextAttr
|= 0x20002;
830 AddOpt( ESCHER_Prop_dxTextLeft
, nLeft
* 360 );
831 AddOpt( ESCHER_Prop_dxTextRight
, nRight
* 360 );
832 AddOpt( ESCHER_Prop_dyTextTop
, nTop
* 360 );
833 AddOpt( ESCHER_Prop_dyTextBottom
, nBottom
* 360 );
835 AddOpt( ESCHER_Prop_WrapText
, eWrapMode
);
836 AddOpt( ESCHER_Prop_AnchorText
, eAnchor
);
837 AddOpt( ESCHER_Prop_FitTextToShape
, nTextAttr
);
840 AddOpt( ESCHER_Prop_lTxid
, nTextId
);
842 // n#404221: In case of rotation we need to write the txtflTextFlow
844 // fdo#58204: not custom shapes (TODO: other cases when it doesn't work?)
845 if (!bIsTextFrame
|| bIsCustomShape
)
848 sal_uInt16 nAngle
= EscherPropertyValueHelper::GetPropertyValue(
849 aAny
, rXPropSet
, u
"RotateAngle"_ustr
, true ) ?
850 static_cast<sal_uInt16
>( ( *o3tl::doAccess
<sal_Int32
>(aAny
) ) + 5 ) / 10 : 0;
853 AddOpt( ESCHER_Prop_txflTextFlow
, ESCHER_txflBtoT
);
857 AddOpt( ESCHER_Prop_txflTextFlow
, ESCHER_txflTtoBA
);
861 bool EscherPropertyContainer::GetLineArrow( const bool bLineStart
,
862 const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
863 ESCHER_LineEnd
& reLineEnd
, sal_Int32
& rnArrowLength
, sal_Int32
& rnArrowWidth
)
865 const OUString
sLine ( bLineStart
? u
"LineStart"_ustr
: u
"LineEnd"_ustr
);
866 const OUString
sLineName ( bLineStart
? u
"LineStartName"_ustr
: u
"LineEndName"_ustr
);
868 bool bIsArrow
= false;
871 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, sLine
) )
873 tools::PolyPolygon
aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aAny
) );
874 if ( aPolyPoly
.Count() && aPolyPoly
[ 0 ].GetSize() )
878 reLineEnd
= ESCHER_LineArrowEnd
;
882 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, sLineName
) )
884 OUString aArrowStartName
= *o3tl::doAccess
<OUString
>(aAny
);
885 sal_uInt16 nWhich
= bLineStart
? sal_uInt16(XATTR_LINESTART
) : sal_uInt16(XATTR_LINEEND
);
887 // remove extra space separated number
888 sal_Int32 nPos
= aArrowStartName
.lastIndexOf(' ');
889 if (nPos
> -1 && aArrowStartName
.lastIndexOf(' ', nPos
) > -1)
890 aArrowStartName
= aArrowStartName
.copy(0, nPos
);
892 OUString aApiName
= SvxUnogetApiNameForItem(nWhich
, aArrowStartName
);
893 bool bIsMapped
= true;
894 if ( !aApiName
.isEmpty() )
897 // TODO: calculate the best option for ArrowLength and ArrowWidth
898 if ( aApiName
== "Arrow concave" )
899 reLineEnd
= ESCHER_LineArrowStealthEnd
;
900 else if ( aApiName
== "Square 45" )
901 reLineEnd
= ESCHER_LineArrowDiamondEnd
;
902 else if ( aApiName
== "Small Arrow" )
903 reLineEnd
= ESCHER_LineArrowEnd
;
904 else if ( aApiName
== "Dimension Lines" )
908 reLineEnd
= ESCHER_LineArrowOvalEnd
;
910 else if ( aApiName
== "Double Arrow" )
911 reLineEnd
= ESCHER_LineArrowEnd
;
912 else if ( aApiName
== "Rounded short Arrow" )
913 reLineEnd
= ESCHER_LineArrowEnd
;
914 else if ( aApiName
== "Symmetric Arrow" )
915 reLineEnd
= ESCHER_LineArrowEnd
;
916 else if ( aApiName
== "Line Arrow" )
917 reLineEnd
= ESCHER_LineArrowOpenEnd
;
918 else if ( aApiName
== "Rounded large Arrow" )
919 reLineEnd
= ESCHER_LineArrowEnd
;
920 else if ( aApiName
== "Circle" )
921 reLineEnd
= ESCHER_LineArrowOvalEnd
;
922 else if ( aApiName
== "Square" )
923 reLineEnd
= ESCHER_LineArrowDiamondEnd
;
924 else if ( aApiName
== "Arrow" )
925 reLineEnd
= ESCHER_LineArrowEnd
;
930 if ( !bIsMapped
&& comphelper::string::getTokenCount(aArrowStartName
, ' ') == 2 )
933 std::u16string_view
aArrowName( o3tl::getToken(aArrowStartName
, 0, ' ', nIdx
) );
934 if ( aArrowName
== u
"msArrowEnd" )
935 reLineEnd
= ESCHER_LineArrowEnd
;
936 else if ( aArrowName
== u
"msArrowOpenEnd" )
937 reLineEnd
= ESCHER_LineArrowOpenEnd
;
938 else if ( aArrowName
== u
"msArrowStealthEnd" )
939 reLineEnd
= ESCHER_LineArrowStealthEnd
;
940 else if ( aArrowName
== u
"msArrowDiamondEnd" )
941 reLineEnd
= ESCHER_LineArrowDiamondEnd
;
942 else if ( aArrowName
== u
"msArrowOvalEnd" )
943 reLineEnd
= ESCHER_LineArrowOvalEnd
;
947 // now we have the arrow, and try to determine the arrow size;
950 std::u16string_view aArrowSize
= o3tl::getToken(aArrowStartName
, 0, ' ', nIdx
);
951 sal_Int32 nArrowSize
= o3tl::toInt32(aArrowSize
);
952 rnArrowWidth
= ( nArrowSize
- 1 ) / 3;
953 rnArrowLength
= nArrowSize
- ( rnArrowWidth
* 3 ) - 1;
962 void EscherPropertyContainer::CreateLineProperties(
963 const uno::Reference
<beans::XPropertySet
> & rXPropSet
, bool bEdge
)
966 sal_uInt32 nLineFlags
= 0x80008;
968 ESCHER_LineEnd eLineEnd
;
969 sal_Int32 nArrowLength
;
970 sal_Int32 nArrowWidth
;
972 bool bSwapLineEnds
= false;
973 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"CircleKind"_ustr
, true ) )
975 drawing::CircleKind eCircleKind
;
976 if ( aAny
>>= eCircleKind
)
978 if ( eCircleKind
== drawing::CircleKind_ARC
)
979 bSwapLineEnds
= true;
982 if ( GetLineArrow( !bSwapLineEnds
, rXPropSet
, eLineEnd
, nArrowLength
, nArrowWidth
) )
984 AddOpt( ESCHER_Prop_lineStartArrowLength
, nArrowLength
);
985 AddOpt( ESCHER_Prop_lineStartArrowWidth
, nArrowWidth
);
986 AddOpt( ESCHER_Prop_lineStartArrowhead
, eLineEnd
);
987 nLineFlags
|= 0x100010;
989 if ( GetLineArrow( bSwapLineEnds
, rXPropSet
, eLineEnd
, nArrowLength
, nArrowWidth
) )
991 AddOpt( ESCHER_Prop_lineEndArrowLength
, nArrowLength
);
992 AddOpt( ESCHER_Prop_lineEndArrowWidth
, nArrowWidth
);
993 AddOpt( ESCHER_Prop_lineEndArrowhead
, eLineEnd
);
994 nLineFlags
|= 0x100010;
998 if(EscherPropertyValueHelper::GetPropertyValue(aAny
, rXPropSet
, u
"LineCap"_ustr
))
1000 drawing::LineCap
aLineCap(drawing::LineCap_BUTT
);
1002 if(aAny
>>= aLineCap
)
1006 default: /* drawing::LineCap_BUTT */
1008 AddOpt(ESCHER_Prop_lineEndCapStyle
, ESCHER_LineEndCapFlat
);
1011 case drawing::LineCap_ROUND
:
1013 AddOpt(ESCHER_Prop_lineEndCapStyle
, ESCHER_LineEndCapRound
);
1016 case drawing::LineCap_SQUARE
:
1018 AddOpt(ESCHER_Prop_lineEndCapStyle
, ESCHER_LineEndCapSquare
);
1025 sal_uInt32 nLineWidth
= ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"LineWidth"_ustr
) )
1026 ? *o3tl::doAccess
<sal_uInt32
>(aAny
) : 0;
1027 if ( nLineWidth
> 1 )
1028 AddOpt( ESCHER_Prop_lineWidth
, nLineWidth
* 360 ); // 100TH MM -> PT , 1PT = 12700 EMU
1030 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"LineStyle"_ustr
) )
1032 drawing::LineStyle eLS
;
1037 case drawing::LineStyle_NONE
:
1038 AddOpt( ESCHER_Prop_fNoLineDrawDash
, 0x90000 ); // 80000
1041 case drawing::LineStyle_DASH
:
1043 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"LineDash"_ustr
) )
1045 ESCHER_LineDashing eDash
= ESCHER_LineSolid
;
1046 auto pLineDash
= o3tl::doAccess
<drawing::LineDash
>(aAny
);
1047 switch ( pLineDash
->Style
)
1049 case drawing::DashStyle_ROUND
:
1050 case drawing::DashStyle_ROUNDRELATIVE
:
1051 AddOpt( ESCHER_Prop_lineEndCapStyle
, 0 ); // set Style Round
1055 // Try to detect exact prstDash styles. Use a similar method as in oox export.
1056 // Map it to a roughly fitting prstDash in other cases.
1057 bool bIsConverted
= false;
1058 bool bIsRelative
= pLineDash
->Style
== drawing::DashStyle_RECTRELATIVE
1059 || pLineDash
->Style
== drawing::DashStyle_ROUNDRELATIVE
;
1060 sal_Int16 nDashes
= pLineDash
->Dashes
;
1061 sal_Int16 nDots
= pLineDash
->Dots
;
1062 sal_Int32 nDashLen
= pLineDash
->DashLen
;
1063 sal_Int32 nDotLen
= pLineDash
->DotLen
;
1064 sal_Int32 nDistance
= pLineDash
->Distance
;
1066 // Caution! The names are misleading. "dot" is always the first dash and "dash"
1067 // the second one, regardless of the actual length. All prstDash
1068 // definitions start with the longer dash and have exact one longer dash.
1069 // Preset line style definitions for binary format are the same as for OOXML.
1070 if (bIsRelative
&& nDots
== 1)
1072 // I'm not sure that LO always uses 100%, because in case of absolute values, LO
1073 // sets length to 0 but treats it as 100%, if the attribute is missing in ODF.
1074 // So to be sure set 100% explicitly in case of relative too.
1075 if (nDashes
> 0 && nDashLen
== 0)
1079 bIsConverted
= true;
1080 if (nDotLen
== 100 && nDashes
== 0 && nDashLen
== 0 && nDistance
== 300)
1081 eDash
= ESCHER_LineDotGEL
;
1082 else if (nDotLen
== 400 && nDashes
== 0 && nDashLen
== 0 && nDistance
== 300)
1083 eDash
= ESCHER_LineDashGEL
;
1084 else if (nDotLen
== 400 && nDashes
== 1 && nDashLen
== 100 && nDistance
== 300)
1085 eDash
= ESCHER_LineDashDotGEL
;
1086 else if (nDotLen
== 800 && nDashes
== 0 && nDashLen
== 0 && nDistance
== 300)
1087 eDash
= ESCHER_LineLongDashGEL
;
1088 else if (nDotLen
== 800 && nDashes
== 1 && nDashLen
== 100 && nDistance
== 300)
1089 eDash
= ESCHER_LineLongDashDotGEL
;
1090 else if (nDotLen
== 800 && nDashes
== 2 && nDashLen
== 100 && nDistance
== 300)
1091 eDash
= ESCHER_LineLongDashDotDotGEL
;
1092 else if (nDotLen
== 100 && nDashes
== 0 && nDashLen
== 0 && nDistance
== 100)
1093 eDash
= ESCHER_LineDotSys
;
1094 else if (nDotLen
== 300 && nDashes
== 0 && nDashLen
== 0 && nDistance
== 100)
1095 eDash
= ESCHER_LineDashSys
;
1096 else if (nDotLen
== 300 && nDashes
== 1 && nDashLen
== 100 && nDistance
== 100)
1097 eDash
= ESCHER_LineDashDotSys
;
1098 else if (nDotLen
== 300 && nDashes
== 2 && nDashLen
== 100 && nDistance
== 100)
1099 eDash
= ESCHER_LineDashDotDotSys
;
1101 bIsConverted
= false;
1105 { // Map the style roughly to preset line styles.
1106 if (((!(pLineDash
->Dots
)) || (!(pLineDash
->Dashes
)))
1107 || (pLineDash
->DotLen
== pLineDash
->DashLen
))
1109 sal_Int32 nLen
= pLineDash
->DotLen
;
1110 if (pLineDash
->Dashes
)
1111 nLen
= pLineDash
->DashLen
;
1112 if (nLen
>= nDistance
)
1113 eDash
= ESCHER_LineLongDashGEL
;
1114 else if (pLineDash
->Dots
)
1115 eDash
= ESCHER_LineDotSys
;
1117 eDash
= ESCHER_LineDashGEL
;
1121 if (pLineDash
->Dots
!= pLineDash
->Dashes
)
1123 if ((pLineDash
->DashLen
> nDistance
) || (pLineDash
->DotLen
> nDistance
))
1124 eDash
= ESCHER_LineLongDashDotDotGEL
;
1126 eDash
= ESCHER_LineDashDotDotSys
;
1130 if ((pLineDash
->DashLen
> nDistance
) || (pLineDash
->DotLen
> nDistance
))
1131 eDash
= ESCHER_LineLongDashDotGEL
;
1133 eDash
= ESCHER_LineDashDotGEL
;
1137 AddOpt( ESCHER_Prop_lineDashing
, eDash
);
1141 case drawing::LineStyle_SOLID
:
1144 AddOpt( ESCHER_Prop_fNoLineDrawDash
, nLineFlags
);
1149 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"LineColor"_ustr
) )
1151 sal_uInt32 nLineColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
) );
1152 AddOpt( ESCHER_Prop_lineColor
, nLineColor
);
1153 AddOpt( ESCHER_Prop_lineBackColor
, nLineColor
^ 0xffffff );
1157 ESCHER_LineJoin eLineJoin
= ESCHER_LineJoinMiter
;
1158 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"LineJoint"_ustr
, true ) )
1160 drawing::LineJoint eLJ
;
1165 case drawing::LineJoint_NONE
:
1166 case drawing::LineJoint_BEVEL
:
1167 eLineJoin
= ESCHER_LineJoinBevel
;
1170 case drawing::LineJoint_MIDDLE
:
1171 case drawing::LineJoint_MITER
:
1172 eLineJoin
= ESCHER_LineJoinMiter
;
1174 case drawing::LineJoint_ROUND
:
1175 eLineJoin
= ESCHER_LineJoinRound
;
1180 AddOpt( ESCHER_Prop_lineJoinStyle
, eLineJoin
);
1182 if ( EscherPropertyValueHelper::GetPropertyValue(
1183 aAny
, rXPropSet
, u
"LineTransparence"_ustr
, true ) )
1185 sal_Int16 nTransparency
= 0;
1186 if ( aAny
>>= nTransparency
)
1187 AddOpt( ESCHER_Prop_lineOpacity
, ( ( 100 - nTransparency
) << 16 ) / 100 );
1193 AddOpt( ESCHER_Prop_fFillOK
, 0x1001 );
1194 AddOpt( ESCHER_Prop_fNoFillHitTest
, 0x100000 );
1198 static Size
lcl_SizeToEmu(Size aPrefSize
, const MapMode
& aPrefMapMode
)
1201 if (aPrefMapMode
.GetMapUnit() == MapUnit::MapPixel
)
1202 aRetSize
= Application::GetDefaultDevice()->PixelToLogic(aPrefSize
, MapMode(MapUnit::Map100thMM
));
1204 aRetSize
= OutputDevice::LogicToLogic(aPrefSize
, aPrefMapMode
, MapMode(MapUnit::Map100thMM
));
1208 void EscherPropertyContainer::ImplCreateGraphicAttributes( const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
1209 sal_uInt32 nBlibId
, bool bCreateCroppingAttributes
)
1213 sal_uInt32 nPicFlags
= 0;
1214 drawing::ColorMode
eColorMode( drawing::ColorMode_STANDARD
);
1215 sal_Int16 nLuminance
= 0;
1216 sal_Int32 nContrast
= 0;
1218 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"GraphicColorMode"_ustr
) )
1219 aAny
>>= eColorMode
;
1220 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"AdjustLuminance"_ustr
) )
1221 aAny
>>= nLuminance
;
1222 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"AdjustContrast"_ustr
) )
1224 sal_Int16 nC
= sal_Int16();
1229 if ( eColorMode
== drawing::ColorMode_WATERMARK
)
1231 eColorMode
= drawing::ColorMode_STANDARD
;
1233 if ( nLuminance
> 100 )
1236 if ( nContrast
< -100 )
1239 if ( eColorMode
== drawing::ColorMode_GREYS
)
1240 nPicFlags
|= 0x40004;
1241 else if ( eColorMode
== drawing::ColorMode_MONO
)
1242 nPicFlags
|= 0x60006;
1247 if ( nContrast
== 100)
1248 nContrast
= 0x10000;
1249 else if ( nContrast
< 100 )
1251 nContrast
*= 0x10000;
1254 else if ( nContrast
< 200 )
1255 nContrast
= ( 100 * 0x10000 ) / ( 200 - nContrast
);
1257 nContrast
= 0x7fffffff;
1258 AddOpt( ESCHER_Prop_pictureContrast
, nContrast
);
1261 AddOpt( ESCHER_Prop_pictureBrightness
, nLuminance
* 327 );
1263 AddOpt( ESCHER_Prop_pictureActive
, nPicFlags
);
1265 if ( !(bCreateCroppingAttributes
&& pGraphicProvider
) )
1269 MapMode aPrefMapMode
;
1270 if ( !pGraphicProvider
->GetPrefSize( nBlibId
, aPrefSize
, aPrefMapMode
) )
1273 Size
aCropSize(lcl_SizeToEmu(aPrefSize
, aPrefMapMode
));
1274 if ( !(aCropSize
.Width() && aCropSize
.Height()) )
1277 if ( !EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"GraphicCrop"_ustr
) )
1280 text::GraphicCrop aGraphCrop
;
1281 if ( !(aAny
>>= aGraphCrop
) )
1284 if ( aGraphCrop
.Left
)
1286 sal_uInt32 nLeft
= ( aGraphCrop
.Left
* 65536 ) / aCropSize
.Width();
1287 AddOpt( ESCHER_Prop_cropFromLeft
, nLeft
);
1289 if ( aGraphCrop
.Top
)
1291 sal_uInt32 nTop
= ( aGraphCrop
.Top
* 65536 ) / aCropSize
.Height();
1292 AddOpt( ESCHER_Prop_cropFromTop
, nTop
);
1294 if ( aGraphCrop
.Right
)
1296 sal_uInt32 nRight
= ( aGraphCrop
.Right
* 65536 ) / aCropSize
.Width();
1297 AddOpt( ESCHER_Prop_cropFromRight
, nRight
);
1299 if ( aGraphCrop
.Bottom
)
1301 sal_uInt32 nBottom
= ( aGraphCrop
.Bottom
* 65536 ) / aCropSize
.Height();
1302 AddOpt( ESCHER_Prop_cropFromBottom
, nBottom
);
1306 void EscherPropertyContainer::CreateShapeProperties( const uno::Reference
<drawing::XShape
> & rXShape
)
1308 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
1309 if ( !aXPropSet
.is() )
1312 bool bVisible
= false;
1313 bool bPrintable
= false;
1315 sal_uInt32 nShapeAttr
= 0;
1316 if (EscherPropertyValueHelper::GetPropertyValue(aAny
, aXPropSet
, u
"Visible"_ustr
, true) && (aAny
>>= bVisible
))
1319 nShapeAttr
|= 0x20002; // set fHidden = true
1321 // This property (fPrint) isn't used in Excel anymore, leaving it for legacy reasons
1322 // one change, based on XLSX: hidden implies not printed, let's not export the fPrint property in that case
1323 if (bVisible
&& EscherPropertyValueHelper::GetPropertyValue(aAny
, aXPropSet
, u
"Printable"_ustr
, true) && (aAny
>>= bPrintable
))
1326 nShapeAttr
|= 0x10000; // set fPrint = false;
1329 AddOpt( ESCHER_Prop_fPrint
, nShapeAttr
);
1332 bool EscherPropertyContainer::CreateOLEGraphicProperties(const uno::Reference
<drawing::XShape
> & rXShape
)
1334 bool bRetValue
= false;
1338 SdrObject
* pObject
= SdrObject::getSdrObjectFromXShape(rXShape
); // SJ: leaving unoapi, because currently there is
1339 if (auto pOle2Obj
= dynamic_cast<const SdrOle2Obj
*>(pObject
)) // no access to the native graphic object
1341 const Graphic
* pGraphic
= pOle2Obj
->GetGraphic();
1344 GraphicObject
aGraphicObject(*pGraphic
);
1345 bRetValue
= CreateGraphicProperties(rXShape
, aGraphicObject
);
1352 bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference
<drawing::XShape
> & rXShape
, const GraphicObject
& rGraphicObj
)
1354 bool bRetValue
= false;
1355 OString
aUniqueId(rGraphicObj
.GetUniqueID());
1356 if ( !aUniqueId
.isEmpty() )
1358 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillPicture
);
1359 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
1361 if ( pGraphicProvider
&& pPicOutStrm
&& pShapeBoundRect
&& aXPropSet
.is() )
1364 std::unique_ptr
<awt::Rectangle
> pVisArea
;
1365 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"VisibleArea"_ustr
) )
1367 pVisArea
.reset(new awt::Rectangle
);
1370 sal_uInt32 nBlibId
= pGraphicProvider
->GetBlibID( *pPicOutStrm
, rGraphicObj
, pVisArea
.get() );
1373 AddOpt( ESCHER_Prop_pib
, nBlibId
, true );
1374 ImplCreateGraphicAttributes( aXPropSet
, nBlibId
, false );
1382 bool EscherPropertyContainer::CreateMediaGraphicProperties(const uno::Reference
<drawing::XShape
> & rXShape
)
1384 bool bRetValue
= false;
1387 SdrObject
* pSdrObject(SdrObject::getSdrObjectFromXShape(rXShape
)); // SJ: leaving unoapi, because currently there is
1388 if (auto pSdrMediaObj
= dynamic_cast<const SdrMediaObj
*>(pSdrObject
)) // no access to the native graphic object
1390 GraphicObject
aGraphicObject(pSdrMediaObj
->getSnapshot());
1391 bRetValue
= CreateGraphicProperties(rXShape
, aGraphicObject
);
1397 bool EscherPropertyContainer::ImplCreateEmbeddedBmp(GraphicObject
const & rGraphicObject
)
1399 if (rGraphicObject
.GetType() != GraphicType::NONE
)
1401 EscherGraphicProvider aProvider
;
1402 SvMemoryStream aMemStrm
;
1404 if (aProvider
.GetBlibID( aMemStrm
, rGraphicObject
))
1406 AddOpt(ESCHER_Prop_fillBlip
, true, 0, aMemStrm
);
1413 void EscherPropertyContainer::CreateEmbeddedBitmapProperties(
1414 uno::Reference
<awt::XBitmap
> const & rxBitmap
, drawing::BitmapMode eBitmapMode
)
1416 uno::Reference
<graphic::XGraphic
> xGraphic(rxBitmap
, uno::UNO_QUERY
);
1419 Graphic
aGraphic(xGraphic
);
1420 if (aGraphic
.IsNone())
1422 GraphicObject
aGraphicObject(std::move(aGraphic
));
1423 if (aGraphicObject
.GetType() == GraphicType::NONE
)
1425 if (ImplCreateEmbeddedBmp(aGraphicObject
))
1427 // bitmap mode property
1428 bool bRepeat
= eBitmapMode
== drawing::BitmapMode_REPEAT
;
1429 AddOpt( ESCHER_Prop_fillType
, bRepeat
? ESCHER_FillTexture
: ESCHER_FillPicture
);
1435 Graphic
lclDrawHatch( const drawing::Hatch
& rHatch
, const Color
& rBackColor
, bool bFillBackground
, const tools::Rectangle
& rRect
)
1437 // #i121183# For hatch, do no longer create a bitmap with the fixed size of 28x28 pixels. Also
1438 // do not create a bitmap in page size, that would explode file sizes (and have no good quality).
1439 // Better use a MetaFile graphic in page size; thus we have good quality due to vector format and
1440 // no bit file sizes.
1441 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
1444 pVDev
->SetOutputSizePixel(Size(2, 2));
1445 pVDev
->EnableOutput(false);
1446 pVDev
->SetMapMode(MapMode(MapUnit::Map100thMM
));
1449 pVDev
->SetLineColor();
1450 pVDev
->SetFillColor(bFillBackground
? rBackColor
: COL_TRANSPARENT
);
1451 pVDev
->DrawRect(rRect
);
1452 pVDev
->DrawHatch(tools::PolyPolygon(rRect
), Hatch(static_cast<HatchStyle
>(rHatch
.Style
), Color(ColorTransparency
, rHatch
.Color
), rHatch
.Distance
,
1453 Degree10(rHatch
.Angle
)));
1456 aMtf
.SetPrefMapMode(MapMode(MapUnit::Map100thMM
));
1457 aMtf
.SetPrefSize(rRect
.GetSize());
1459 return Graphic(aMtf
);
1464 void EscherPropertyContainer::CreateEmbeddedHatchProperties(const drawing::Hatch
& rHatch
, const Color
& rBackColor
, bool bFillBackground
)
1466 const tools::Rectangle
aRect(pShapeBoundRect
? *pShapeBoundRect
: tools::Rectangle(Point(0,0), Size(28000, 21000)));
1467 Graphic
aGraphic(lclDrawHatch(rHatch
, rBackColor
, bFillBackground
, aRect
));
1468 GraphicObject
aGraphicObject(std::move(aGraphic
));
1470 if (ImplCreateEmbeddedBmp(aGraphicObject
))
1471 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillTexture
);
1474 bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
1475 const OUString
& rSource
,
1476 const bool bCreateFillBitmap
,
1477 const bool bCreateCroppingAttributes
,
1478 const bool bFillBitmapModeAllowed
,
1479 const bool bOOxmlExport
)
1481 bool bRetValue
= false;
1482 bool bCreateFillStyles
= false;
1484 std::unique_ptr
<GraphicAttr
> pGraphicAttr
;
1485 uno::Reference
<graphic::XGraphic
> xGraphic
;
1489 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, rSource
) )
1491 bool bMirrored
= false;
1492 bool bRotate
= true;
1493 bool bIsGraphicMtf
= false;
1494 sal_Int16
nTransparency(0);
1496 sal_Int16
nGreen(0);
1499 drawing::BitmapMode
eBitmapMode(drawing::BitmapMode_NO_REPEAT
);
1500 OUString aGraphicUrl
;
1502 sal_uInt16 nAngle
= 0;
1503 if ( rSource
== "MetaFile" )
1505 auto & aSeq
= *o3tl::doAccess
<uno::Sequence
<sal_Int8
>>(aAny
);
1506 const sal_Int8
* pArray
= aSeq
.getConstArray();
1507 sal_uInt32 nArrayLength
= aSeq
.getLength();
1509 // the metafile is already rotated
1512 if (pArray
&& nArrayLength
)
1515 SvMemoryStream
aStream(const_cast<sal_Int8
*>(pArray
), nArrayLength
, StreamMode::READ
);
1516 ErrCode nErrCode
= GraphicConverter::Import(aStream
, aGraphic
, ConvertDataFormat::WMF
);
1517 if ( nErrCode
== ERRCODE_NONE
)
1519 xGraphic
= aGraphic
.GetXGraphic();
1520 bIsGraphicMtf
= aGraphic
.GetType() == GraphicType::GdiMetafile
;
1524 else if (rSource
== "Bitmap" || rSource
== "FillBitmap")
1526 auto xBitmap
= aAny
.get
<uno::Reference
<awt::XBitmap
>>();
1529 xGraphic
.set(xBitmap
, uno::UNO_QUERY
);
1530 Graphic
aGraphic(xGraphic
);
1531 bIsGraphicMtf
= aGraphic
.GetType() == GraphicType::GdiMetafile
;
1534 else if ( rSource
== "Graphic" )
1536 xGraphic
= aAny
.get
<uno::Reference
<graphic::XGraphic
>>();
1537 bCreateFillStyles
= true;
1539 else if ( rSource
== "FillHatch" )
1541 drawing::Hatch aHatch
;
1542 if ( aAny
>>= aHatch
)
1545 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillColor"_ustr
) )
1547 aBackColor
= Color(ColorTransparency
, ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
), false ));
1549 bool bFillBackground
= false;
1550 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBackground"_ustr
, true ) )
1552 aAny
>>= bFillBackground
;
1555 const tools::Rectangle
aRect(Point(0, 0), pShapeBoundRect
? pShapeBoundRect
->GetSize() : Size(28000, 21000));
1556 Graphic
aGraphic(lclDrawHatch(aHatch
, aBackColor
, bFillBackground
, aRect
));
1557 xGraphic
= aGraphic
.GetXGraphic();
1558 eBitmapMode
= drawing::BitmapMode_REPEAT
;
1559 bIsGraphicMtf
= aGraphic
.GetType() == GraphicType::GdiMetafile
;
1563 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"IsMirrored"_ustr
, true ) )
1566 // #121074# transparency of graphic is not supported in MS formats, get and apply it
1567 // in the GetTransformedGraphic call in GetBlibID
1568 if(EscherPropertyValueHelper::GetPropertyValue(aAny
, rXPropSet
, u
"Transparency"_ustr
))
1570 aAny
>>= nTransparency
;
1573 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"AdjustRed"_ustr
) )
1578 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"AdjustGreen"_ustr
) )
1583 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"AdjustBlue"_ustr
) )
1588 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"Gamma"_ustr
) )
1593 if ( bCreateFillBitmap
&& bFillBitmapModeAllowed
)
1595 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBitmapMode"_ustr
, true ) )
1596 aAny
>>= eBitmapMode
;
1600 nAngle
= bRotate
&& EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"RotateAngle"_ustr
, true )
1601 ? static_cast<sal_uInt16
>( ( *o3tl::doAccess
<sal_Int32
>(aAny
) ) + 5 ) / 10
1607 Graphic
aGraphic(xGraphic
);
1608 aGraphicUrl
= aGraphic
.getOriginURL();
1611 if (!aGraphicUrl
.isEmpty())
1613 bool bConverted
= false;
1615 // externally, linked graphic? convert to embedded
1616 // one, if transformations are needed. this is because
1617 // everything < msoxp cannot even handle rotated
1619 // And check whether the graphic link target is
1620 // actually supported by mso.
1621 INetURLObject
aTmp( aGraphicUrl
);
1622 GraphicDescriptor
aDescriptor(aTmp
);
1623 (void)aDescriptor
.Detect();
1624 const GraphicFileFormat nFormat
= aDescriptor
.GetFileFormat();
1626 // can MSO handle it?
1627 if ( bMirrored
|| nAngle
|| nTransparency
|| nRed
|| nGreen
|| nBlue
|| (1.0 != fGamma
) ||
1628 (nFormat
!= GraphicFileFormat::BMP
&&
1629 nFormat
!= GraphicFileFormat::GIF
&&
1630 nFormat
!= GraphicFileFormat::JPG
&&
1631 nFormat
!= GraphicFileFormat::PNG
&&
1632 nFormat
!= GraphicFileFormat::TIF
&&
1633 nFormat
!= GraphicFileFormat::PCT
&&
1634 nFormat
!= GraphicFileFormat::WMF
&&
1635 nFormat
!= GraphicFileFormat::WMZ
&&
1636 nFormat
!= GraphicFileFormat::EMF
&&
1637 nFormat
!= GraphicFileFormat::EMZ
) )
1639 std::unique_ptr
<SvStream
> pIn(::utl::UcbStreamHelper::CreateStream(
1640 aTmp
.GetMainURL( INetURLObject::DecodeMechanism::NONE
), StreamMode::READ
));
1644 ErrCode nErrCode
= GraphicConverter::Import( *pIn
, aGraphic
);
1646 if ( nErrCode
== ERRCODE_NONE
)
1648 xGraphic
= aGraphic
.GetXGraphic();
1651 // else: simply keep the graphic link
1655 if (!bConverted
&& pGraphicProvider
)
1657 const OUString
& rBaseURI( pGraphicProvider
->GetBaseURI() );
1658 INetURLObject
aBaseURI( rBaseURI
);
1659 if( aBaseURI
.GetProtocol() == aTmp
.GetProtocol() )
1661 OUString
aRelUrl( INetURLObject::GetRelURL( rBaseURI
, aGraphicUrl
) );
1662 if ( !aRelUrl
.isEmpty() )
1663 aGraphicUrl
= aRelUrl
;
1668 if (!aGraphicUrl
.isEmpty() || xGraphic
.is())
1670 if(bMirrored
|| nTransparency
|| nRed
|| nGreen
|| nBlue
|| (1.0 != fGamma
))
1672 pGraphicAttr
.reset(new GraphicAttr
);
1676 pGraphicAttr
->SetMirrorFlags(BmpMirrorFlags::Horizontal
);
1681 pGraphicAttr
->SetAlpha(255 - (nTransparency
* 255) / 100);
1686 pGraphicAttr
->SetChannelR(nRed
);
1691 pGraphicAttr
->SetChannelG(nGreen
);
1696 pGraphicAttr
->SetChannelB(nBlue
);
1701 pGraphicAttr
->SetGamma(fGamma
);
1705 if(nAngle
&& bIsGraphicMtf
)
1707 AddOpt( ESCHER_Prop_Rotation
, ( ( (static_cast<sal_Int32
>(nAngle
) << 16 ) / 10 ) + 0x8000 ) &~ 0xffff );
1710 if ( eBitmapMode
== drawing::BitmapMode_REPEAT
)
1712 sal_Int32 nSizeX
= 0,nSizeY
= 0,nOffsetX
= 0,nOffsetY
= 0,nPosOffsetX
= 0,nPosOffsetY
= 0;
1713 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBitmapSizeX"_ustr
, true ) )
1717 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBitmapSizeY"_ustr
, true ) )
1721 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBitmapOffsetX"_ustr
, true ) )
1725 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBitmapOffsetY"_ustr
, true ) )
1729 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBitmapPositionOffsetX"_ustr
, true ) )
1731 aAny
>>= nPosOffsetX
;
1733 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"FillBitmapPositionOffsetY"_ustr
, true ) )
1735 aAny
>>= nPosOffsetY
;
1737 if(nSizeX
== -100 && nSizeY
== -100 && nOffsetX
== 0 && nOffsetY
== 0 && nPosOffsetX
== 0 && nPosOffsetY
== 0)
1738 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillPicture
);
1740 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillTexture
);
1743 AddOpt( ESCHER_Prop_fillType
, ESCHER_FillPicture
);
1747 Graphic
aGraphic(xGraphic
);
1748 if (!aGraphic
.getOriginURL().isEmpty())
1750 AddOpt(ESCHER_Prop_pibName
, aGraphicUrl
);
1751 sal_uInt32 nPibFlags
= 0;
1752 GetOpt(ESCHER_Prop_pibFlags
, nPibFlags
);
1753 AddOpt(ESCHER_Prop_pibFlags
, ESCHER_BlipFlagLinkToFile
| ESCHER_BlipFlagFile
| ESCHER_BlipFlagDoNotSave
| nPibFlags
);
1755 else if (pGraphicProvider
&& pPicOutStrm
&& pShapeBoundRect
) // write out embedded graphic
1757 GraphicObject
aGraphicObject(std::move(aGraphic
));
1758 const sal_uInt32
nBlibId(pGraphicProvider
->GetBlibID(*pPicOutStrm
, aGraphicObject
, nullptr, pGraphicAttr
.get()));
1762 if(bCreateFillBitmap
)
1764 AddOpt(ESCHER_Prop_fillBlip
, nBlibId
, true);
1768 AddOpt( ESCHER_Prop_pib
, nBlibId
, true );
1769 ImplCreateGraphicAttributes( rXPropSet
, nBlibId
, bCreateCroppingAttributes
);
1777 EscherGraphicProvider aProvider
;
1778 SvMemoryStream aMemStrm
;
1779 GraphicObject
aGraphicObject(std::move(aGraphic
));
1781 if (aProvider
.GetBlibID(aMemStrm
, aGraphicObject
, nullptr, pGraphicAttr
.get(), bOOxmlExport
))
1783 AddOpt(ESCHER_Prop_fillBlip
, true, 0, aMemStrm
);
1790 pGraphicAttr
.reset();
1791 if ( bCreateFillStyles
)
1792 CreateFillProperties( rXPropSet
, true );
1797 tools::PolyPolygon
EscherPropertyContainer::GetPolyPolygon( const uno::Reference
< drawing::XShape
> & rXShape
)
1799 tools::PolyPolygon aRetPolyPoly
;
1800 uno::Reference
< beans::XPropertySet
> aXPropSet
;
1801 uno::Any
aAny( rXShape
->queryInterface(
1802 cppu::UnoType
<beans::XPropertySet
>::get()));
1804 if ( aAny
>>= aXPropSet
)
1806 bool bHasProperty
= EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"PolyPolygonBezier"_ustr
, true );
1807 if ( !bHasProperty
)
1808 bHasProperty
= EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"PolyPolygon"_ustr
, true );
1809 if ( !bHasProperty
)
1810 bHasProperty
= EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"Polygon"_ustr
, true );
1812 aRetPolyPoly
= GetPolyPolygon( aAny
);
1814 return aRetPolyPoly
;
1817 // adapting to basegfx::B2DPolyPolygon now, has no sense to do corrections in the
1818 // old tools::PolyPolygon creation code. Convert to that at return time
1819 tools::PolyPolygon
EscherPropertyContainer::GetPolyPolygon( const uno::Any
& rAny
)
1821 basegfx::B2DPolyPolygon aRetval
;
1823 if(auto pBCC
= o3tl::tryAccess
<drawing::PolyPolygonBezierCoords
>(rAny
))
1825 aRetval
= basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pBCC
);
1827 else if(auto pCC
= o3tl::tryAccess
<drawing::PointSequenceSequence
>(rAny
))
1829 aRetval
= basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pCC
);
1831 else if(auto pC
= o3tl::tryAccess
<drawing::PointSequence
>(rAny
))
1833 aRetval
.append(basegfx::utils::UnoPointSequenceToB2DPolygon(*pC
));
1836 basegfx::B2DPolyPolygon aRetval2
;
1838 for(sal_uInt32
a(0); a
< aRetval
.count(); a
++)
1840 if(0 != aRetval
.getB2DPolygon(a
).count())
1842 aRetval2
.append(aRetval
.getB2DPolygon(a
));
1846 return tools::PolyPolygon(aRetval2
);
1849 bool EscherPropertyContainer::CreatePolygonProperties(
1850 const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
1853 awt::Rectangle
& rGeoRect
,
1854 tools::Polygon
const * pPolygon
)
1856 tools::PolyPolygon aPolyPolygon
;
1858 if(nullptr != pPolygon
)
1860 aPolyPolygon
.Insert(*pPolygon
);
1866 if(EscherPropertyValueHelper::GetPropertyValue(
1869 bBezier
? u
"PolyPolygonBezier"_ustr
: u
"PolyPolygon"_ustr
,
1872 aPolyPolygon
= GetPolyPolygon(aAny
);
1880 if(0 == aPolyPolygon
.Count())
1885 if(0 != (nFlags
& ESCHER_CREATEPOLYGON_LINE
))
1887 if((1 == aPolyPolygon
.Count()) && (2 == aPolyPolygon
[0].GetSize()))
1889 const tools::Polygon
& rPoly(aPolyPolygon
[0]);
1891 rGeoRect
= awt::Rectangle(
1894 rPoly
[1].X() - rPoly
[0].X(),
1895 rPoly
[1].Y() - rPoly
[0].Y());
1903 const tools::Rectangle
aRect(aPolyPolygon
.GetBoundRect());
1905 rGeoRect
= awt::Rectangle(
1911 const sal_uInt16
nPolyCount(aPolyPolygon
.Count());
1912 sal_uInt32
nTotalPoints(0);
1914 std::vector
< sal_uInt8
> aVertices
1917 static_cast<sal_uInt8
>(0xf0),
1918 static_cast<sal_uInt8
>(0xff)
1921 std::vector
< sal_uInt8
> aSegments
1924 static_cast<sal_uInt8
>(2),
1925 static_cast<sal_uInt8
>(0)
1928 for(sal_uInt16
j(0); j
< nPolyCount
; ++j
)
1930 const tools::Polygon
& aPolygon(aPolyPolygon
[j
]);
1931 const sal_uInt16
nPoints(aPolygon
.GetSize());
1939 aSegments
.push_back(static_cast<sal_uInt8
>(0x0));
1940 aSegments
.push_back(static_cast<sal_uInt8
>(0x40));
1942 sal_uInt16
nSegmentIgnoreCounter(0);
1944 // write points from polygon to buffer
1945 for(sal_uInt16
i(0); i
< nPoints
; ++i
)
1947 Point
aPoint(aPolygon
[i
]);
1949 aPoint
.AdjustX(-(rGeoRect
.X
));
1950 aPoint
.AdjustY(-(rGeoRect
.Y
));
1952 aVertices
.push_back(static_cast<sal_uInt8
>(aPoint
.X()));
1953 aVertices
.push_back(static_cast<sal_uInt8
>(aPoint
.X() >> 8));
1954 aVertices
.push_back(static_cast<sal_uInt8
>(aPoint
.Y()));
1955 aVertices
.push_back(static_cast<sal_uInt8
>(aPoint
.Y() >> 8));
1959 if(0 != nSegmentIgnoreCounter
)
1961 nSegmentIgnoreCounter
--;
1965 aSegments
.push_back(static_cast<sal_uInt8
>(0));
1969 aSegments
.push_back(static_cast<sal_uInt8
>(0xb3));
1973 aSegments
.push_back(static_cast<sal_uInt8
>(0xac));
1976 if(i
+ 1 == nPoints
)
1981 aSegments
.push_back(static_cast<sal_uInt8
>(1));
1982 aSegments
.push_back(static_cast<sal_uInt8
>(0x60));
1987 aSegments
.push_back(static_cast<sal_uInt8
>(1));
1989 if(PolyFlags::Control
== aPolygon
.GetFlags(i
+ 1))
1991 aSegments
.push_back(static_cast<sal_uInt8
>(0x20));
1992 nSegmentIgnoreCounter
= 2;
1996 aSegments
.push_back(static_cast<sal_uInt8
>(0));
2003 if(0 == nTotalPoints
|| aSegments
.size() < 6 || aVertices
.size() < 6)
2007 aVertices
[0] = static_cast<sal_uInt8
>(nTotalPoints
);
2008 aVertices
[1] = static_cast<sal_uInt8
>(nTotalPoints
>> 8);
2009 aVertices
[2] = static_cast<sal_uInt8
>(nTotalPoints
);
2010 aVertices
[3] = static_cast<sal_uInt8
>(nTotalPoints
>> 8);
2012 aSegments
.push_back(static_cast<sal_uInt8
>(0));
2013 aSegments
.push_back(static_cast<sal_uInt8
>(0x80));
2015 const sal_uInt32
nSegmentBufSize(aSegments
.size() - 6);
2016 aSegments
[0] = static_cast<sal_uInt8
>(nSegmentBufSize
>> 1);
2017 aSegments
[1] = static_cast<sal_uInt8
>(nSegmentBufSize
>> 9);
2018 aSegments
[2] = static_cast<sal_uInt8
>(nSegmentBufSize
>> 1);
2019 aSegments
[3] = static_cast<sal_uInt8
>(nSegmentBufSize
>> 9);
2022 ESCHER_Prop_geoRight
,
2025 ESCHER_Prop_geoBottom
,
2028 ESCHER_Prop_shapePath
,
2029 ESCHER_ShapeComplex
);
2031 ESCHER_Prop_pVertices
,
2033 aVertices
.size() - 6,
2036 ESCHER_Prop_pSegmentInfo
,
2046 in MS,the connector including 9 types :
2047 "straightConnector1",
2048 "bentConnector2","bentConnector3","bentConnector4","bentConnector5"
2049 "curvedConnector2","curvedConnector3","curvedConnector4","curvedConnector5"
2050 in AOO,including 4 types:"standard","lines","line","curve"
2051 when save as MS file, the connector must be convert to corresponding type.
2052 "line" and "lines" <-> "straightConnector1"
2053 "standard" <-> "bentConnector2-5"
2054 "curve" <-> "curvedConnector2-5"
2056 static sal_Int32
lcl_GetAdjustValueCount( const XPolygon
& rPoly
)
2059 switch ( rPoly
.GetSize() )
2072 if ( rPoly
.GetSize()>=6 )
2079 // Adjust value decide the position which connector should turn a corner
2080 static sal_Int32
lcl_GetConnectorAdjustValue ( const XPolygon
& rPoly
, sal_uInt16 nIndex
)
2082 sal_uInt16 k
= rPoly
.GetSize();
2083 OSL_ASSERT ( k
>= ( 3 + nIndex
) );
2086 Point aStart
= rPoly
[0];
2087 Point aEnd
= rPoly
[k
-1];
2088 if ( aEnd
.Y() == aStart
.Y() )
2089 aEnd
.setY( aStart
.Y() +4 );
2090 if ( aEnd
.X() == aStart
.X() )
2091 aEnd
.setX( aStart
.X() +4 );
2093 bool bVertical
= ( rPoly
[1].X()-aStart
.X() ) == 0 ;
2094 // vertical and horizon alternate
2095 if ( nIndex
%2 == 1 ) bVertical
= !bVertical
;
2096 aPt
= rPoly
[ nIndex
+ 1];
2098 sal_Int32 nAdjustValue
;
2100 nAdjustValue
= ( aPt
.Y()-aStart
.Y())* 21600 /(aEnd
.Y()-aStart
.Y());
2102 nAdjustValue
= ( aPt
.X()-aStart
.X() )* 21600 /(aEnd
.X()-aStart
.X());
2104 return nAdjustValue
;
2108 static void lcl_Rotate(Degree100 nAngle
, Point center
, Point
& pt
)
2110 nAngle
= NormAngle36000(nAngle
);
2113 switch (nAngle
.get())
2134 sal_Int32 x0
=pt
.X()-center
.X();
2135 sal_Int32 y0
=pt
.Y()-center
.Y();
2136 pt
.setX(center
.X()+ x0
*cs
-y0
*sn
);
2137 pt
.setY(center
.Y()+ y0
*cs
+x0
*sn
);
2140 FlipV defines that the shape will be flipped vertically about the center of its bounding box.
2141 Generally, draw the connector from top to bottom, from left to right when meet the adjust value,
2142 but when (X1>X2 or Y1>Y2),the draw director must be reverse, FlipV or FlipH should be set to true.
2144 static bool lcl_GetAngle(tools::Polygon
&rPoly
, ShapeFlag
& rShapeFlags
,sal_Int32
& nAngle
)
2146 Point aStart
= rPoly
[0];
2147 Point aEnd
= rPoly
[rPoly
.GetSize()-1];
2148 nAngle
= ( rPoly
[1].X() == aStart
.X() ) ? 9000: 0 ;
2149 Point
p1(aStart
.X(),aStart
.Y());
2150 Point
p2(aEnd
.X(),aEnd
.Y());
2153 Point
center((aEnd
.X()+aStart
.X())>>1,(aEnd
.Y()+aStart
.Y())>>1);
2154 lcl_Rotate(Degree100(-nAngle
), center
,p1
);
2155 lcl_Rotate(Degree100(-nAngle
), center
,p2
);
2157 if ( p1
.X() > p2
.X() )
2160 rShapeFlags
|= ShapeFlag::FlipV
;
2162 rShapeFlags
|= ShapeFlag::FlipH
;
2165 if ( p1
.Y() > p2
.Y() )
2168 rShapeFlags
|= ShapeFlag::FlipH
;
2170 rShapeFlags
|= ShapeFlag::FlipV
;
2173 if ( (rShapeFlags
&ShapeFlag::FlipH
) && (rShapeFlags
&ShapeFlag::FlipV
) )
2175 rShapeFlags
&= ~ShapeFlag( ShapeFlag::FlipH
| ShapeFlag::FlipV
);
2181 // Set angle properties
2184 nAngle
&=~0xffff; // round nAngle to whole number of degrees
2189 bool EscherPropertyContainer::CreateConnectorProperties(
2190 const uno::Reference
<drawing::XShape
> & rXShape
,
2191 EscherSolverContainer
& rSolverContainer
, awt::Rectangle
& rGeoRect
,
2192 sal_uInt16
& rShapeType
, ShapeFlag
& rShapeFlags
)
2194 bool bRetValue
= false;
2196 rShapeFlags
= ShapeFlag::NONE
;
2200 uno::Reference
<beans::XPropertySet
> aXPropSet
;
2201 uno::Reference
<drawing::XShape
> aShapeA
, aShapeB
;
2202 uno::Any
aAny( rXShape
->queryInterface( cppu::UnoType
<beans::XPropertySet
>::get()));
2203 if ( aAny
>>= aXPropSet
)
2205 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"EdgeKind"_ustr
, true ) )
2207 drawing::ConnectorType eCt
;
2209 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"EdgeStartPoint"_ustr
) )
2211 awt::Point aStartPoint
= *o3tl::doAccess
<awt::Point
>(aAny
);
2212 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"EdgeEndPoint"_ustr
) )
2214 awt::Point aEndPoint
= *o3tl::doAccess
<awt::Point
>(aAny
);
2216 rShapeFlags
= ShapeFlag::HaveAnchor
| ShapeFlag::HaveShapeProperty
| ShapeFlag::Connector
;
2217 rGeoRect
= awt::Rectangle( aStartPoint
.X
, aStartPoint
.Y
,
2218 ( aEndPoint
.X
- aStartPoint
.X
) + 1, ( aEndPoint
.Y
- aStartPoint
.Y
) + 1 );
2219 // set standard's FLIP in below code
2220 if ( eCt
!= drawing::ConnectorType_STANDARD
)
2222 if ( rGeoRect
.Height
< 0 ) // justify
2224 rShapeFlags
|= ShapeFlag::FlipV
;
2225 rGeoRect
.Y
= aEndPoint
.Y
;
2226 rGeoRect
.Height
= -rGeoRect
.Height
;
2228 if ( rGeoRect
.Width
< 0 )
2230 rShapeFlags
|= ShapeFlag::FlipH
;
2231 rGeoRect
.X
= aEndPoint
.X
;
2232 rGeoRect
.Width
= -rGeoRect
.Width
;
2235 sal_uInt32 nAdjustValue1
, nAdjustValue2
;
2236 nAdjustValue1
= nAdjustValue2
= 0x2a30;
2238 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"EdgeStartConnection"_ustr
) )
2240 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"EdgeEndConnection"_ustr
) )
2242 rSolverContainer
.AddConnector( rXShape
, aStartPoint
, aShapeA
, aEndPoint
, aShapeB
);
2245 case drawing::ConnectorType_CURVE
:
2247 rShapeType
= ESCHER_ShpInst_CurvedConnector3
;
2248 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleCurved
);
2249 AddOpt( ESCHER_Prop_adjustValue
, nAdjustValue1
);
2250 AddOpt( ESCHER_Prop_adjust2Value
, -static_cast<sal_Int32
>(nAdjustValue2
) );
2254 case drawing::ConnectorType_STANDARD
:// Connector 2->5
2256 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"PolyPolygonBezier"_ustr
) )
2258 tools::PolyPolygon aPolyPolygon
= GetPolyPolygon( aAny
);
2259 tools::Polygon aPoly
;
2260 if ( aPolyPolygon
.Count() > 0 )
2262 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleBent
);
2263 aPoly
= aPolyPolygon
[ 0 ];
2264 sal_Int32 nAdjCount
= lcl_GetAdjustValueCount( aPoly
);
2265 rShapeType
= static_cast<sal_uInt16
>( ESCHER_ShpInst_BentConnector2
+ nAdjCount
);
2266 for ( sal_Int32 i
= 0 ; i
< nAdjCount
; ++ i
)
2267 AddOpt( static_cast<sal_uInt16
>( ESCHER_Prop_adjustValue
+i
) , lcl_GetConnectorAdjustValue( aPoly
, i
) );
2270 if (lcl_GetAngle(aPoly
,rShapeFlags
,nAngle
))
2272 AddOpt( ESCHER_Prop_Rotation
, nAngle
);
2277 rShapeType
= ESCHER_ShpInst_BentConnector3
;
2278 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleBent
);
2283 case drawing::ConnectorType_LINE
:
2284 case drawing::ConnectorType_LINES
: // Connector 2->5
2286 rShapeType
= ESCHER_ShpInst_StraightConnector1
;
2287 AddOpt( ESCHER_Prop_cxstyle
, ESCHER_cxstyleStraight
);
2291 CreateLineProperties( aXPropSet
, false );
2301 void EscherPropertyContainer::CreateShadowProperties(
2302 const uno::Reference
<beans::XPropertySet
> & rXPropSet
)
2306 sal_uInt32 nLineFlags
= 0; // default : shape has no line
2307 sal_uInt32 nFillFlags
= 0x10; // shape is filled
2309 GetOpt( ESCHER_Prop_fNoLineDrawDash
, nLineFlags
);
2310 GetOpt( ESCHER_Prop_fNoFillHitTest
, nFillFlags
);
2313 bool bGraphic
= GetOpt( DFF_Prop_pib
, nDummy
) || GetOpt( DFF_Prop_pibName
, nDummy
) || GetOpt( DFF_Prop_pibFlags
, nDummy
);
2315 sal_uInt32 nShadowFlags
= 0x20000;
2316 if ( ( nLineFlags
& 8 ) || ( nFillFlags
& 0x10 ) || bGraphic
)
2318 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"Shadow"_ustr
, true ) )
2320 bool bHasShadow
= false; // shadow is possible only if at least a fillcolor, linecolor or graphic is set
2321 if ( (aAny
>>= bHasShadow
) && bHasShadow
)
2324 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"ShadowColor"_ustr
) )
2325 AddOpt( ESCHER_Prop_shadowColor
, ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aAny
) ) );
2326 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"ShadowXDistance"_ustr
) )
2327 AddOpt( ESCHER_Prop_shadowOffsetX
, *o3tl::doAccess
<sal_Int32
>(aAny
) * 360 );
2328 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"ShadowYDistance"_ustr
) )
2329 AddOpt( ESCHER_Prop_shadowOffsetY
, *o3tl::doAccess
<sal_Int32
>(aAny
) * 360 );
2330 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, rXPropSet
, u
"ShadowTransparence"_ustr
) )
2331 AddOpt( ESCHER_Prop_shadowOpacity
, 0x10000 - (static_cast<sal_uInt32
>(*o3tl::doAccess
<sal_uInt16
>(aAny
)) * 655 ) );
2335 AddOpt( ESCHER_Prop_fshadowObscured
, nShadowFlags
);
2338 sal_Int32
EscherPropertyContainer::GetValueForEnhancedCustomShapeParameter( const drawing::EnhancedCustomShapeParameter
& rParameter
,
2339 const std::vector
< sal_Int32
>& rEquationOrder
, bool bAdjustTrans
)
2341 sal_Int32 nValue
= 0;
2342 if ( rParameter
.Value
.getValueTypeClass() == uno::TypeClass_DOUBLE
)
2345 if ( rParameter
.Value
>>= fValue
)
2346 nValue
= static_cast<sal_Int32
>(fValue
);
2349 rParameter
.Value
>>= nValue
;
2351 switch( rParameter
.Type
)
2353 case drawing::EnhancedCustomShapeParameterType::EQUATION
:
2355 size_t nIndex
= static_cast<size_t>(nValue
);
2356 OSL_ASSERT(nIndex
< rEquationOrder
.size());
2357 if ( nIndex
< rEquationOrder
.size() )
2359 nValue
= static_cast<sal_uInt16
>(rEquationOrder
[ nIndex
]);
2360 nValue
|= sal_uInt32(0x80000000);
2364 case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT
:
2368 sal_uInt32 nAdjustValue
= 0;
2369 bool bGot
= GetOpt(static_cast<sal_uInt16
>( DFF_Prop_adjustValue
+ nValue
), nAdjustValue
);
2370 if(bGot
) nValue
= static_cast<sal_Int32
>(nAdjustValue
);
2374 case drawing::EnhancedCustomShapeParameterType::NORMAL
:
2377 /* not sure if it is allowed to set following values
2378 (but they are not yet used)
2379 case drawing::EnhancedCustomShapeParameterType::BOTTOM :
2380 case drawing::EnhancedCustomShapeParameterType::RIGHT :
2381 case drawing::EnhancedCustomShapeParameterType::TOP :
2382 case drawing::EnhancedCustomShapeParameterType::LEFT :
2388 static bool GetValueForEnhancedCustomShapeHandleParameter( sal_Int32
& nRetValue
, const drawing::EnhancedCustomShapeParameter
& rParameter
)
2390 bool bSpecial
= false;
2392 if ( rParameter
.Value
.getValueTypeClass() == uno::TypeClass_DOUBLE
)
2395 if ( rParameter
.Value
>>= fValue
)
2396 nRetValue
= static_cast<sal_Int32
>(fValue
);
2399 rParameter
.Value
>>= nRetValue
;
2401 switch( rParameter
.Type
)
2403 case drawing::EnhancedCustomShapeParameterType::EQUATION
:
2409 case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT
:
2415 case drawing::EnhancedCustomShapeParameterType::TOP
:
2416 case drawing::EnhancedCustomShapeParameterType::LEFT
:
2422 case drawing::EnhancedCustomShapeParameterType::RIGHT
:
2423 case drawing::EnhancedCustomShapeParameterType::BOTTOM
:
2429 case drawing::EnhancedCustomShapeParameterType::NORMAL
:
2438 static void ConvertEnhancedCustomShapeEquation(
2439 const SdrObjCustomShape
& rSdrObjCustomShape
,
2440 std::vector
< EnhancedCustomShapeEquation
>& rEquations
,
2441 std::vector
< sal_Int32
>& rEquationOrder
)
2443 uno::Sequence
< OUString
> sEquationSource
;
2444 const SdrCustomShapeGeometryItem
& rGeometryItem
=
2445 rSdrObjCustomShape
.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
2446 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( u
"Equations"_ustr
);
2448 *pAny
>>= sEquationSource
;
2449 sal_Int32 nEquationSourceCount
= sEquationSource
.getLength();
2450 if ( !(nEquationSourceCount
&& (nEquationSourceCount
<= 128)) )
2454 for ( i
= 0; i
< nEquationSourceCount
; i
++ )
2456 EnhancedCustomShape2d
aCustomShape2d(
2457 const_cast< SdrObjCustomShape
& >(rSdrObjCustomShape
));
2460 std::shared_ptr
< EnhancedCustomShape::ExpressionNode
> aExpressNode(
2461 EnhancedCustomShape::FunctionParser::parseFunction(
2462 sEquationSource
[ i
], aCustomShape2d
));
2463 drawing::EnhancedCustomShapeParameter
aPara( aExpressNode
->fillNode( rEquations
, nullptr, 0 ) );
2464 if ( aPara
.Type
!= drawing::EnhancedCustomShapeParameterType::EQUATION
)
2466 EnhancedCustomShapeEquation aEquation
;
2467 aEquation
.nOperation
= 0;
2468 EnhancedCustomShape::FillEquationParameter( aPara
, 0, aEquation
);
2469 rEquations
.push_back( aEquation
);
2472 catch ( const EnhancedCustomShape::ParseError
& )
2474 EnhancedCustomShapeEquation aEquation
; // ups, we should not be here,
2475 aEquation
.nOperation
= 0; // creating a default equation with value 1
2476 aEquation
.nPara
[ 0 ] = 1; // hoping that this will not break anything
2477 rEquations
.push_back( aEquation
);
2481 EnhancedCustomShapeEquation aEquation
; // #i112309# EnhancedCustomShape::Parse error
2482 aEquation
.nOperation
= 0; // not caught on linux platform
2483 aEquation
.nPara
[ 0 ] = 1;
2484 rEquations
.push_back( aEquation
);
2486 rEquationOrder
.push_back( rEquations
.size() - 1 );
2488 // now updating our old equation indices, they are marked with a bit in the hiword of nOperation
2489 for (auto & equation
: rEquations
)
2491 sal_uInt32 nMask
= 0x20000000;
2492 for( i
= 0; i
< 3; i
++ )
2494 if ( equation
.nOperation
& nMask
)
2496 equation
.nOperation
^= nMask
;
2497 const size_t nIndex(equation
.nPara
[ i
] & 0x3ff);
2499 // #i124661# check index access, there are cases where this is out of bound leading
2500 // to errors up to crashes when executed
2501 if(nIndex
< rEquationOrder
.size())
2503 equation
.nPara
[ i
] = rEquationOrder
[ nIndex
] | 0x400;
2507 OSL_ENSURE(false, "Attempted out of bound access to rEquationOrder of CustomShape (!)");
2510 nMask
= sal_uInt32(nMask
<< 1);
2515 bool EscherPropertyContainer::IsDefaultObject(
2516 const SdrObjCustomShape
& rSdrObjCustomShape
,
2517 const MSO_SPT eShapeType
)
2521 // if the custom shape is not default shape of ppt, return false;
2522 case mso_sptTearDrop
:
2529 return rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Equations
)
2530 && rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Viewbox
)
2531 && rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Path
)
2532 && rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Gluepoints
)
2533 && rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::Segments
)
2534 && rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchX
)
2535 && rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::StretchY
)
2536 && rSdrObjCustomShape
.IsDefaultGeometry( SdrObjCustomShape::DefaultType::TextFrames
);
2539 void EscherPropertyContainer::LookForPolarHandles( const MSO_SPT eShapeType
, sal_Int32
& nAdjustmentsWhichNeedsToBeConverted
)
2541 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent( eShapeType
);
2542 if ( !pDefCustomShape
|| pDefCustomShape
->pHandles
.empty() )
2545 sal_Int32 k
, nkCount
= pDefCustomShape
->pHandles
.size();
2546 for (k
= 0; k
< nkCount
; k
++)
2548 const SvxMSDffHandle
* pData
= &pDefCustomShape
->pHandles
[k
];
2549 if ( pData
->nFlags
& SvxMSDffHandleFlags::POLAR
)
2551 if ( ( pData
->nPositionY
>= 0x256 ) || ( pData
->nPositionY
<= 0x107 ) )
2552 nAdjustmentsWhichNeedsToBeConverted
|= ( 1 << k
);
2557 bool EscherPropertyContainer::GetAdjustmentValue( const drawing::EnhancedCustomShapeAdjustmentValue
& rkProp
, sal_Int32 nIndex
, sal_Int32 nAdjustmentsWhichNeedsToBeConverted
, sal_Int32
& nValue
)
2559 if ( rkProp
.State
!= beans::PropertyState_DIRECT_VALUE
)
2562 bool bUseFixedFloat
= ( nAdjustmentsWhichNeedsToBeConverted
& ( 1 << nIndex
) ) != 0;
2563 if ( rkProp
.Value
.getValueTypeClass() == uno::TypeClass_DOUBLE
)
2566 rkProp
.Value
>>= fValue
;
2567 if ( bUseFixedFloat
)
2569 nValue
= static_cast<sal_Int32
>(fValue
);
2573 rkProp
.Value
>>= nValue
;
2574 if ( bUseFixedFloat
)
2581 void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeType
, const uno::Reference
< drawing::XShape
> & rXShape
, bool bOOXML
)
2583 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
2584 if ( !aXPropSet
.is() )
2587 SdrObjCustomShape
* pSdrObjCustomShape
= dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(rXShape
));
2588 if(!pSdrObjCustomShape
)
2593 SdrObjCustomShape
& rSdrObjCustomShape
= *pSdrObjCustomShape
;
2594 uno::Any aGeoPropSet
= aXPropSet
->getPropertyValue( u
"CustomShapeGeometry"_ustr
);
2595 uno::Sequence
< beans::PropertyValue
> aGeoPropSeq
;
2596 if ( !(aGeoPropSet
>>= aGeoPropSeq
) )
2599 static constexpr OUStringLiteral
sViewBox ( u
"ViewBox" );
2600 static constexpr OUStringLiteral
sTextRotateAngle ( u
"TextRotateAngle" );
2601 static constexpr OUString
sExtrusion ( u
"Extrusion"_ustr
);
2602 static constexpr OUStringLiteral
sEquations ( u
"Equations" );
2603 static constexpr OUStringLiteral
sPath ( u
"Path" );
2604 static constexpr OUString
sTextPath ( u
"TextPath"_ustr
);
2605 static constexpr OUStringLiteral
sHandles ( u
"Handles" );
2606 static constexpr OUStringLiteral
sAdjustmentValues ( u
"AdjustmentValues" );
2608 bool bAdjustmentValuesProp
= false;
2609 uno::Any aAdjustmentValuesProp
;
2610 bool bPathCoordinatesProp
= false;
2611 uno::Any aPathCoordinatesProp
;
2613 sal_Int32 nAdjustmentsWhichNeedsToBeConverted
= 0;
2614 uno::Sequence
< beans::PropertyValues
> aHandlesPropSeq
;
2615 bool bPredefinedHandlesUsed
= true;
2616 const bool bIsDefaultObject(
2621 bool bUseDefaultObject
= false;
2624 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent(eShapeType
);
2626 bUseDefaultObject
= true;
2629 // convert property "Equations" into std::vector< EnhancedCustomShapeEquationEquation >
2630 std::vector
< EnhancedCustomShapeEquation
> aEquations
;
2631 std::vector
< sal_Int32
> aEquationOrder
;
2632 ConvertEnhancedCustomShapeEquation(
2637 sal_Int32 i
, nCount
= aGeoPropSeq
.getLength();
2638 for ( i
= 0; i
< nCount
; i
++ )
2640 const beans::PropertyValue
& rProp
= aGeoPropSeq
[ i
];
2641 if ( rProp
.Name
== sViewBox
)
2643 if (!bIsDefaultObject
&& !bUseDefaultObject
)
2645 awt::Rectangle aViewBox
;
2646 if ( rProp
.Value
>>= aViewBox
)
2648 AddOpt( DFF_Prop_geoLeft
, aViewBox
.X
);
2649 AddOpt( DFF_Prop_geoTop
, aViewBox
.Y
);
2650 AddOpt( DFF_Prop_geoRight
, aViewBox
.X
+ aViewBox
.Width
);
2651 AddOpt( DFF_Prop_geoBottom
,aViewBox
.Y
+ aViewBox
.Height
);
2655 else if ( rProp
.Name
== sTextRotateAngle
)
2658 if ( rProp
.Value
>>= f
)
2660 double fTextRotateAngle
= fmod( f
, 360.0 );
2661 if ( fTextRotateAngle
< 0 )
2662 fTextRotateAngle
= 360 + fTextRotateAngle
;
2663 if ( ( fTextRotateAngle
< 271.0 ) && ( fTextRotateAngle
> 269.0 ) )
2664 AddOpt( DFF_Prop_cdirFont
, mso_cdir90
);
2665 else if ( ( fTextRotateAngle
< 181.0 ) && ( fTextRotateAngle
> 179.0 ) )
2666 AddOpt( DFF_Prop_cdirFont
, mso_cdir180
);
2667 else if ( ( fTextRotateAngle
< 91.0 ) && ( fTextRotateAngle
> 79.0 ) )
2668 AddOpt( DFF_Prop_cdirFont
, mso_cdir270
);
2671 else if ( rProp
.Name
== sExtrusion
)
2673 uno::Sequence
< beans::PropertyValue
> aExtrusionPropSeq
;
2674 if ( rProp
.Value
>>= aExtrusionPropSeq
)
2676 sal_uInt32 nLightFaceFlagsOrg
, nLightFaceFlags
;
2677 sal_uInt32 nFillHarshFlagsOrg
, nFillHarshFlags
;
2678 nLightFaceFlagsOrg
= nLightFaceFlags
= 0x000001;
2679 nFillHarshFlagsOrg
= nFillHarshFlags
= 0x00001e;
2680 if ( GetOpt( DFF_Prop_fc3DLightFace
, nLightFaceFlags
) )
2681 nLightFaceFlagsOrg
= nLightFaceFlags
;
2682 if ( GetOpt( DFF_Prop_fc3DFillHarsh
, nFillHarshFlags
) )
2683 nFillHarshFlagsOrg
= nFillHarshFlags
;
2685 sal_Int32 r
, nrCount
= aExtrusionPropSeq
.getLength();
2686 for ( r
= 0; r
< nrCount
; r
++ )
2688 const beans::PropertyValue
& rrProp
= aExtrusionPropSeq
[ r
];
2690 if ( rrProp
.Name
== sExtrusion
)
2693 if ( rrProp
.Value
>>= bExtrusionOn
)
2695 nLightFaceFlags
|= 0x80000;
2697 nLightFaceFlags
|= 8;
2699 nLightFaceFlags
&=~8;
2702 else if ( rrProp
.Name
== "Brightness" )
2704 double fExtrusionBrightness
= 0;
2705 if ( rrProp
.Value
>>= fExtrusionBrightness
)
2706 AddOpt( DFF_Prop_c3DAmbientIntensity
, static_cast<sal_Int32
>( fExtrusionBrightness
* 655.36 ) );
2708 else if ( rrProp
.Name
== "Depth" )
2711 double fFraction
= 0;
2712 drawing::EnhancedCustomShapeParameterPair aDepthParaPair
;
2713 if ( ( rrProp
.Value
>>= aDepthParaPair
) && ( aDepthParaPair
.First
.Value
>>= fDepth
) && ( aDepthParaPair
.Second
.Value
>>= fFraction
) )
2715 double fForeDepth
= fDepth
* fFraction
;
2716 double fBackDepth
= fDepth
- fForeDepth
;
2718 fBackDepth
*= 360.0;
2719 AddOpt( DFF_Prop_c3DExtrudeBackward
, static_cast<sal_Int32
>(fBackDepth
) );
2721 if ( fForeDepth
!= 0.0 )
2723 fForeDepth
*= 360.0;
2724 AddOpt( DFF_Prop_c3DExtrudeForward
, static_cast<sal_Int32
>(fForeDepth
) );
2728 else if ( rrProp
.Name
== "Diffusion" )
2730 double fExtrusionDiffusion
= 0;
2731 if ( rrProp
.Value
>>= fExtrusionDiffusion
)
2732 AddOpt( DFF_Prop_c3DDiffuseAmt
, static_cast<sal_Int32
>( fExtrusionDiffusion
* 655.36 ) );
2734 else if ( rrProp
.Name
== "NumberOfLineSegments" )
2736 sal_Int32 nExtrusionNumberOfLineSegments
= 0;
2737 if ( rrProp
.Value
>>= nExtrusionNumberOfLineSegments
)
2738 AddOpt( DFF_Prop_c3DTolerance
, nExtrusionNumberOfLineSegments
);
2740 else if ( rrProp
.Name
== "LightFace" )
2742 bool bExtrusionLightFace
;
2743 if ( rrProp
.Value
>>= bExtrusionLightFace
)
2745 nLightFaceFlags
|= 0x10000;
2746 if ( bExtrusionLightFace
)
2747 nLightFaceFlags
|= 1;
2749 nLightFaceFlags
&=~1;
2752 else if ( rrProp
.Name
== "FirstLightHarsh" )
2754 bool bExtrusionFirstLightHarsh
;
2755 if ( rrProp
.Value
>>= bExtrusionFirstLightHarsh
)
2757 nFillHarshFlags
|= 0x20000;
2758 if ( bExtrusionFirstLightHarsh
)
2759 nFillHarshFlags
|= 2;
2761 nFillHarshFlags
&=~2;
2764 else if ( rrProp
.Name
== "SecondLightHarsh" )
2766 bool bExtrusionSecondLightHarsh
;
2767 if ( rrProp
.Value
>>= bExtrusionSecondLightHarsh
)
2769 nFillHarshFlags
|= 0x10000;
2770 if ( bExtrusionSecondLightHarsh
)
2771 nFillHarshFlags
|= 1;
2773 nFillHarshFlags
&=~1;
2776 else if ( rrProp
.Name
== "FirstLightLevel" )
2778 double fExtrusionFirstLightLevel
= 0;
2779 if ( rrProp
.Value
>>= fExtrusionFirstLightLevel
)
2780 AddOpt( DFF_Prop_c3DKeyIntensity
, static_cast<sal_Int32
>( fExtrusionFirstLightLevel
* 655.36 ) );
2782 else if ( rrProp
.Name
== "SecondLightLevel" )
2784 double fExtrusionSecondLightLevel
= 0;
2785 if ( rrProp
.Value
>>= fExtrusionSecondLightLevel
)
2786 AddOpt( DFF_Prop_c3DFillIntensity
, static_cast<sal_Int32
>( fExtrusionSecondLightLevel
* 655.36 ) );
2788 else if ( rrProp
.Name
== "FirstLightDirection" )
2790 drawing::Direction3D aExtrusionFirstLightDirection
;
2791 if ( rrProp
.Value
>>= aExtrusionFirstLightDirection
)
2793 AddOpt( DFF_Prop_c3DKeyX
, static_cast<sal_Int32
>(aExtrusionFirstLightDirection
.DirectionX
) );
2794 AddOpt( DFF_Prop_c3DKeyY
, static_cast<sal_Int32
>(aExtrusionFirstLightDirection
.DirectionY
) );
2795 AddOpt( DFF_Prop_c3DKeyZ
, static_cast<sal_Int32
>(aExtrusionFirstLightDirection
.DirectionZ
) );
2798 else if ( rrProp
.Name
== "SecondLightDirection" )
2800 drawing::Direction3D aExtrusionSecondLightPosition
;
2801 if ( rrProp
.Value
>>= aExtrusionSecondLightPosition
)
2803 AddOpt( DFF_Prop_c3DFillX
, static_cast<sal_Int32
>(aExtrusionSecondLightPosition
.DirectionX
) );
2804 AddOpt( DFF_Prop_c3DFillY
, static_cast<sal_Int32
>(aExtrusionSecondLightPosition
.DirectionY
) );
2805 AddOpt( DFF_Prop_c3DFillZ
, static_cast<sal_Int32
>(aExtrusionSecondLightPosition
.DirectionZ
) );
2808 else if ( rrProp
.Name
== "Metal" )
2810 bool bExtrusionMetal
;
2811 if ( rrProp
.Value
>>= bExtrusionMetal
)
2813 nLightFaceFlags
|= 0x40000;
2814 if ( bExtrusionMetal
)
2815 nLightFaceFlags
|= 4;
2817 nLightFaceFlags
&=~4;
2820 else if ( rrProp
.Name
== "ShadeMode" )
2822 drawing::ShadeMode eExtrusionShadeMode
;
2823 if ( rrProp
.Value
>>= eExtrusionShadeMode
)
2825 sal_uInt32 nRenderMode
;
2826 switch( eExtrusionShadeMode
)
2829 case drawing::ShadeMode_FLAT
:
2830 case drawing::ShadeMode_PHONG
:
2831 case drawing::ShadeMode_SMOOTH
:
2832 nRenderMode
= mso_FullRender
;
2834 case drawing::ShadeMode_DRAFT
:
2836 nRenderMode
= mso_Wireframe
;
2840 AddOpt( DFF_Prop_c3DRenderMode
, nRenderMode
);
2843 else if ( rrProp
.Name
== "RotateAngle" )
2845 double fExtrusionAngleX
= 0;
2846 double fExtrusionAngleY
= 0;
2847 drawing::EnhancedCustomShapeParameterPair aRotateAnglePair
;
2848 if ( ( rrProp
.Value
>>= aRotateAnglePair
) && ( aRotateAnglePair
.First
.Value
>>= fExtrusionAngleX
) && ( aRotateAnglePair
.Second
.Value
>>= fExtrusionAngleY
) )
2850 fExtrusionAngleX
*= 65536;
2851 fExtrusionAngleY
*= 65536;
2852 AddOpt( DFF_Prop_c3DXRotationAngle
, static_cast<sal_Int32
>(fExtrusionAngleX
) );
2853 AddOpt( DFF_Prop_c3DYRotationAngle
, static_cast<sal_Int32
>(fExtrusionAngleY
) );
2856 else if ( rrProp
.Name
== "RotationCenter" )
2858 drawing::Direction3D aExtrusionRotationCenter
;
2859 if ( rrProp
.Value
>>= aExtrusionRotationCenter
)
2861 // tdf#145904 X- and Y-component is fraction, Z-component in EMU
2862 AddOpt( DFF_Prop_c3DRotationCenterX
, static_cast<sal_Int32
>( aExtrusionRotationCenter
.DirectionX
* 65536.0 ) );
2863 AddOpt( DFF_Prop_c3DRotationCenterY
, static_cast<sal_Int32
>( aExtrusionRotationCenter
.DirectionY
* 65536.0 ) );
2864 AddOpt( DFF_Prop_c3DRotationCenterZ
, static_cast<sal_Int32
>( aExtrusionRotationCenter
.DirectionZ
* 360.0 ) );
2865 nFillHarshFlags
&=~8; // don't use AutoRotationCenter;
2868 else if ( rrProp
.Name
== "Shininess" )
2870 double fExtrusionShininess
= 0;
2871 if ( rrProp
.Value
>>= fExtrusionShininess
)
2873 // ODF to MS Office conversion invers to msdffimp.cxx
2874 fExtrusionShininess
= std::round(fExtrusionShininess
/ 10.0);
2875 AddOpt( DFF_Prop_c3DShininess
, static_cast<sal_Int32
>(fExtrusionShininess
) );
2878 else if ( rrProp
.Name
== "Skew" )
2880 double fSkewAmount
= 0;
2881 double fSkewAngle
= 0;
2882 drawing::EnhancedCustomShapeParameterPair aSkewParaPair
;
2883 if ( ( rrProp
.Value
>>= aSkewParaPair
) && ( aSkewParaPair
.First
.Value
>>= fSkewAmount
) && ( aSkewParaPair
.Second
.Value
>>= fSkewAngle
) )
2885 AddOpt( DFF_Prop_c3DSkewAmount
, static_cast<sal_Int32
>(fSkewAmount
) );
2886 AddOpt( DFF_Prop_c3DSkewAngle
, static_cast<sal_Int32
>( fSkewAngle
* 65536 ) );
2889 else if ( rrProp
.Name
== "Specularity" )
2891 double fExtrusionSpecularity
= 0;
2892 if ( rrProp
.Value
>>= fExtrusionSpecularity
)
2893 AddOpt( DFF_Prop_c3DSpecularAmt
, static_cast<sal_Int32
>( fExtrusionSpecularity
* 655.36 ) );
2895 else if ( rrProp
.Name
== "ProjectionMode" )
2897 drawing::ProjectionMode eExtrusionProjectionMode
;
2898 if ( rrProp
.Value
>>= eExtrusionProjectionMode
)
2900 nFillHarshFlags
|= 0x40000;
2901 if ( eExtrusionProjectionMode
== drawing::ProjectionMode_PARALLEL
)
2902 nFillHarshFlags
|= 4;
2904 nFillHarshFlags
&=~4;
2907 else if ( rrProp
.Name
== "ViewPoint" )
2909 drawing::Position3D aExtrusionViewPoint
;
2910 if ( rrProp
.Value
>>= aExtrusionViewPoint
)
2912 aExtrusionViewPoint
.PositionX
*= 360.0;
2913 aExtrusionViewPoint
.PositionY
*= 360.0;
2914 aExtrusionViewPoint
.PositionZ
*= 360.0;
2915 AddOpt( DFF_Prop_c3DXViewpoint
, static_cast<sal_Int32
>(aExtrusionViewPoint
.PositionX
) );
2916 AddOpt( DFF_Prop_c3DYViewpoint
, static_cast<sal_Int32
>(aExtrusionViewPoint
.PositionY
) );
2917 AddOpt( DFF_Prop_c3DZViewpoint
, static_cast<sal_Int32
>(aExtrusionViewPoint
.PositionZ
) );
2920 else if ( rrProp
.Name
== "Origin" )
2922 double fExtrusionOriginX
= 0;
2923 double fExtrusionOriginY
= 0;
2924 drawing::EnhancedCustomShapeParameterPair aOriginPair
;
2925 if ( ( rrProp
.Value
>>= aOriginPair
) && ( aOriginPair
.First
.Value
>>= fExtrusionOriginX
) && ( aOriginPair
.Second
.Value
>>= fExtrusionOriginY
) )
2927 AddOpt( DFF_Prop_c3DOriginX
, static_cast<sal_Int32
>( fExtrusionOriginX
* 65536 ) );
2928 AddOpt( DFF_Prop_c3DOriginY
, static_cast<sal_Int32
>( fExtrusionOriginY
* 65536 ) );
2931 else if ( rrProp
.Name
== "Color" )
2933 bool bExtrusionColor
;
2934 if ( rrProp
.Value
>>= bExtrusionColor
)
2936 nLightFaceFlags
|= 0x20000;
2937 if ( bExtrusionColor
)
2939 nLightFaceFlags
|= 2;
2940 uno::Any aFillColor2
;
2941 if ( EscherPropertyValueHelper::GetPropertyValue( aFillColor2
, aXPropSet
, u
"FillColor2"_ustr
, true ) )
2943 sal_uInt32 nFillColor
= ImplGetColor( *o3tl::doAccess
<sal_uInt32
>(aFillColor2
) );
2944 AddOpt( DFF_Prop_c3DExtrusionColor
, nFillColor
);
2948 nLightFaceFlags
&=~2;
2952 if ( nLightFaceFlags
!= nLightFaceFlagsOrg
)
2953 AddOpt( DFF_Prop_fc3DLightFace
, nLightFaceFlags
);
2954 if ( nFillHarshFlags
!= nFillHarshFlagsOrg
)
2955 AddOpt( DFF_Prop_fc3DFillHarsh
, nFillHarshFlags
);
2958 else if ( rProp
.Name
== sEquations
)
2960 if (!bIsDefaultObject
&& !bUseDefaultObject
)
2962 sal_uInt16 nElements
= static_cast<sal_uInt16
>(aEquations
.size());
2965 sal_uInt16 nElementSize
= 8;
2966 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
2967 SvMemoryStream
aMemStrm( nStreamSize
);
2968 aMemStrm
.WriteUInt16( nElements
)
2969 .WriteUInt16( nElements
)
2970 .WriteUInt16( nElementSize
);
2972 for (auto const& equation
: aEquations
)
2974 aMemStrm
.WriteUInt16( equation
.nOperation
)
2977 equation
.nPara
[ 0 ], sal_Int32(SAL_MIN_INT16
),
2978 sal_Int32(SAL_MAX_INT16
)) )
2981 equation
.nPara
[ 1 ], sal_Int32(SAL_MIN_INT16
),
2982 sal_Int32(SAL_MAX_INT16
)) )
2985 equation
.nPara
[ 2 ], sal_Int32(SAL_MIN_INT16
),
2986 sal_Int32(SAL_MAX_INT16
)) );
2989 AddOpt(DFF_Prop_pFormulas
, true, 6, aMemStrm
);
2993 AddOpt(DFF_Prop_pFormulas
, 0, true);
2997 else if ( rProp
.Name
== sPath
)
2999 uno::Sequence
< beans::PropertyValue
> aPathPropSeq
;
3000 if ( rProp
.Value
>>= aPathPropSeq
)
3002 sal_uInt32 nPathFlags
, nPathFlagsOrg
;
3003 nPathFlagsOrg
= nPathFlags
= 0x39;
3004 if ( GetOpt( DFF_Prop_fFillOK
, nPathFlags
) )
3005 nPathFlagsOrg
= nPathFlags
;
3007 sal_Int32 r
, nrCount
= aPathPropSeq
.getLength();
3008 for ( r
= 0; r
< nrCount
; r
++ )
3010 const beans::PropertyValue
& rrProp
= aPathPropSeq
[ r
];
3012 if ( rrProp
.Name
== "ExtrusionAllowed" )
3014 bool bExtrusionAllowed
;
3015 if ( rrProp
.Value
>>= bExtrusionAllowed
)
3017 nPathFlags
|= 0x100000;
3018 if ( bExtrusionAllowed
)
3024 else if ( rrProp
.Name
== "ConcentricGradientFillAllowed" )
3026 bool bConcentricGradientFillAllowed
;
3027 if ( rrProp
.Value
>>= bConcentricGradientFillAllowed
)
3029 nPathFlags
|= 0x20000;
3030 if ( bConcentricGradientFillAllowed
)
3036 else if ( rrProp
.Name
== "TextPathAllowed" )
3038 bool bTextPathAllowed
;
3039 if ( rrProp
.Value
>>= bTextPathAllowed
)
3041 nPathFlags
|= 0x40000;
3042 if ( bTextPathAllowed
)
3048 else if ( rrProp
.Name
== "Coordinates" )
3050 if (!bIsDefaultObject
&& !bUseDefaultObject
)
3052 aPathCoordinatesProp
= rrProp
.Value
;
3053 bPathCoordinatesProp
= true;
3056 else if ( rrProp
.Name
== "GluePoints" )
3058 if (!bIsDefaultObject
&& !bUseDefaultObject
)
3060 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> aGluePoints
;
3061 if ( rrProp
.Value
>>= aGluePoints
)
3063 // creating the vertices
3064 sal_uInt16 nElements
= static_cast<sal_uInt16
>(aGluePoints
.getLength());
3067 sal_uInt16 j
, nElementSize
= 8;
3068 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3069 SvMemoryStream
aMemStrm( nStreamSize
);
3070 aMemStrm
.WriteUInt16( nElements
)
3071 .WriteUInt16( nElements
)
3072 .WriteUInt16( nElementSize
);
3073 for( j
= 0; j
< nElements
; j
++ )
3075 sal_Int32 X
= GetValueForEnhancedCustomShapeParameter( aGluePoints
[ j
].First
, aEquationOrder
);
3076 sal_Int32 Y
= GetValueForEnhancedCustomShapeParameter( aGluePoints
[ j
].Second
, aEquationOrder
);
3077 aMemStrm
.WriteInt32( X
)
3081 AddOpt(DFF_Prop_connectorPoints
, true, 6, aMemStrm
); // -6
3085 AddOpt(DFF_Prop_connectorPoints
, 0, true);
3090 else if ( rrProp
.Name
== "GluePointType" )
3092 sal_Int16 nGluePointType
= sal_Int16();
3093 if ( rrProp
.Value
>>= nGluePointType
)
3094 AddOpt( DFF_Prop_connectorType
, static_cast<sal_uInt16
>(nGluePointType
) );
3096 else if ( rrProp
.Name
== "Segments" )
3098 if (!bIsDefaultObject
&& !bUseDefaultObject
)
3100 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> aSegments
;
3101 if ( rrProp
.Value
>>= aSegments
)
3104 if ( aSegments
.hasElements() )
3106 sal_uInt16 j
, nElements
= static_cast<sal_uInt16
>(aSegments
.getLength());
3107 sal_uInt16 nElementSize
= 2;
3108 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3109 SvMemoryStream
aMemStrm( nStreamSize
);
3110 aMemStrm
.WriteUInt16( nElements
)
3111 .WriteUInt16( nElements
)
3112 .WriteUInt16( nElementSize
);
3113 for ( j
= 0; j
< nElements
; j
++ )
3115 // The segment type is stored in the upper 3 bits
3116 // and segment count is stored in the lower 13
3119 // If the segment type is msopathEscape, the lower 13 bits
3120 // are divided in a 5 bit escape code and 8 bit
3121 // vertex count (not segment count!)
3122 sal_uInt16 nVal
= static_cast<sal_uInt16
>(aSegments
[ j
].Count
);
3123 switch( aSegments
[ j
].Command
)
3125 case drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN
:
3126 case drawing::EnhancedCustomShapeSegmentCommand::LINETO
:
3128 case drawing::EnhancedCustomShapeSegmentCommand::MOVETO
:
3129 nVal
= (msopathMoveTo
<< 13);
3131 case drawing::EnhancedCustomShapeSegmentCommand::CURVETO
:
3133 nVal
|= (msopathCurveTo
<< 13);
3136 case drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
:
3139 nVal
|= (msopathClose
<< 13);
3142 case drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH
:
3144 nVal
= (msopathEnd
<< 13);
3147 case drawing::EnhancedCustomShapeSegmentCommand::NOFILL
:
3149 nVal
= (msopathEscape
<< 13) | (10 << 8);
3152 case drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE
:
3154 nVal
= (msopathEscape
<< 13) | (11 << 8);
3157 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO
:
3160 nVal
|= (msopathEscape
<< 13) | (1 << 8);
3163 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE
:
3166 nVal
|= (msopathEscape
<< 13) | (2 << 8);
3169 case drawing::EnhancedCustomShapeSegmentCommand::ARCTO
:
3172 nVal
|= (msopathEscape
<< 13) | (3 << 8);
3175 case drawing::EnhancedCustomShapeSegmentCommand::ARC
:
3178 nVal
|= (msopathEscape
<< 13) | (4 << 8);
3181 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO
:
3184 nVal
|= (msopathEscape
<< 13) | (5 << 8);
3187 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC
:
3190 nVal
|= (msopathEscape
<< 13) | (6 << 8);
3193 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX
:
3195 nVal
|= (msopathEscape
<< 13) | (7 << 8);
3198 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY
:
3200 nVal
|= (msopathEscape
<< 13) | (8 << 8);
3204 aMemStrm
.WriteUInt16( nVal
);
3207 AddOpt(DFF_Prop_pSegmentInfo
, false, 6, aMemStrm
);
3211 AddOpt(DFF_Prop_pSegmentInfo
, 0, true);
3216 else if ( rrProp
.Name
== "StretchX" )
3218 if (!bIsDefaultObject
&& !bUseDefaultObject
)
3220 sal_Int32 nStretchX
= 0;
3221 if ( rrProp
.Value
>>= nStretchX
)
3222 AddOpt( DFF_Prop_stretchPointX
, nStretchX
);
3225 else if ( rrProp
.Name
== "StretchY" )
3227 if (!bIsDefaultObject
&& !bUseDefaultObject
)
3229 sal_Int32 nStretchY
= 0;
3230 if ( rrProp
.Value
>>= nStretchY
)
3231 AddOpt( DFF_Prop_stretchPointY
, nStretchY
);
3234 else if ( rrProp
.Name
== "TextFrames" )
3236 if (!bIsDefaultObject
&& !bUseDefaultObject
)
3238 uno::Sequence
<drawing::EnhancedCustomShapeTextFrame
> aPathTextFrames
;
3239 if ( rrProp
.Value
>>= aPathTextFrames
)
3241 if ( aPathTextFrames
.hasElements() )
3243 sal_uInt16 j
, nElements
= static_cast<sal_uInt16
>(aPathTextFrames
.getLength());
3244 sal_uInt16 nElementSize
= 16;
3245 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3246 SvMemoryStream
aMemStrm( nStreamSize
);
3247 aMemStrm
.WriteUInt16( nElements
)
3248 .WriteUInt16( nElements
)
3249 .WriteUInt16( nElementSize
);
3250 for ( j
= 0; j
< nElements
; j
++ )
3252 sal_Int32 nLeft
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].TopLeft
.First
, aEquationOrder
);
3253 sal_Int32 nTop
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].TopLeft
.Second
, aEquationOrder
);
3254 sal_Int32 nRight
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].BottomRight
.First
, aEquationOrder
);
3255 sal_Int32 nBottom
= GetValueForEnhancedCustomShapeParameter( aPathTextFrames
[ j
].BottomRight
.Second
, aEquationOrder
);
3257 aMemStrm
.WriteInt32( nLeft
)
3259 .WriteInt32( nRight
)
3260 .WriteInt32( nBottom
);
3263 AddOpt(DFF_Prop_textRectangles
, true, 6, aMemStrm
);
3267 AddOpt(DFF_Prop_textRectangles
, 0, true);
3273 if ( nPathFlags
!= nPathFlagsOrg
)
3274 AddOpt( DFF_Prop_fFillOK
, nPathFlags
);
3277 else if ( rProp
.Name
== sTextPath
)
3279 uno::Sequence
< beans::PropertyValue
> aTextPathPropSeq
;
3280 if ( rProp
.Value
>>= aTextPathPropSeq
)
3282 sal_uInt32 nTextPathFlagsOrg
, nTextPathFlags
;
3283 nTextPathFlagsOrg
= nTextPathFlags
= 0xffff1000; // default
3284 if ( GetOpt( DFF_Prop_gtextFStrikethrough
, nTextPathFlags
) )
3285 nTextPathFlagsOrg
= nTextPathFlags
;
3287 sal_Int32 r
, nrCount
= aTextPathPropSeq
.getLength();
3288 for ( r
= 0; r
< nrCount
; r
++ )
3290 const beans::PropertyValue
& rrProp
= aTextPathPropSeq
[ r
];
3292 if ( rrProp
.Name
== sTextPath
)
3295 if ( rrProp
.Value
>>= bTextPathOn
)
3297 nTextPathFlags
|= 0x40000000;
3300 nTextPathFlags
|= 0x4000;
3302 sal_uInt32 nPathFlags
= 0x39;
3303 GetOpt( DFF_Prop_fFillOK
, nPathFlags
); // SJ: can be removed if we are supporting the TextPathAllowed property in XML
3304 nPathFlags
|= 0x40004;
3305 AddOpt( DFF_Prop_fFillOK
, nPathFlags
);
3308 nTextPathFlags
&=~0x4000;
3311 else if ( rrProp
.Name
== "TextPathMode" )
3313 drawing::EnhancedCustomShapeTextPathMode eTextPathMode
;
3314 if ( rrProp
.Value
>>= eTextPathMode
)
3316 nTextPathFlags
|= 0x05000000;
3317 nTextPathFlags
&=~0x500; // TextPathMode_NORMAL
3318 if ( eTextPathMode
== drawing::EnhancedCustomShapeTextPathMode_PATH
)
3319 nTextPathFlags
|= 0x100;
3320 else if ( eTextPathMode
== drawing::EnhancedCustomShapeTextPathMode_SHAPE
)
3321 nTextPathFlags
|= 0x500;
3324 else if ( rrProp
.Name
== "ScaleX" )
3326 bool bTextPathScaleX
;
3327 if ( rrProp
.Value
>>= bTextPathScaleX
)
3329 nTextPathFlags
|= 0x00400000;
3330 if ( bTextPathScaleX
)
3331 nTextPathFlags
|= 0x40;
3333 nTextPathFlags
&=~0x40;
3336 else if ( rrProp
.Name
== "SameLetterHeights" )
3338 bool bSameLetterHeights
;
3339 if ( rrProp
.Value
>>= bSameLetterHeights
)
3341 nTextPathFlags
|= 0x00800000;
3342 if ( bSameLetterHeights
)
3343 nTextPathFlags
|= 0x80;
3345 nTextPathFlags
&=~0x80;
3349 if ( nTextPathFlags
& 0x4000 ) // Is FontWork ?
3353 uno::Reference
< text::XSimpleText
> xText( rXShape
, uno::UNO_QUERY
);
3355 aText
= xText
->getString();
3356 if ( aText
.isEmpty() )
3357 aText
= "your text"; // TODO: moving into a resource
3358 AddOpt( DFF_Prop_gtextUNICODE
, aText
);
3362 uno::Any aAny
= aXPropSet
->getPropertyValue( u
"CharFontName"_ustr
);
3364 if ( aFontName
.isEmpty() )
3365 aFontName
= "Arial Black";
3366 AddOpt( DFF_Prop_gtextFont
, aFontName
);
3368 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"CharScaleWidth"_ustr
, true ) )
3370 sal_Int16 nCharScaleWidth
= 100;
3371 if ( aAny
>>= nCharScaleWidth
)
3373 if ( nCharScaleWidth
!= 100 )
3375 sal_Int32 nVal
= nCharScaleWidth
* 655;
3376 AddOpt( DFF_Prop_gtextSpacing
, nVal
);
3380 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"CharHeight"_ustr
, true ) )
3382 float fCharHeight
= 0.0;
3383 if ( aAny
>>= fCharHeight
)
3385 sal_Int32 nTextSize
= static_cast< sal_Int32
> ( fCharHeight
* 65536 );
3386 AddOpt(ESCHER_Prop_gtextSize
, nTextSize
);
3389 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"CharKerning"_ustr
, true ) )
3391 sal_Int16 nCharKerning
= sal_Int16();
3392 if ( aAny
>>= nCharKerning
)
3394 nTextPathFlags
|= 0x10000000;
3396 nTextPathFlags
|= 0x1000;
3398 nTextPathFlags
&=~0x1000;
3401 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"CharPosture"_ustr
, true ) )
3403 awt::FontSlant eFontSlant
;
3404 if ( aAny
>>= eFontSlant
)
3406 nTextPathFlags
|= 0x100010;
3407 if ( eFontSlant
!= awt::FontSlant_NONE
)
3408 nTextPathFlags
|= 0x10;
3410 nTextPathFlags
&=~0x10;
3413 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"CharWeight"_ustr
, true ) )
3415 float fFontWidth
= 0;
3416 if ( aAny
>>= fFontWidth
)
3418 nTextPathFlags
|= 0x200020;
3419 if ( fFontWidth
> awt::FontWeight::NORMAL
)
3420 nTextPathFlags
|= 0x20;
3422 nTextPathFlags
&=~0x20;
3425 // export gTextAlign attr
3426 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aXPropSet
, u
"TextHorizontalAdjust"_ustr
, true ) )
3428 MSO_GeoTextAlign gTextAlign
= mso_alignTextCenter
;
3429 drawing::TextHorizontalAdjust
eHA( drawing::TextHorizontalAdjust_LEFT
);
3433 case drawing::TextHorizontalAdjust_LEFT
:
3434 gTextAlign
= mso_alignTextLeft
;
3436 case drawing::TextHorizontalAdjust_CENTER
:
3437 gTextAlign
= mso_alignTextCenter
;
3439 case drawing::TextHorizontalAdjust_RIGHT
:
3440 gTextAlign
= mso_alignTextRight
;
3442 case drawing::TextHorizontalAdjust_BLOCK
:
3444 drawing::TextFitToSizeType
const eFTS(
3445 rSdrObjCustomShape
.GetMergedItem( SDRATTR_TEXT_FITTOSIZE
).GetValue() );
3446 if (eFTS
== drawing::TextFitToSizeType_ALLLINES
||
3447 eFTS
== drawing::TextFitToSizeType_PROPORTIONAL
)
3449 gTextAlign
= mso_alignTextStretch
;
3453 gTextAlign
= mso_alignTextWordJust
;
3460 AddOpt(DFF_Prop_gtextAlign
,gTextAlign
);
3463 if((nTextPathFlags
& 0x4000) != 0) // Is Fontwork
3465 OutlinerParaObject
* pOutlinerParaObject(rSdrObjCustomShape
.GetOutlinerParaObject());
3466 if ( pOutlinerParaObject
&& pOutlinerParaObject
->IsEffectivelyVertical() )
3467 nTextPathFlags
|= 0x2000;
3470 // Use gtextFStretch for Watermark like MSO does
3471 nTextPathFlags
|= use_gtextFBestFit
| gtextFBestFit
3472 | use_gtextFStretch
| gtextFStretch
3473 | use_gtextFShrinkFit
| gtextFShrinkFit
;
3475 if ( nTextPathFlags
!= nTextPathFlagsOrg
)
3476 AddOpt( DFF_Prop_gtextFStrikethrough
, nTextPathFlags
);
3479 else if ( rProp
.Name
== sHandles
)
3481 if (!bIsDefaultObject
&& !bUseDefaultObject
)
3483 bPredefinedHandlesUsed
= false;
3484 if ( rProp
.Value
>>= aHandlesPropSeq
)
3486 sal_uInt16 nElements
= static_cast<sal_uInt16
>(aHandlesPropSeq
.getLength());
3489 sal_uInt16 k
, nElementSize
= 36;
3490 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3491 SvMemoryStream
aMemStrm( nStreamSize
);
3492 aMemStrm
.WriteUInt16( nElements
)
3493 .WriteUInt16( nElements
)
3494 .WriteUInt16( nElementSize
);
3496 for ( k
= 0; k
< nElements
; k
++ )
3498 sal_uInt32 nFlags
= 0;
3499 sal_Int32 nXPosition
= 0;
3500 sal_Int32 nYPosition
= 0;
3501 sal_Int32 nXMap
= 0;
3502 sal_Int32 nYMap
= 0;
3503 sal_Int32 nXRangeMin
= 0x80000000;
3504 sal_Int32 nXRangeMax
= 0x7fffffff;
3505 sal_Int32 nYRangeMin
= 0x80000000;
3506 sal_Int32 nYRangeMax
= 0x7fffffff;
3508 const uno::Sequence
< beans::PropertyValue
>& rPropSeq
= aHandlesPropSeq
[ k
];
3509 for ( const beans::PropertyValue
& rPropVal
: rPropSeq
)
3511 if ( rPropVal
.Name
== "Position" )
3513 drawing::EnhancedCustomShapeParameterPair aPosition
;
3514 if ( rPropVal
.Value
>>= aPosition
)
3516 GetValueForEnhancedCustomShapeHandleParameter( nXPosition
, aPosition
.First
);
3517 GetValueForEnhancedCustomShapeHandleParameter( nYPosition
, aPosition
.Second
);
3520 else if ( rPropVal
.Name
== "MirroredX" )
3523 if ( rPropVal
.Value
>>= bMirroredX
)
3529 else if ( rPropVal
.Name
== "MirroredY" )
3532 if ( rPropVal
.Value
>>= bMirroredY
)
3538 else if ( rPropVal
.Name
== "Switched" )
3541 if ( rPropVal
.Value
>>= bSwitched
)
3547 else if ( rPropVal
.Name
== "Polar" )
3549 drawing::EnhancedCustomShapeParameterPair aPolar
;
3550 if ( rPropVal
.Value
>>= aPolar
)
3552 if ( GetValueForEnhancedCustomShapeHandleParameter( nXMap
, aPolar
.First
) )
3554 if ( GetValueForEnhancedCustomShapeHandleParameter( nYMap
, aPolar
.Second
) )
3559 else if ( rPropVal
.Name
== "RadiusRangeMinimum" )
3561 nYRangeMin
= sal_Int32(0xff4c0000); // the range of angles seems to be a not
3562 nYRangeMax
= sal_Int32(0x00b40000); // used feature, so we are defaulting this
3564 drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum
;
3565 if ( rPropVal
.Value
>>= aRadiusRangeMinimum
)
3567 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin
, aRadiusRangeMinimum
) )
3572 else if ( rPropVal
.Name
== "RadiusRangeMaximum" )
3574 nYRangeMin
= sal_Int32(0xff4c0000); // the range of angles seems to be a not
3575 nYRangeMax
= sal_Int32(0x00b40000); // used feature, so we are defaulting this
3577 drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum
;
3578 if ( rPropVal
.Value
>>= aRadiusRangeMaximum
)
3580 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax
, aRadiusRangeMaximum
) )
3585 else if ( rPropVal
.Name
== "RangeXMinimum" )
3587 drawing::EnhancedCustomShapeParameter aXRangeMinimum
;
3588 if ( rPropVal
.Value
>>= aXRangeMinimum
)
3590 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin
, aXRangeMinimum
) )
3595 else if ( rPropVal
.Name
== "RangeXMaximum" )
3597 drawing::EnhancedCustomShapeParameter aXRangeMaximum
;
3598 if ( rPropVal
.Value
>>= aXRangeMaximum
)
3600 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax
, aXRangeMaximum
) )
3605 else if ( rPropVal
.Name
== "RangeYMinimum" )
3607 drawing::EnhancedCustomShapeParameter aYRangeMinimum
;
3608 if ( rPropVal
.Value
>>= aYRangeMinimum
)
3610 if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMin
, aYRangeMinimum
) )
3615 else if ( rPropVal
.Name
== "RangeYMaximum" )
3617 drawing::EnhancedCustomShapeParameter aYRangeMaximum
;
3618 if ( rPropVal
.Value
>>= aYRangeMaximum
)
3620 if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMax
, aYRangeMaximum
) )
3626 aMemStrm
.WriteUInt32( nFlags
)
3627 .WriteInt32( nXPosition
)
3628 .WriteInt32( nYPosition
)
3629 .WriteInt32( nXMap
)
3630 .WriteInt32( nYMap
)
3631 .WriteInt32( nXRangeMin
)
3632 .WriteInt32( nXRangeMax
)
3633 .WriteInt32( nYRangeMin
)
3634 .WriteInt32( nYRangeMax
);
3637 nAdjustmentsWhichNeedsToBeConverted
|= ( 1 << ( nYPosition
- 0x100 ) );
3640 AddOpt(DFF_Prop_Handles
, true, 6, aMemStrm
);
3644 AddOpt(DFF_Prop_Handles
, 0, true);
3649 else if ( rProp
.Name
== sAdjustmentValues
)
3651 // it is required, that the information which handle is polar has already be read,
3652 // so we are able to change the polar value to a fixed float
3653 aAdjustmentValuesProp
= rProp
.Value
;
3654 bAdjustmentValuesProp
= true;
3657 if ( bAdjustmentValuesProp
)
3659 uno::Sequence
<drawing::EnhancedCustomShapeAdjustmentValue
> aAdjustmentSeq
;
3660 if ( aAdjustmentValuesProp
>>= aAdjustmentSeq
)
3662 if ( bPredefinedHandlesUsed
)
3663 LookForPolarHandles( eShapeType
, nAdjustmentsWhichNeedsToBeConverted
);
3665 sal_Int32 k
, nValue
= 0, nAdjustmentValues
= aAdjustmentSeq
.getLength();
3666 for ( k
= 0; k
< nAdjustmentValues
; k
++ )
3667 if( GetAdjustmentValue( aAdjustmentSeq
[ k
], k
, nAdjustmentsWhichNeedsToBeConverted
, nValue
) )
3669 if (bUseDefaultObject
)
3670 nValue
= 21600 * (nValue
/ 100000.00);
3672 AddOpt( static_cast<sal_uInt16
>( DFF_Prop_adjustValue
+ k
), static_cast<sal_uInt32
>(nValue
) );
3676 if( !bPathCoordinatesProp
)
3679 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> aCoordinates
;
3680 if ( !(aPathCoordinatesProp
>>= aCoordinates
) )
3683 // creating the vertices
3684 if (aCoordinates
.hasElements())
3686 sal_uInt16 j
, nElements
= static_cast<sal_uInt16
>(aCoordinates
.getLength());
3687 sal_uInt16 nElementSize
= 8;
3688 sal_uInt32 nStreamSize
= nElementSize
* nElements
+ 6;
3689 SvMemoryStream
aMemStrm( nStreamSize
);
3690 aMemStrm
.WriteUInt16( nElements
)
3691 .WriteUInt16( nElements
)
3692 .WriteUInt16( nElementSize
);
3693 for( j
= 0; j
< nElements
; j
++ )
3695 sal_Int32 X
= GetValueForEnhancedCustomShapeParameter( aCoordinates
[ j
].First
, aEquationOrder
, true );
3696 sal_Int32 Y
= GetValueForEnhancedCustomShapeParameter( aCoordinates
[ j
].Second
, aEquationOrder
, true );
3697 aMemStrm
.WriteInt32( X
)
3701 AddOpt(DFF_Prop_pVertices
, true, 6, aMemStrm
); // -6
3705 AddOpt(DFF_Prop_pVertices
, 0, true);
3709 MSO_SPT
EscherPropertyContainer::GetCustomShapeType( const uno::Reference
< drawing::XShape
> & rXShape
, ShapeFlag
& nMirrorFlags
, OUString
& rShapeType
, bool bOOXML
)
3711 MSO_SPT eShapeType
= mso_sptNil
;
3712 nMirrorFlags
= ShapeFlag::NONE
;
3713 uno::Reference
< beans::XPropertySet
> aXPropSet( rXShape
, uno::UNO_QUERY
);
3714 if ( aXPropSet
.is() )
3718 uno::Any aGeoPropSet
= aXPropSet
->getPropertyValue( u
"CustomShapeGeometry"_ustr
);
3719 uno::Sequence
< beans::PropertyValue
> aGeoPropSeq
;
3720 if ( aGeoPropSet
>>= aGeoPropSeq
)
3722 sal_Int32 i
, nCount
= aGeoPropSeq
.getLength();
3723 for ( i
= 0; i
< nCount
; i
++ )
3725 const beans::PropertyValue
& rProp
= aGeoPropSeq
[ i
];
3726 if ( rProp
.Name
== "Type" )
3728 if ( rProp
.Value
>>= rShapeType
)
3732 // In case of VML export, try to handle the
3733 // ooxml- prefix in rShapeType. If that fails,
3734 // just do the same as the binary export.
3735 eShapeType
= msfilter::util::GETVMLShapeType(rShapeType
);
3736 if (eShapeType
== mso_sptNil
)
3737 eShapeType
= EnhancedCustomShapeTypeNames::Get(rShapeType
);
3740 eShapeType
= EnhancedCustomShapeTypeNames::Get( rShapeType
);
3743 else if ( rProp
.Name
== "MirroredX" )
3746 if ( ( rProp
.Value
>>= bMirroredX
) && bMirroredX
)
3747 nMirrorFlags
|= ShapeFlag::FlipH
;
3749 else if ( rProp
.Name
== "MirroredY" )
3752 if ( ( rProp
.Value
>>= bMirroredY
) && bMirroredY
)
3753 nMirrorFlags
|= ShapeFlag::FlipV
;
3758 catch( const uno::Exception
& )
3766 // Implement for form control export
3767 bool EscherPropertyContainer::CreateBlipPropertiesforOLEControl(const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
3768 const uno::Reference
<drawing::XShape
> & rXShape
)
3770 SdrObject
* pShape
= SdrObject::getSdrObjectFromXShape(rXShape
);
3774 Graphic
aGraphic(SdrExchangeView::GetObjGraphic(*pShape
));
3775 const GraphicObject
aGraphicObject(std::move(aGraphic
));
3777 if (!aGraphicObject
.GetUniqueID().isEmpty())
3779 if ( pGraphicProvider
&& pPicOutStrm
&& pShapeBoundRect
)
3781 sal_uInt32 nBlibId
= pGraphicProvider
->GetBlibID(*pPicOutStrm
, aGraphicObject
);
3784 AddOpt( ESCHER_Prop_pib
, nBlibId
, true );
3785 ImplCreateGraphicAttributes( rXPropSet
, nBlibId
, false );
3794 EscherPersistTable::EscherPersistTable()
3798 EscherPersistTable::~EscherPersistTable()
3802 bool EscherPersistTable::PtIsID( sal_uInt32 nID
)
3804 return std::any_of(maPersistTable
.begin(), maPersistTable
.end(),
3805 [&nID
](const auto& rxEntry
) { return rxEntry
->mnID
== nID
; });
3808 void EscherPersistTable::PtInsert( sal_uInt32 nID
, sal_uInt32 nOfs
)
3810 maPersistTable
.push_back( std::make_unique
<EscherPersistEntry
>( nID
, nOfs
) );
3813 void EscherPersistTable::PtDelete( sal_uInt32 nID
)
3815 auto it
= std::find_if(maPersistTable
.begin(), maPersistTable
.end(),
3816 [&nID
](const std::unique_ptr
<EscherPersistEntry
>& rxEntry
) { return rxEntry
->mnID
== nID
; });
3817 if (it
!= maPersistTable
.end())
3818 maPersistTable
.erase( it
);
3821 sal_uInt32
EscherPersistTable::PtGetOffsetByID( sal_uInt32 nID
)
3823 for(auto const & pPtr
: maPersistTable
) {
3824 if ( pPtr
->mnID
== nID
) {
3825 return pPtr
->mnOffset
;
3831 void EscherPersistTable::PtReplace( sal_uInt32 nID
, sal_uInt32 nOfs
)
3833 for(auto const & pPtr
: maPersistTable
) {
3834 if ( pPtr
->mnID
== nID
) {
3835 pPtr
->mnOffset
= nOfs
;
3841 void EscherPersistTable::PtReplaceOrInsert( sal_uInt32 nID
, sal_uInt32 nOfs
)
3843 for(auto const & pPtr
: maPersistTable
) {
3844 if ( pPtr
->mnID
== nID
) {
3845 pPtr
->mnOffset
= nOfs
;
3849 PtInsert( nID
, nOfs
);
3852 bool EscherPropertyValueHelper::GetPropertyValue(
3854 const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
3855 const OUString
& rString
,
3856 bool bTestPropertyAvailability
)
3858 bool bRetValue
= true;
3859 if ( bTestPropertyAvailability
)
3864 uno::Reference
<beans::XPropertySetInfo
>
3865 aXPropSetInfo( rXPropSet
->getPropertySetInfo() );
3866 if ( aXPropSetInfo
.is() )
3867 bRetValue
= aXPropSetInfo
->hasPropertyByName( rString
);
3869 catch( const uno::Exception
& )
3878 rAny
= rXPropSet
->getPropertyValue( rString
);
3879 if ( !rAny
.hasValue() )
3882 catch( const uno::Exception
& )
3890 beans::PropertyState
EscherPropertyValueHelper::GetPropertyState(
3891 const uno::Reference
<beans::XPropertySet
> & rXPropSet
,
3892 const OUString
& rPropertyName
)
3894 beans::PropertyState eRetValue
= beans::PropertyState_AMBIGUOUS_VALUE
;
3897 uno::Reference
<beans::XPropertyState
> aXPropState
3898 ( rXPropSet
, uno::UNO_QUERY
);
3899 if ( aXPropState
.is() )
3900 eRetValue
= aXPropState
->getPropertyState( rPropertyName
);
3902 catch( const uno::Exception
& )
3908 EscherBlibEntry::EscherBlibEntry( sal_uInt32 nPictureOffset
, const GraphicObject
& rObject
, const OString
& rId
,
3909 const GraphicAttr
* pGraphicAttr
) :
3910 maPrefMapMode ( rObject
.GetPrefMapMode() ),
3911 maPrefSize ( rObject
.GetPrefSize() ),
3912 mnPictureOffset ( nPictureOffset
),
3917 mbIsNativeGraphicPossible
= ( pGraphicAttr
== nullptr );
3918 meBlibType
= UNKNOWN
;
3921 sal_uInt32 nLen
= static_cast<sal_uInt32
>(rId
.getLength());
3922 const char* pData
= rId
.getStr();
3923 GraphicType
eType( rObject
.GetType() );
3924 if (!(nLen
&& (eType
!= GraphicType::NONE
)))
3927 mnIdentifier
[ 0 ] = rtl_crc32( 0,pData
, nLen
);
3928 mnIdentifier
[ 1 ] = 0;
3932 if ( pGraphicAttr
->IsSpecialDrawMode()
3933 || pGraphicAttr
->IsMirrored()
3934 || pGraphicAttr
->IsCropped()
3935 || pGraphicAttr
->IsRotated()
3936 || pGraphicAttr
->IsTransparent()
3937 || pGraphicAttr
->IsAdjusted() )
3939 SvMemoryStream
aSt( sizeof( GraphicAttr
) );
3940 aSt
.WriteUInt16( static_cast<sal_uInt16
>(pGraphicAttr
->GetDrawMode()) )
3941 .WriteUInt32( static_cast<sal_uInt32
>(pGraphicAttr
->GetMirrorFlags()) )
3942 .WriteInt32( pGraphicAttr
->GetLeftCrop() )
3943 .WriteInt32( pGraphicAttr
->GetTopCrop() )
3944 .WriteInt32( pGraphicAttr
->GetRightCrop() )
3945 .WriteInt32( pGraphicAttr
->GetBottomCrop() )
3946 .WriteUInt16( pGraphicAttr
->GetRotation().get() )
3947 .WriteInt16( pGraphicAttr
->GetLuminance() )
3948 .WriteInt16( pGraphicAttr
->GetContrast() )
3949 .WriteInt16( pGraphicAttr
->GetChannelR() )
3950 .WriteInt16( pGraphicAttr
->GetChannelG() )
3951 .WriteInt16( pGraphicAttr
->GetChannelB() )
3952 .WriteDouble( pGraphicAttr
->GetGamma() );
3953 aSt
.WriteBool( pGraphicAttr
->IsInvert() )
3954 .WriteUChar( 255 - pGraphicAttr
->GetAlpha() ); // transparency
3955 mnIdentifier
[ 1 ] = rtl_crc32( 0, aSt
.GetData(), aSt
.Tell() );
3958 mbIsNativeGraphicPossible
= true;
3960 sal_uInt32 i
, nTmp
, n1
, n2
;
3962 for ( i
= 0; i
< nLen
; i
++ )
3964 nTmp
= n2
>> 28; // rotating 4 bit
3969 n1
^= *pData
++ - '0';
3971 mnIdentifier
[ 2 ] = n1
;
3972 mnIdentifier
[ 3 ] = n2
;
3976 void EscherBlibEntry::WriteBlibEntry( SvStream
& rSt
, bool bWritePictureOffset
, sal_uInt32 nResize
)
3978 sal_uInt32 nPictureOffset
= bWritePictureOffset
? mnPictureOffset
: 0;
3980 rSt
.WriteUInt32( ( ESCHER_BSE
<< 16 ) | ( ( static_cast<sal_uInt16
>(meBlibType
) << 4 ) | 2 ) )
3981 .WriteUInt32( 36 + nResize
)
3982 .WriteUChar( meBlibType
);
3984 switch ( meBlibType
)
3987 case WMF
: // converting EMF/WMF on OS2 to Pict
3988 rSt
.WriteUChar( PICT
);
3991 rSt
.WriteUChar( meBlibType
);
3994 rSt
.WriteBytes(&mnIdentifier
[0], 16);
3995 rSt
.WriteUInt16( 0 )
3996 .WriteUInt32( mnSize
+ mnSizeExtra
)
3997 .WriteUInt32( mnRefCount
)
3998 .WriteUInt32( nPictureOffset
)
4002 EscherBlibEntry::~EscherBlibEntry()
4006 bool EscherBlibEntry::operator==( const EscherBlibEntry
& rEscherBlibEntry
) const
4008 for ( int i
= 0; i
< 3; i
++ )
4010 if ( mnIdentifier
[ i
] != rEscherBlibEntry
.mnIdentifier
[ i
] )
4016 EscherGraphicProvider::EscherGraphicProvider( EscherGraphicProviderFlags nFlags
) :
4021 EscherGraphicProvider::~EscherGraphicProvider()
4025 void EscherGraphicProvider::SetNewBlipStreamOffset( sal_Int32 nOffset
)
4027 for( size_t i
= 0; i
< mvBlibEntrys
.size(); i
++ )
4029 mvBlibEntrys
[ i
]->mnPictureOffset
+= nOffset
;
4033 sal_uInt32
EscherGraphicProvider::ImplInsertBlib( EscherBlibEntry
* p_EscherBlibEntry
)
4035 mvBlibEntrys
.push_back( std::unique_ptr
<EscherBlibEntry
>(p_EscherBlibEntry
) );
4036 return mvBlibEntrys
.size();
4039 sal_uInt32
EscherGraphicProvider::GetBlibStoreContainerSize( SvStream
const * pMergePicStreamBSE
) const
4041 sal_uInt32 nSize
= 44 * mvBlibEntrys
.size() + 8;
4042 if ( pMergePicStreamBSE
)
4044 for ( size_t i
= 0; i
< mvBlibEntrys
.size(); i
++ )
4045 nSize
+= mvBlibEntrys
[ i
]->mnSize
+ mvBlibEntrys
[ i
]->mnSizeExtra
;
4050 void EscherGraphicProvider::WriteBlibStoreEntry(SvStream
& rSt
,
4051 sal_uInt32 nBlipId
, sal_uInt32 nResize
)
4053 if (nBlipId
> mvBlibEntrys
.size() || nBlipId
== 0)
4055 mvBlibEntrys
[nBlipId
-1]->WriteBlibEntry(rSt
, true/*bWritePictureOffSet*/, nResize
);
4058 void EscherGraphicProvider::WriteBlibStoreContainer( SvStream
& rSt
, SvStream
* pMergePicStreamBSE
)
4060 sal_uInt32 nSize
= GetBlibStoreContainerSize( pMergePicStreamBSE
);
4064 rSt
.WriteUInt32( ( ESCHER_BstoreContainer
<< 16 ) | 0x1f )
4065 .WriteUInt32( nSize
- 8 );
4067 if ( pMergePicStreamBSE
)
4069 sal_uInt32 nBlipSize
;
4070 sal_uInt64 nOldPos
= pMergePicStreamBSE
->Tell();
4071 const sal_uInt32 nBuf
= 0x40000; // 256KB buffer
4072 std::unique_ptr
<sal_uInt8
[]> pBuf(new sal_uInt8
[ nBuf
]);
4074 for ( size_t i
= 0; i
< mvBlibEntrys
.size(); i
++ )
4076 EscherBlibEntry
* pBlibEntry
= mvBlibEntrys
[ i
].get();
4078 ESCHER_BlibType nBlibType
= pBlibEntry
->meBlibType
;
4079 nBlipSize
= pBlibEntry
->mnSize
+ pBlibEntry
->mnSizeExtra
;
4080 pBlibEntry
->WriteBlibEntry( rSt
, false, nBlipSize
);
4083 pMergePicStreamBSE
->Seek( pBlibEntry
->mnPictureOffset
);
4085 // record version and instance
4086 pMergePicStreamBSE
->ReadUInt16( n16
);
4087 rSt
.WriteUInt16( n16
);
4089 pMergePicStreamBSE
->ReadUInt16( n16
);
4090 rSt
.WriteUInt16( ESCHER_BlipFirst
+ nBlibType
);
4091 DBG_ASSERT( n16
== ESCHER_BlipFirst
+ nBlibType
, "EscherGraphicProvider::WriteBlibStoreContainer: BLIP record types differ" );
4094 pMergePicStreamBSE
->ReadUInt32( n32
);
4096 rSt
.WriteUInt32( nBlipSize
);
4097 DBG_ASSERT( nBlipSize
== n32
, "EscherGraphicProvider::WriteBlibStoreContainer: BLIP sizes differ" );
4101 sal_uInt32 nBytes
= std::min( nBlipSize
, nBuf
);
4102 pMergePicStreamBSE
->ReadBytes(pBuf
.get(), nBytes
);
4103 rSt
.WriteBytes(pBuf
.get(), nBytes
);
4104 nBlipSize
-= nBytes
;
4107 pMergePicStreamBSE
->Seek( nOldPos
);
4111 for ( size_t i
= 0; i
< mvBlibEntrys
.size(); i
++ )
4112 mvBlibEntrys
[ i
]->WriteBlibEntry( rSt
, true );
4116 bool EscherGraphicProvider::GetPrefSize( const sal_uInt32 nBlibId
, Size
& rPrefSize
, MapMode
& rPrefMapMode
)
4118 bool bInRange
= nBlibId
&& ( ( nBlibId
- 1 ) < mvBlibEntrys
.size() );
4121 EscherBlibEntry
* pEntry
= mvBlibEntrys
[ nBlibId
- 1 ].get();
4122 rPrefSize
= pEntry
->maPrefSize
;
4123 rPrefMapMode
= pEntry
->maPrefMapMode
;
4128 sal_uInt32
EscherGraphicProvider::GetBlibID( SvStream
& rPicOutStrm
, GraphicObject
const & rGraphicObject
,
4129 const awt::Rectangle
* pVisArea
,
4130 const GraphicAttr
* pGraphicAttr
, const bool bOOxmlExport
)
4132 sal_uInt32 nBlibId
= 0;
4134 std::unique_ptr
<EscherBlibEntry
> p_EscherBlibEntry( new EscherBlibEntry( rPicOutStrm
.Tell(), rGraphicObject
, rGraphicObject
.GetUniqueID(), pGraphicAttr
) );
4135 if ( !p_EscherBlibEntry
->IsEmpty() )
4137 for ( size_t i
= 0; i
< mvBlibEntrys
.size(); i
++ )
4139 if ( *( mvBlibEntrys
[ i
] ) == *p_EscherBlibEntry
)
4141 mvBlibEntrys
[ i
]->mnRefCount
++;
4146 bool bUseNativeGraphic( false );
4148 Graphic
aGraphic(rGraphicObject
.GetTransformedGraphic(pGraphicAttr
));
4149 GfxLink aGraphicLink
;
4150 SvMemoryStream aStream
;
4152 const sal_uInt8
* pGraphicAry
= nullptr;
4154 if ( p_EscherBlibEntry
->mbIsNativeGraphicPossible
&& aGraphic
.IsGfxLink() )
4156 aGraphicLink
= aGraphic
.GetGfxLink();
4158 p_EscherBlibEntry
->mnSize
= aGraphicLink
.GetDataSize();
4159 pGraphicAry
= aGraphicLink
.GetData();
4161 if ( p_EscherBlibEntry
->mnSize
&& pGraphicAry
)
4163 switch ( aGraphicLink
.GetType() )
4165 case GfxLinkType::NativeJpg
: p_EscherBlibEntry
->meBlibType
= PEG
; break;
4166 case GfxLinkType::NativePng
: p_EscherBlibEntry
->meBlibType
= PNG
; break;
4168 // #i15508# added BMP type for better exports; need to check this
4169 // checked - does not work that way, so keep out for now. It may
4170 // work somehow with direct DIB data, but that would need to be checked
4172 // for more comments please check RtfAttributeOutput::FlyFrameGraphic
4174 // case GfxLinkType::NativeBmp : p_EscherBlibEntry->meBlibType = DIB; break;
4176 case GfxLinkType::NativeWmf
:
4178 if ( aGraphicLink
.IsEMF() )
4180 p_EscherBlibEntry
->meBlibType
= EMF
;
4182 else if ( pGraphicAry
&& ( p_EscherBlibEntry
->mnSize
> 0x2c ) )
4184 p_EscherBlibEntry
->meBlibType
= WMF
;
4185 if ( ( pGraphicAry
[ 0 ] == 0xd7 ) && ( pGraphicAry
[ 1 ] == 0xcd )
4186 && ( pGraphicAry
[ 2 ] == 0xc6 ) && ( pGraphicAry
[ 3 ] == 0x9a ) )
4187 { // we have to get rid of the metafileheader
4189 p_EscherBlibEntry
->mnSize
-= 22;
4196 if ( p_EscherBlibEntry
->meBlibType
!= UNKNOWN
)
4197 bUseNativeGraphic
= true;
4200 if ( !bUseNativeGraphic
)
4202 GraphicType eGraphicType
= aGraphic
.GetType();
4203 if ( ( eGraphicType
== GraphicType::Bitmap
) || ( eGraphicType
== GraphicType::GdiMetafile
) )
4206 if ( !aGraphic
.IsAnimated() )
4207 nErrCode
= GraphicConverter::Export( aStream
, aGraphic
, ( eGraphicType
== GraphicType::Bitmap
) ? ConvertDataFormat::PNG
: ConvertDataFormat::EMF
);
4209 { // to store an animation, a gif has to be included into the msOG chunk of a png #I5583#
4210 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
4211 SvMemoryStream aGIFStream
;
4212 const char* const pString
= "MSOFFICE9.0";
4213 aGIFStream
.WriteBytes(pString
, strlen(pString
));
4214 nErrCode
= rFilter
.ExportGraphic( aGraphic
, u
"", aGIFStream
,
4215 rFilter
.GetExportFormatNumberForShortName( u
"GIF" ) );
4217 nErrCode
!= ERRCODE_NONE
, "filter.ms",
4218 "ExportGraphic to GIF failed with " << nErrCode
);
4219 if (nErrCode
== ERRCODE_NONE
)
4221 sal_uInt32 nGIFSreamLen
= aGIFStream
.Tell();
4222 uno::Sequence
<sal_Int8
> aGIFSeq( nGIFSreamLen
);
4223 sal_Int8
* pSeq
= aGIFSeq
.getArray();
4224 aGIFStream
.Seek( STREAM_SEEK_TO_BEGIN
);
4225 aGIFStream
.ReadBytes(pSeq
, nGIFSreamLen
);
4226 beans::PropertyValue aChunkProp
, aFilterProp
;
4227 aChunkProp
.Name
= "msOG";
4228 aChunkProp
.Value
<<= aGIFSeq
;
4229 uno::Sequence
<beans::PropertyValue
> aAdditionalChunkSequence
{ std::move(aChunkProp
) };
4230 aFilterProp
.Name
= "AdditionalChunks";
4231 aFilterProp
.Value
<<= aAdditionalChunkSequence
;
4232 uno::Sequence
<beans::PropertyValue
> aFilterData
{ std::move(aFilterProp
) };
4233 nErrCode
= rFilter
.ExportGraphic( aGraphic
, u
"", aStream
,
4234 rFilter
.GetExportFormatNumberForShortName( u
"PNG" ), &aFilterData
);
4237 if ( nErrCode
== ERRCODE_NONE
)
4239 p_EscherBlibEntry
->meBlibType
= ( eGraphicType
== GraphicType::Bitmap
) ? PNG
: EMF
;
4240 p_EscherBlibEntry
->mnSize
= aStream
.TellEnd();
4241 pGraphicAry
= static_cast<sal_uInt8
const *>(aStream
.GetData());
4246 ESCHER_BlibType eBlibType
= p_EscherBlibEntry
->meBlibType
;
4247 if ( p_EscherBlibEntry
->mnSize
&& pGraphicAry
&& ( eBlibType
!= UNKNOWN
) )
4249 sal_uInt32 nExtra
, nAtomSize
= 0;
4250 sal_uInt32 nInstance
, nUncompressedSize
= p_EscherBlibEntry
->mnSize
;
4252 if ( mnFlags
& EscherGraphicProviderFlags::UseInstances
)
4254 rPicOutStrm
.WriteUInt32( 0x7f90000 | static_cast<sal_uInt16
>( mvBlibEntrys
.size() << 4 ) )
4256 nAtomSize
= rPicOutStrm
.Tell();
4257 if ( eBlibType
== PNG
)
4258 rPicOutStrm
.WriteUInt16( 0x0606 );
4259 else if ( eBlibType
== WMF
)
4260 rPicOutStrm
.WriteUInt16( 0x0403 );
4261 else if ( eBlibType
== EMF
)
4262 rPicOutStrm
.WriteUInt16( 0x0402 );
4263 else if ( eBlibType
== PEG
)
4264 rPicOutStrm
.WriteUInt16( 0x0505 );
4267 // fdo#69607 do not compress WMF files if we are in OOXML export
4268 if ( ( eBlibType
== PEG
) || ( eBlibType
== PNG
) // || ( eBlibType == DIB )) // #i15508#
4269 || ( ( ( eBlibType
== WMF
) || ( eBlibType
== EMF
) ) && bOOxmlExport
) )
4272 p_EscherBlibEntry
->mnSizeExtra
= nExtra
+ 8;
4274 // #i15508# type see SvxMSDffManager::GetBLIPDirect (checked, does not work this way)
4275 // see RtfAttributeOutput::FlyFrameGraphic for more comments
4276 // maybe it would work with direct DIB data, but that would need thorough testing
4277 if( eBlibType
== PNG
)
4279 nInstance
= 0xf01e6e00;
4281 else // if( eBlibType == PEG )
4283 nInstance
= 0xf01d46a0;
4285 //else // eBlibType == DIB
4287 // nInstance = 0xf01d7A80;
4291 //nInstance = ( eBlibType == PNG ) ? 0xf01e6e00 : 0xf01d46a0;
4294 rPicOutStrm
.WriteUInt32( nInstance
).WriteUInt32( p_EscherBlibEntry
->mnSize
+ nExtra
);
4295 rPicOutStrm
.WriteBytes(p_EscherBlibEntry
->mnIdentifier
, 16);
4296 rPicOutStrm
.WriteUChar( 0xff );
4297 rPicOutStrm
.WriteBytes(pGraphicAry
, p_EscherBlibEntry
->mnSize
);
4301 ZCodec
aZCodec( 0x8000, 0x8000 );
4302 aZCodec
.BeginCompression();
4303 SvMemoryStream aDestStrm
;
4304 aZCodec
.Write( aDestStrm
, pGraphicAry
, p_EscherBlibEntry
->mnSize
);
4305 aZCodec
.EndCompression();
4306 p_EscherBlibEntry
->mnSize
= aDestStrm
.TellEnd();
4307 pGraphicAry
= static_cast<sal_uInt8
const *>(aDestStrm
.GetData());
4308 if ( p_EscherBlibEntry
->mnSize
&& pGraphicAry
)
4310 nExtra
= eBlibType
== WMF
? 0x42 : 0x32; // !EMF -> no change
4311 p_EscherBlibEntry
->mnSizeExtra
= nExtra
+ 8;
4312 nInstance
= ( eBlibType
== WMF
) ? 0xf01b2170 : 0xf01a3d40; // !EMF -> no change
4313 rPicOutStrm
.WriteUInt32( nInstance
).WriteUInt32( p_EscherBlibEntry
->mnSize
+ nExtra
);
4314 if ( eBlibType
== WMF
) // !EMF -> no change
4315 rPicOutStrm
.WriteBytes(p_EscherBlibEntry
->mnIdentifier
, 16);
4316 rPicOutStrm
.WriteBytes(p_EscherBlibEntry
->mnIdentifier
, 16);
4320 For Word the stored size of the graphic is critical the
4321 metafile boundaries must match the actual graphics
4322 boundaries, and the width and height must be in EMU's
4324 If you don't do it this way then objects edited in the
4325 msoffice app may show strange behaviour as the size jumps
4326 around, and the original size and scaling factor in word
4327 will be a very strange figure
4329 sal_uInt32 nPrefWidth
= p_EscherBlibEntry
->maPrefSize
.Width();
4330 sal_uInt32 nPrefHeight
= p_EscherBlibEntry
->maPrefSize
.Height();
4331 sal_uInt32 nWidth
, nHeight
;
4334 nWidth
= pVisArea
->Width
* 360;
4335 nHeight
= pVisArea
->Height
* 360;
4339 Size
aPrefSize(lcl_SizeToEmu(p_EscherBlibEntry
->maPrefSize
, p_EscherBlibEntry
->maPrefMapMode
));
4340 nWidth
= aPrefSize
.Width() * 360;
4341 nHeight
= aPrefSize
.Height() * 360;
4343 rPicOutStrm
.WriteUInt32( nUncompressedSize
) // WMFSize without FileHeader
4344 .WriteInt32( 0 ) // since we can't find out anymore what the original size of
4345 .WriteInt32( 0 ) // the WMF (without Fileheader) was we write 10cm / x
4346 .WriteUInt32( nPrefWidth
)
4347 .WriteUInt32( nPrefHeight
)
4348 .WriteUInt32( nWidth
)
4349 .WriteUInt32( nHeight
)
4350 .WriteUInt32( p_EscherBlibEntry
->mnSize
)
4351 .WriteUInt16( 0xfe00 ); // compression Flags
4352 rPicOutStrm
.WriteBytes(pGraphicAry
, p_EscherBlibEntry
->mnSize
);
4357 sal_uInt64 nPos
= rPicOutStrm
.Tell();
4358 rPicOutStrm
.Seek( nAtomSize
- 4 );
4359 rPicOutStrm
.WriteUInt32( nPos
- nAtomSize
);
4360 rPicOutStrm
.Seek( nPos
);
4362 nBlibId
= ImplInsertBlib( p_EscherBlibEntry
.release() );
4370 struct EscherConnectorRule
4373 sal_uInt32 nShapeA
; // SPID of shape A
4374 sal_uInt32 nShapeB
; // SPID of shape B
4375 sal_uInt32 nShapeC
; // SPID of connector shape
4376 sal_uInt32 ncptiA
; // Connection site Index of shape A
4377 sal_uInt32 ncptiB
; // Connection site Index of shape B
4382 struct EscherShapeListEntry
4384 uno::Reference
<drawing::XShape
>aXShape
;
4385 sal_uInt32 n_EscherId
;
4387 EscherShapeListEntry(uno::Reference
<drawing::XShape
> xShape
, sal_uInt32 nId
)
4388 : aXShape(std::move(xShape
))
4393 sal_uInt32
EscherConnectorListEntry::GetClosestPoint( const tools::Polygon
& rPoly
, const awt::Point
& rPoint
)
4395 sal_uInt16 nCount
= rPoly
.GetSize();
4396 sal_uInt16 nClosest
= nCount
;
4397 double fDist
= sal_uInt32(0xffffffff);
4400 double fDistance
= hypot( rPoint
.X
- rPoly
[ nCount
].X(), rPoint
.Y
- rPoly
[ nCount
].Y() );
4401 if ( fDistance
< fDist
)
4411 // for rectangles for ellipses for polygons
4413 // nRule = 0 ->Top 0 ->Top nRule = index to a (Poly)Polygon point
4414 // 1 ->Left 2 ->Left
4415 // 2 ->Bottom 4 ->Bottom
4416 // 3 ->Right 6 ->Right
4418 sal_uInt32
EscherConnectorListEntry::GetConnectorRule( bool bFirst
)
4420 sal_uInt32 nRule
= 0;
4423 awt::Point
aRefPoint( bFirst
? maPointA
: maPointB
);
4424 uno::Reference
<drawing::XShape
>
4425 aXShape( bFirst
? mXConnectToA
: mXConnectToB
);
4427 OUString
aString(aXShape
->getShapeType());
4428 OStringBuffer
aBuf(OUStringToOString(aString
, RTL_TEXTENCODING_UTF8
));
4429 aBuf
.remove( 0, 13 ); // removing "com.sun.star."
4430 sal_Int16 nPos
= aBuf
.toString().indexOf("Shape");
4431 aBuf
.remove(nPos
, 5);
4432 OString aType
= aBuf
.makeStringAndClear();
4434 uno::Reference
<beans::XPropertySet
>
4435 aPropertySet( aXShape
, uno::UNO_QUERY
);
4437 if ((aType
== "drawing.PolyPolygon") || (aType
== "drawing.PolyLine"))
4439 if ( aPropertySet
.is() )
4441 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aPropertySet
, u
"PolyPolygon"_ustr
) )
4443 auto pSourcePolyPolygon
=
4444 o3tl::doAccess
<drawing::PointSequenceSequence
>(aAny
);
4445 sal_Int32 nOuterSequenceCount
= pSourcePolyPolygon
->getLength();
4446 drawing::PointSequence
const * pOuterSequence
= pSourcePolyPolygon
->getConstArray();
4448 if ( pOuterSequence
)
4450 sal_Int32 a
, b
, nIndex
= 0;
4451 sal_uInt32 nDistance
= 0xffffffff;
4452 for( a
= 0; a
< nOuterSequenceCount
; a
++ )
4454 drawing::PointSequence
const * pInnerSequence
= pOuterSequence
++;
4455 if ( pInnerSequence
)
4457 awt::Point
const * pArray
= pInnerSequence
->getConstArray();
4460 for ( b
= 0; b
< pInnerSequence
->getLength(); b
++, nIndex
++, pArray
++ )
4462 sal_uInt32 nDist
= static_cast<sal_uInt32
>(hypot( aRefPoint
.X
- pArray
->X
, aRefPoint
.Y
- pArray
->Y
));
4463 if ( nDist
< nDistance
)
4476 else if ((aType
== "drawing.OpenBezier") || (aType
== "drawing.OpenFreeHand") || (aType
== "drawing.PolyLinePath")
4477 || (aType
== "drawing.ClosedBezier") || ( aType
== "drawing.ClosedFreeHand") || (aType
== "drawing.PolyPolygonPath") )
4479 uno::Reference
<beans::XPropertySet
>
4480 aPropertySet2( aXShape
, uno::UNO_QUERY
);
4481 if ( aPropertySet2
.is() )
4483 if ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aPropertySet2
, u
"PolyPolygonBezier"_ustr
) )
4485 auto pSourcePolyPolygon
=
4486 o3tl::doAccess
<drawing::PolyPolygonBezierCoords
>(aAny
);
4487 sal_Int32 nOuterSequenceCount
= pSourcePolyPolygon
->Coordinates
.getLength();
4489 // get pointer of inner sequences
4490 drawing::PointSequence
const * pOuterSequence
=
4491 pSourcePolyPolygon
->Coordinates
.getConstArray();
4492 drawing::FlagSequence
const * pOuterFlags
=
4493 pSourcePolyPolygon
->Flags
.getConstArray();
4495 if ( pOuterSequence
&& pOuterFlags
)
4497 sal_Int32 a
, b
, nIndex
= 0;
4498 sal_uInt32 nDistance
= 0xffffffff;
4500 for ( a
= 0; a
< nOuterSequenceCount
; a
++ )
4502 drawing::PointSequence
const * pInnerSequence
= pOuterSequence
++;
4503 drawing::FlagSequence
const * pInnerFlags
= pOuterFlags
++;
4504 if ( pInnerSequence
&& pInnerFlags
)
4506 awt::Point
const * pArray
= pInnerSequence
->getConstArray();
4507 drawing::PolygonFlags
const * pFlags
= pInnerFlags
->getConstArray();
4508 if ( pArray
&& pFlags
)
4510 for ( b
= 0; b
< pInnerSequence
->getLength(); b
++, pArray
++ )
4512 drawing::PolygonFlags ePolyFlags
= *pFlags
++;
4513 if ( ePolyFlags
== drawing::PolygonFlags_CONTROL
)
4515 sal_uInt32 nDist
= static_cast<sal_uInt32
>(hypot( aRefPoint
.X
- pArray
->X
, aRefPoint
.Y
- pArray
->Y
));
4516 if ( nDist
< nDistance
)
4532 bool bRectangularConnection
= true;
4534 if (aType
== "drawing.Custom")
4536 if (auto pSdrObjCustomShape
= dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(aXShape
)))
4538 const SdrCustomShapeGeometryItem
& rGeometryItem
=
4539 pSdrObjCustomShape
->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
4541 OUString sShapeType
;
4542 const uno::Any
* pType
= rGeometryItem
.GetPropertyValueByName( u
"Type"_ustr
);
4544 *pType
>>= sShapeType
;
4545 MSO_SPT eSpType
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
4547 const uno::Any
* pGluePointType
= rGeometryItem
.GetPropertyValueByName( u
"Path"_ustr
, u
"GluePointType"_ustr
);
4549 sal_Int16 nGluePointType
= sal_Int16();
4550 if ( !( pGluePointType
&&
4551 ( *pGluePointType
>>= nGluePointType
) ) )
4552 nGluePointType
= GetCustomShapeConnectionTypeDefault( eSpType
);
4554 if ( nGluePointType
== drawing::EnhancedCustomShapeGluePointType::CUSTOM
)
4556 const SdrGluePointList
* pList
= pSdrObjCustomShape
->GetGluePointList();
4559 tools::Polygon aPoly
;
4560 sal_uInt16 nNum
, nCnt
= pList
->GetCount();
4563 for ( nNum
= 0; nNum
< nCnt
; nNum
++ )
4565 const SdrGluePoint
& rGP
= (*pList
)[ nNum
];
4566 Point
aPt(rGP
.GetAbsolutePos(*pSdrObjCustomShape
));
4567 aPoly
.Insert( POLY_APPEND
, aPt
);
4569 nRule
= GetClosestPoint( aPoly
, aRefPoint
);
4570 bRectangularConnection
= false;
4574 else if ( nGluePointType
== drawing::EnhancedCustomShapeGluePointType::SEGMENTS
)
4576 tools::PolyPolygon aPolyPoly
;
4577 rtl::Reference
<SdrObject
> pTemporaryConvertResultObject(pSdrObjCustomShape
->DoConvertToPolyObj(true, true));
4578 SdrPathObj
* pSdrPathObj(dynamic_cast< SdrPathObj
* >(pTemporaryConvertResultObject
.get()));
4582 // #i74631# use explicit constructor here. Also XPolyPolygon is not necessary,
4583 // reducing to PolyPolygon
4584 aPolyPoly
= tools::PolyPolygon(pSdrPathObj
->GetPathPoly());
4587 // do *not* forget to delete the temporary used SdrObject - possible memory leak (!)
4588 pTemporaryConvertResultObject
.clear();
4589 pSdrPathObj
= nullptr;
4591 if(0 != aPolyPoly
.Count())
4593 sal_Int16 nIndex
= 0;
4595 sal_uInt32 nDistance
= 0xffffffff;
4597 for ( a
= 0; a
< aPolyPoly
.Count(); a
++ )
4599 const tools::Polygon
& rPoly
= aPolyPoly
.GetObject( a
);
4600 for ( b
= 0; b
< rPoly
.GetSize(); b
++ )
4602 if ( rPoly
.GetFlags( b
) != PolyFlags::Normal
)
4604 const Point
& rPt
= rPoly
[ b
];
4605 sal_uInt32 nDist
= static_cast<sal_uInt32
>(hypot( aRefPoint
.X
- rPt
.X(), aRefPoint
.Y
- rPt
.Y() ));
4606 if ( nDist
< nDistance
)
4615 if ( nDistance
!= 0xffffffff )
4616 bRectangularConnection
= false;
4621 if ( bRectangularConnection
)
4623 awt::Point
aPoint( aXShape
->getPosition() );
4624 awt::Size
aSize( aXShape
->getSize() );
4626 tools::Rectangle
aRect( Point( aPoint
.X
, aPoint
.Y
), Size( aSize
.Width
, aSize
.Height
) );
4627 Point
aCenter( aRect
.Center() );
4628 tools::Polygon
aPoly( 4 );
4630 aPoly
[ 0 ] = Point( aCenter
.X(), aRect
.Top() );
4631 aPoly
[ 1 ] = Point( aRect
.Left(), aCenter
.Y() );
4632 aPoly
[ 2 ] = Point( aCenter
.X(), aRect
.Bottom() );
4633 aPoly
[ 3 ] = Point( aRect
.Right(), aCenter
.Y() );
4635 sal_Int32 nAngle
= ( EscherPropertyValueHelper::GetPropertyValue( aAny
, aPropertySet
, u
"RotateAngle"_ustr
, true ) )
4636 ? *o3tl::doAccess
<sal_Int32
>(aAny
) : 0;
4638 aPoly
.Rotate( aRect
.TopLeft(), Degree10(static_cast<sal_Int16
>( ( nAngle
+ 5 ) / 10 )) );
4639 nRule
= GetClosestPoint( aPoly
, aRefPoint
);
4641 if (aType
== "drawing.Ellipse")
4642 nRule
<<= 1; // In PPT an ellipse has 8 ways to connect
4648 EscherSolverContainer::EscherSolverContainer()
4652 EscherSolverContainer::~EscherSolverContainer()
4656 void EscherSolverContainer::AddShape( const uno::Reference
<drawing::XShape
> & rXShape
, sal_uInt32 nId
)
4658 maShapeList
.push_back( std::make_unique
<EscherShapeListEntry
>( rXShape
, nId
) );
4661 void EscherSolverContainer::AddConnector(
4662 const uno::Reference
<drawing::XShape
> & rConnector
,
4663 const awt::Point
& rPA
,
4664 uno::Reference
<drawing::XShape
> const & rConA
,
4665 const awt::Point
& rPB
,
4666 uno::Reference
<drawing::XShape
> const & rConB
4669 maConnectorList
.push_back( std::make_unique
<EscherConnectorListEntry
>( rConnector
, rPA
, rConA
, rPB
, rConB
) );
4672 sal_uInt32
EscherSolverContainer::GetShapeId( const uno::Reference
<drawing::XShape
> & rXShape
) const
4674 for (auto const & pPtr
: maShapeList
)
4676 if ( rXShape
== pPtr
->aXShape
)
4677 return pPtr
->n_EscherId
;
4682 void EscherSolverContainer::WriteSolver( SvStream
& rStrm
)
4684 sal_uInt32 nCount
= maConnectorList
.size();
4688 sal_uInt32 nRecHdPos
, nCurrentPos
, nSize
;
4689 rStrm
.WriteUInt16( ( nCount
<< 4 ) | 0xf ) // open an ESCHER_SolverContainer
4690 .WriteUInt16( ESCHER_SolverContainer
)
4693 nRecHdPos
= rStrm
.Tell() - 4;
4695 EscherConnectorRule aConnectorRule
;
4696 aConnectorRule
.nRuleId
= 2;
4697 for (auto const & pPtr
: maConnectorList
)
4699 aConnectorRule
.ncptiA
= aConnectorRule
.ncptiB
= 0xffffffff;
4700 aConnectorRule
.nShapeC
= GetShapeId( pPtr
->mXConnector
);
4701 aConnectorRule
.nShapeA
= GetShapeId( pPtr
->mXConnectToA
);
4702 aConnectorRule
.nShapeB
= GetShapeId( pPtr
->mXConnectToB
);
4704 if ( aConnectorRule
.nShapeC
)
4706 if ( aConnectorRule
.nShapeA
)
4707 aConnectorRule
.ncptiA
= pPtr
->GetConnectorRule( true );
4708 if ( aConnectorRule
.nShapeB
)
4709 aConnectorRule
.ncptiB
= pPtr
->GetConnectorRule( false );
4711 rStrm
.WriteUInt32( ( ESCHER_ConnectorRule
<< 16 ) | 1 ) // atom hd
4713 .WriteUInt32( aConnectorRule
.nRuleId
)
4714 .WriteUInt32( aConnectorRule
.nShapeA
)
4715 .WriteUInt32( aConnectorRule
.nShapeB
)
4716 .WriteUInt32( aConnectorRule
.nShapeC
)
4717 .WriteUInt32( aConnectorRule
.ncptiA
)
4718 .WriteUInt32( aConnectorRule
.ncptiB
);
4720 aConnectorRule
.nRuleId
+= 2;
4723 nCurrentPos
= rStrm
.Tell(); // close the ESCHER_SolverContainer
4724 nSize
= ( nCurrentPos
- nRecHdPos
) - 4;
4725 rStrm
.Seek( nRecHdPos
);
4726 rStrm
.WriteUInt32( nSize
);
4727 rStrm
.Seek( nCurrentPos
);
4730 EscherExGlobal::EscherExGlobal() :
4731 EscherGraphicProvider( EscherGraphicProviderFlags::NONE
),
4732 mpPicStrm( nullptr ),
4733 mbHasDggCont( false ),
4734 mbPicStrmQueried( false )
4738 EscherExGlobal::~EscherExGlobal()
4742 sal_uInt32
EscherExGlobal::GenerateDrawingId()
4744 // new drawing starts a new cluster in the cluster table (cluster identifiers are one-based)
4745 sal_uInt32 nClusterId
= static_cast< sal_uInt32
>( maClusterTable
.size() + 1 );
4746 // drawing identifiers are one-based
4747 sal_uInt32 nDrawingId
= static_cast< sal_uInt32
>( maDrawingInfos
.size() + 1 );
4748 // prepare new entries in the tables
4749 maClusterTable
.emplace_back( nDrawingId
);
4750 maDrawingInfos
.emplace_back( nClusterId
);
4751 // return the new drawing identifier
4755 sal_uInt32
EscherExGlobal::GenerateShapeId( sal_uInt32 nDrawingId
, bool bIsInSpgr
)
4757 // drawing identifier is one-based
4758 // make sure the drawing is valid (bnc#656503)
4759 if ( nDrawingId
== 0 )
4761 // create index from the identifier
4762 size_t nDrawingIdx
= nDrawingId
- 1;
4763 OSL_ENSURE( nDrawingIdx
< maDrawingInfos
.size(), "EscherExGlobal::GenerateShapeId - invalid drawing ID" );
4764 if( nDrawingIdx
>= maDrawingInfos
.size() )
4766 DrawingInfo
& rDrawingInfo
= maDrawingInfos
[ nDrawingIdx
];
4768 // cluster identifier in drawing info struct is one-based
4769 ClusterEntry
* pClusterEntry
= &maClusterTable
[ rDrawingInfo
.mnClusterId
- 1 ];
4771 // check cluster overflow, create new cluster entry
4772 if( pClusterEntry
->mnNextShapeId
== DFF_DGG_CLUSTER_SIZE
)
4774 // start a new cluster in the cluster table
4775 maClusterTable
.emplace_back( nDrawingId
);
4776 pClusterEntry
= &maClusterTable
.back();
4777 // new size of maClusterTable is equal to one-based identifier of the new cluster
4778 rDrawingInfo
.mnClusterId
= static_cast< sal_uInt32
>( maClusterTable
.size() );
4781 // build shape identifier from cluster identifier and next free cluster shape identifier
4782 rDrawingInfo
.mnLastShapeId
= static_cast< sal_uInt32
>( rDrawingInfo
.mnClusterId
* DFF_DGG_CLUSTER_SIZE
+ pClusterEntry
->mnNextShapeId
);
4783 // update free shape identifier in cluster entry
4784 ++pClusterEntry
->mnNextShapeId
;
4785 /* Old code has counted the shapes only, if we are in a SPGRCONTAINER. Is
4786 this really intended? Maybe it's always true... */
4788 ++rDrawingInfo
.mnShapeCount
;
4790 // return the new shape identifier
4791 return rDrawingInfo
.mnLastShapeId
;
4794 sal_uInt32
EscherExGlobal::GetDrawingShapeCount( sal_uInt32 nDrawingId
) const
4796 size_t nDrawingIdx
= nDrawingId
- 1;
4797 OSL_ENSURE( nDrawingIdx
< maDrawingInfos
.size(), "EscherExGlobal::GetDrawingShapeCount - invalid drawing ID" );
4798 return (nDrawingIdx
< maDrawingInfos
.size()) ? maDrawingInfos
[ nDrawingIdx
].mnShapeCount
: 0;
4801 sal_uInt32
EscherExGlobal::GetLastShapeId( sal_uInt32 nDrawingId
) const
4803 size_t nDrawingIdx
= nDrawingId
- 1;
4804 OSL_ENSURE( nDrawingIdx
< maDrawingInfos
.size(), "EscherExGlobal::GetLastShapeId - invalid drawing ID" );
4805 return (nDrawingIdx
< maDrawingInfos
.size()) ? maDrawingInfos
[ nDrawingIdx
].mnLastShapeId
: 0;
4808 sal_uInt32
EscherExGlobal::GetDggAtomSize() const
4810 // 8 bytes header, 16 bytes fixed DGG data, 8 bytes for each cluster
4811 return static_cast< sal_uInt32
>( 24 + 8 * maClusterTable
.size() );
4814 void EscherExGlobal::WriteDggAtom( SvStream
& rStrm
) const
4816 sal_uInt32 nDggSize
= GetDggAtomSize();
4818 // write the DGG record header (do not include the 8 bytes of the header in the data size)
4819 rStrm
.WriteUInt32( ESCHER_Dgg
<< 16 ).WriteUInt32( nDggSize
- 8 );
4821 // calculate and write the fixed DGG data
4822 sal_uInt32 nShapeCount
= 0;
4823 sal_uInt32 nLastShapeId
= 0;
4824 for (auto const& drawingInfo
: maDrawingInfos
)
4826 nShapeCount
+= drawingInfo
.mnShapeCount
;
4827 nLastShapeId
= ::std::max( nLastShapeId
, drawingInfo
.mnLastShapeId
);
4829 // the non-existing cluster with index #0 is counted too
4830 sal_uInt32 nClusterCount
= static_cast< sal_uInt32
>( maClusterTable
.size() + 1 );
4831 sal_uInt32 nDrawingCount
= static_cast< sal_uInt32
>( maDrawingInfos
.size() );
4832 rStrm
.WriteUInt32( nLastShapeId
).WriteUInt32( nClusterCount
).WriteUInt32( nShapeCount
).WriteUInt32( nDrawingCount
);
4834 // write the cluster table
4835 for (auto const& elem
: maClusterTable
)
4836 rStrm
.WriteUInt32( elem
.mnDrawingId
).WriteUInt32( elem
.mnNextShapeId
);
4839 SvStream
* EscherExGlobal::QueryPictureStream()
4841 if( !mbPicStrmQueried
)
4843 mpPicStrm
= ImplQueryPictureStream();
4844 mbPicStrmQueried
= true;
4849 SvStream
* EscherExGlobal::ImplQueryPictureStream()
4856 // Implementation of an empty stream that silently succeeds, but does nothing.
4858 // In fact, this is a hack. The right solution is to abstract EscherEx to be
4859 // able to work without SvStream; but at the moment it is better to live with
4861 class SvNullStream
: public SvStream
4864 virtual std::size_t GetData( void* pData
, std::size_t nSize
) override
{ memset( pData
, 0, nSize
); return nSize
; }
4865 virtual std::size_t PutData( const void*, std::size_t nSize
) override
{ return nSize
; }
4866 virtual sal_uInt64
SeekPos( sal_uInt64 nPos
) override
{ return nPos
; }
4867 virtual void SetSize( sal_uInt64
) override
{}
4868 virtual void FlushData() override
{}
4876 EscherEx::EscherEx(std::shared_ptr
<EscherExGlobal
> xGlobal
, SvStream
* pOutStrm
, bool bOOXML
)
4877 : mxGlobal(std::move(xGlobal
))
4878 , mpOutStrm(pOutStrm
)
4882 , mnHellLayerId(SDRLAYER_NOTFOUND
)
4883 , mnHeaderFooterHellLayerId(SDRLAYER_NOTFOUND
)
4884 , mbEscherSpgr(false)
4890 mxOwnStrm
= std::make_unique
<SvNullStream
>();
4891 mpOutStrm
= mxOwnStrm
.get();
4893 mnStrmStartOfs
= mpOutStrm
->Tell();
4894 mpImplEESdrWriter
.reset( new ImplEESdrWriter( *this ) );
4897 EscherEx::~EscherEx()
4901 void EscherEx::Flush( SvStream
* pPicStreamMergeBSE
/* = NULL */ )
4903 if ( !mxGlobal
->HasDggContainer() )
4906 // store the current stream position at ESCHER_Persist_CurrentPosition key
4907 PtReplaceOrInsert( ESCHER_Persist_CurrentPosition
, mpOutStrm
->Tell() );
4908 if ( DoSeek( ESCHER_Persist_Dgg
) )
4910 /* The DGG record is still not written. ESCHER_Persist_Dgg seeks
4911 to the place where the complete record has to be inserted. */
4912 InsertAtCurrentPos( mxGlobal
->GetDggAtomSize() );
4913 mxGlobal
->WriteDggAtom( *mpOutStrm
);
4915 if ( mxGlobal
->HasGraphics() )
4917 /* Calculate the total size of the BSTORECONTAINER including
4918 all BSE records containing the picture data contained in
4919 the passed in pPicStreamMergeBSE. */
4920 sal_uInt32 nBSCSize
= mxGlobal
->GetBlibStoreContainerSize( pPicStreamMergeBSE
);
4923 InsertAtCurrentPos( nBSCSize
);
4924 mxGlobal
->WriteBlibStoreContainer( *mpOutStrm
, pPicStreamMergeBSE
);
4928 /* Forget the stream position stored for the DGG which is invalid
4929 after the call to InsertAtCurrentPos() anyway. */
4930 PtDelete( ESCHER_Persist_Dgg
);
4932 // seek to initial position (may be different due to inserted DGG and BLIPs)
4933 mpOutStrm
->Seek( PtGetOffsetByID( ESCHER_Persist_CurrentPosition
) );
4936 void EscherEx::InsertAtCurrentPos( sal_uInt32 nBytes
)
4938 sal_uInt32 nSize
, nType
, nSource
, nBufSize
, nToCopy
;
4939 sal_uInt64 nCurPos
= mpOutStrm
->Tell();
4941 // adjust persist table
4942 for(auto const & pPtr
: maPersistTable
) {
4943 sal_uInt32 nOfs
= pPtr
->mnOffset
;
4944 if ( nOfs
>= nCurPos
) {
4945 pPtr
->mnOffset
+= nBytes
;
4949 // adapt container and atom sizes
4950 mpOutStrm
->Seek( mnStrmStartOfs
);
4951 while ( mpOutStrm
->Tell() < nCurPos
)
4953 mpOutStrm
->ReadUInt32( nType
).ReadUInt32( nSize
);
4954 sal_uInt64 nEndOfRecord
= mpOutStrm
->Tell() + nSize
;
4955 bool bContainer
= (nType
& 0x0F) == 0x0F;
4956 /* Expand the record, if the insertion position is inside, or if the
4957 position is at the end of a container (expands always), or at the
4958 end of an atom and bExpandEndOfAtom is set. */
4959 if ( (nCurPos
< nEndOfRecord
) || ((nCurPos
== nEndOfRecord
) && bContainer
) )
4961 mpOutStrm
->SeekRel( -4 );
4962 mpOutStrm
->WriteUInt32( nSize
+ nBytes
);
4964 mpOutStrm
->SeekRel( nSize
);
4967 mpOutStrm
->SeekRel( nSize
);
4969 for (auto & offset
: mOffsets
)
4971 if ( offset
> nCurPos
)
4974 nSource
= mpOutStrm
->TellEnd();
4975 nToCopy
= nSource
- nCurPos
; // increase the size of the stream by nBytes
4976 std::unique_ptr
<sal_uInt8
[]> pBuf(new sal_uInt8
[ 0x40000 ]); // 256KB Buffer
4979 nBufSize
= ( nToCopy
>= 0x40000 ) ? 0x40000 : nToCopy
;
4980 nToCopy
-= nBufSize
;
4981 nSource
-= nBufSize
;
4982 mpOutStrm
->Seek( nSource
);
4983 mpOutStrm
->ReadBytes(pBuf
.get(), nBufSize
);
4984 mpOutStrm
->Seek( nSource
+ nBytes
);
4985 mpOutStrm
->WriteBytes(pBuf
.get(), nBufSize
);
4987 mpOutStrm
->Seek( nCurPos
);
4990 void EscherEx::InsertPersistOffset( sal_uInt32 nKey
, sal_uInt32 nOffset
)
4992 PtInsert( ESCHER_Persist_PrivateEntry
| nKey
, nOffset
);
4995 void EscherEx::ReplacePersistOffset( sal_uInt32 nKey
, sal_uInt32 nOffset
)
4997 PtReplace( ESCHER_Persist_PrivateEntry
| nKey
, nOffset
);
5000 void EscherEx::SetEditAs( const OUString
& rEditAs
)
5005 sal_uInt32
EscherEx::GetPersistOffset( sal_uInt32 nKey
)
5007 return PtGetOffsetByID( ESCHER_Persist_PrivateEntry
| nKey
);
5010 bool EscherEx::DoSeek( sal_uInt32 nKey
)
5012 sal_uInt32 nPos
= PtGetOffsetByID( nKey
);
5014 mpOutStrm
->Seek( nPos
);
5017 if (! PtIsID( nKey
) )
5019 mpOutStrm
->Seek( 0 );
5024 bool EscherEx::SeekToPersistOffset( sal_uInt32 nKey
)
5026 return DoSeek( ESCHER_Persist_PrivateEntry
| nKey
);
5029 void EscherEx::InsertAtPersistOffset( sal_uInt32 nKey
, sal_uInt32 nValue
)
5031 sal_uInt64 nOldPos
= mpOutStrm
->Tell();
5032 bool bRetValue
= SeekToPersistOffset( nKey
);
5035 mpOutStrm
->WriteUInt32( nValue
);
5036 mpOutStrm
->Seek( nOldPos
);
5040 void EscherEx::OpenContainer( sal_uInt16 nEscherContainer
, int nRecInstance
)
5042 mpOutStrm
->WriteUInt16( ( nRecInstance
<< 4 ) | 0xf ).WriteUInt16( nEscherContainer
).WriteUInt32( 0 );
5043 mOffsets
.push_back( mpOutStrm
->Tell() - 4 );
5044 mRecTypes
.push_back( nEscherContainer
);
5045 switch( nEscherContainer
)
5047 case ESCHER_DggContainer
:
5049 mxGlobal
->SetDggContainer();
5051 /* Remember the current position as start position of the DGG
5052 record and BSTORECONTAINER, but do not write them actually.
5053 This will be done later in Flush() when the number of drawings,
5054 the size and contents of the FIDCL cluster table, and the size
5055 of the BLIP container are known. */
5056 PtReplaceOrInsert( ESCHER_Persist_Dgg
, mpOutStrm
->Tell() );
5060 case ESCHER_DgContainer
:
5062 if ( mxGlobal
->HasDggContainer() )
5067 mnCurrentDg
= mxGlobal
->GenerateDrawingId();
5068 AddAtom( 8, ESCHER_Dg
, 0, mnCurrentDg
);
5069 PtReplaceOrInsert( ESCHER_Persist_Dg
| mnCurrentDg
, mpOutStrm
->Tell() );
5070 mpOutStrm
->WriteUInt32( 0 ) // The number of shapes in this drawing
5071 .WriteUInt32( 0 ); // The last MSOSPID given to an SP in this DG
5077 case ESCHER_SpgrContainer
:
5081 mbEscherSpgr
= true;
5086 case ESCHER_SpContainer
:
5096 void EscherEx::CloseContainer()
5098 sal_uInt64 nPos
= mpOutStrm
->Tell();
5099 sal_uInt32 nSize
= ( nPos
- mOffsets
.back() ) - 4;
5100 mpOutStrm
->Seek( mOffsets
.back() );
5101 mpOutStrm
->WriteUInt32( nSize
);
5103 switch( mRecTypes
.back() )
5105 case ESCHER_DgContainer
:
5110 if ( DoSeek( ESCHER_Persist_Dg
| mnCurrentDg
) )
5111 mpOutStrm
->WriteUInt32( mxGlobal
->GetDrawingShapeCount( mnCurrentDg
) ).WriteUInt32( mxGlobal
->GetLastShapeId( mnCurrentDg
) );
5116 case ESCHER_SpgrContainer
:
5120 mbEscherSpgr
= false;
5129 mOffsets
.pop_back();
5130 mRecTypes
.pop_back();
5131 mpOutStrm
->Seek( nPos
);
5134 void EscherEx::BeginAtom()
5136 mnCountOfs
= mpOutStrm
->Tell();
5137 mpOutStrm
->WriteUInt32( 0 ).WriteUInt32( 0 ); // record header will be written later
5140 void EscherEx::EndAtom( sal_uInt16 nRecType
, int nRecVersion
, int nRecInstance
)
5142 sal_uInt64 nOldPos
= mpOutStrm
->Tell();
5143 mpOutStrm
->Seek( mnCountOfs
);
5144 sal_uInt32 nSize
= nOldPos
- mnCountOfs
;
5145 mpOutStrm
->WriteUInt16( ( nRecInstance
<< 4 ) | ( nRecVersion
& 0xf ) ).WriteUInt16( nRecType
).WriteUInt32( nSize
- 8 );
5146 mpOutStrm
->Seek( nOldPos
);
5149 void EscherEx::AddAtom( sal_uInt32 nAtomSize
, sal_uInt16 nRecType
, int nRecVersion
, int nRecInstance
)
5151 mpOutStrm
->WriteUInt16( ( nRecInstance
<< 4 ) | ( nRecVersion
& 0xf ) ).WriteUInt16( nRecType
).WriteUInt32( nAtomSize
);
5154 void EscherEx::AddChildAnchor( const tools::Rectangle
& rRect
)
5156 AddAtom( 16, ESCHER_ChildAnchor
);
5157 mpOutStrm
->WriteInt32( rRect
.Left() )
5158 .WriteInt32( rRect
.Top() )
5159 .WriteInt32( rRect
.Right() )
5160 .WriteInt32( rRect
.Bottom() );
5163 void EscherEx::AddClientAnchor( const tools::Rectangle
& rRect
)
5165 AddAtom( 8, ESCHER_ClientAnchor
);
5166 mpOutStrm
->WriteInt16( rRect
.Top() )
5167 .WriteInt16( rRect
.Left() )
5168 .WriteInt16( rRect
.GetWidth() + rRect
.Left() )
5169 .WriteInt16( rRect
.GetHeight() + rRect
.Top() );
5172 EscherExHostAppData
* EscherEx::EnterAdditionalTextGroup()
5177 sal_uInt32
EscherEx::EnterGroup( const OUString
& rShapeName
, const tools::Rectangle
* pBoundRect
)
5179 tools::Rectangle aRect
;
5181 aRect
= *pBoundRect
;
5183 OpenContainer( ESCHER_SpgrContainer
);
5184 OpenContainer( ESCHER_SpContainer
);
5185 AddAtom( 16, ESCHER_Spgr
, 1 );
5186 PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap
| mnGroupLevel
,
5187 mpOutStrm
->Tell() );
5188 mpOutStrm
->WriteInt32( aRect
.Left() ) // Bounding box for the grouped shapes to which they will be attached
5189 .WriteInt32( aRect
.Top() )
5190 .WriteInt32( aRect
.IsWidthEmpty() ? aRect
.Left() : aRect
.Right() )
5191 .WriteInt32( aRect
.IsHeightEmpty() ? aRect
.Top() : aRect
.Bottom() );
5193 sal_uInt32 nShapeId
= GenerateShapeId();
5194 if ( !mnGroupLevel
)
5195 AddShape( ESCHER_ShpInst_Min
, ShapeFlag::Group
| ShapeFlag::Patriarch
, nShapeId
);
5198 AddShape( ESCHER_ShpInst_Min
, ShapeFlag::Group
| ShapeFlag::HaveAnchor
, nShapeId
);
5199 EscherPropertyContainer aPropOpt
;
5200 aPropOpt
.AddOpt( ESCHER_Prop_LockAgainstGrouping
, 0x00040004 );
5201 aPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistLeft
, 0 );
5202 aPropOpt
.AddOpt( ESCHER_Prop_dxWrapDistRight
, 0 );
5204 // #i51348# shape name
5205 if( rShapeName
.getLength() > 0 )
5206 aPropOpt
.AddOpt( ESCHER_Prop_wzName
, rShapeName
);
5208 Commit( aPropOpt
, aRect
);
5209 if ( mnGroupLevel
> 1 )
5210 AddChildAnchor( aRect
);
5212 EscherExHostAppData
* pAppData
= mpImplEESdrWriter
->ImplGetHostData();
5215 if ( mnGroupLevel
<= 1 )
5216 pAppData
->WriteClientAnchor( *this, aRect
);
5217 pAppData
->WriteClientData( *this );
5220 CloseContainer(); // ESCHER_SpContainer
5225 sal_uInt32
EscherEx::EnterGroup( const tools::Rectangle
* pBoundRect
)
5227 return EnterGroup( OUString(), pBoundRect
);
5230 void EscherEx::SetGroupSnapRect( sal_uInt32 nGroupLevel
, const tools::Rectangle
& rRect
)
5234 sal_uInt64 nCurrentPos
= mpOutStrm
->Tell();
5235 if ( DoSeek( ESCHER_Persist_Grouping_Snap
| ( nGroupLevel
- 1 ) ) )
5237 mpOutStrm
->WriteInt32( rRect
.Left() ) // Bounding box for the grouped shapes to which they will be attached
5238 .WriteInt32( rRect
.Top() )
5239 .WriteInt32( rRect
.Right() )
5240 .WriteInt32( rRect
.Bottom() );
5241 mpOutStrm
->Seek( nCurrentPos
);
5246 void EscherEx::SetGroupLogicRect( sal_uInt32 nGroupLevel
, const tools::Rectangle
& rRect
)
5250 sal_uInt64 nCurrentPos
= mpOutStrm
->Tell();
5251 if ( DoSeek( ESCHER_Persist_Grouping_Logic
| ( nGroupLevel
- 1 ) ) )
5253 mpOutStrm
->WriteInt16( rRect
.Top() ).WriteInt16( rRect
.Left() ).WriteInt16( rRect
.Right() ).WriteInt16( rRect
.Bottom() );
5254 mpOutStrm
->Seek( nCurrentPos
);
5259 void EscherEx::LeaveGroup()
5262 PtDelete( ESCHER_Persist_Grouping_Snap
| mnGroupLevel
);
5263 PtDelete( ESCHER_Persist_Grouping_Logic
| mnGroupLevel
);
5267 void EscherEx::AddShape( sal_uInt32 nShpInstance
, ShapeFlag nFlags
, sal_uInt32 nShapeID
)
5269 AddAtom( 8, ESCHER_Sp
, 2, nShpInstance
);
5272 nShapeID
= GenerateShapeId();
5274 if (nFlags
^ ShapeFlag::Group
) // no pure group shape
5276 if ( mnGroupLevel
> 1 )
5277 nFlags
|= ShapeFlag::Child
; // this not a topmost shape
5279 mpOutStrm
->WriteUInt32( nShapeID
).WriteUInt32( static_cast<sal_uInt32
>(nFlags
) );
5282 void EscherEx::Commit( EscherPropertyContainer
& rProps
, const tools::Rectangle
& )
5284 rProps
.Commit( GetStream() );
5287 sal_uInt32
EscherEx::GetColor( const sal_uInt32 nSOColor
)
5289 sal_uInt32 nColor
= nSOColor
& 0xff00; // Green
5290 nColor
|= static_cast<sal_uInt8
>(nSOColor
) << 16; // Red
5291 nColor
|= static_cast<sal_uInt8
>( nSOColor
>> 16 ); // Blue
5295 sal_uInt32
EscherEx::GetColor( const Color
& rSOColor
)
5297 sal_uInt32 nColor
= ( rSOColor
.GetRed() << 16 );
5298 nColor
|= ( rSOColor
.GetGreen() << 8 );
5299 nColor
|= rSOColor
.GetBlue();
5300 nColor
= GetColor( nColor
);
5304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */