LibreOffice Module filter (master) 1
escherex.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
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>
34#include <utility>
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>
43#include <stdlib.h>
44#include <vcl/graphicfilter.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>
89#include <comphelper/string.hxx>
90#include <vcl/virdev.hxx>
91#include <rtl/crc.h>
92#include <rtl/strbuf.hxx>
93#include <sal/log.hxx>
97#include <osl/diagnose.h>
98
99#include <algorithm>
100#include <memory>
101
102using namespace css;
103
104EscherExContainer::EscherExContainer( SvStream& rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance ) :
105 rStrm ( rSt )
106{
107 rStrm.WriteUInt32( ( 0xf | ( nInstance << 4 ) ) | ( nRecType << 16 ) ).WriteUInt32( 0 );
108 nContPos = rStrm.Tell();
109}
111{
112 sal_uInt32 nPos = rStrm.Tell();
113 sal_uInt32 nSize= nPos - nContPos;
114 if ( nSize )
115 {
116 rStrm.Seek( nContPos - 4 );
117 rStrm.WriteUInt32( nSize );
118 rStrm.Seek( nPos );
119 }
120}
121
122EscherExAtom::EscherExAtom( SvStream& rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance, const sal_uInt8 nVersion ) :
123 rStrm ( rSt )
124{
125 rStrm.WriteUInt32( ( nVersion | ( nInstance << 4 ) ) | ( nRecType << 16 ) ).WriteUInt32( 0 );
126 nContPos = rStrm.Tell();
127}
129{
130 sal_uInt32 nPos = rStrm.Tell();
131 sal_uInt32 nSize= nPos - nContPos;
132 if ( nSize )
133 {
134 rStrm.Seek( nContPos - 4 );
135 rStrm.WriteUInt32( nSize );
136 rStrm.Seek( nPos );
137 }
138}
139
141{
142}
143
145{
146}
147
149 EscherGraphicProvider * pGraphProv, SvStream * pPiOutStrm,
150 tools::Rectangle * pBoundRect):
151 pGraphicProvider(pGraphProv),
152 pPicOutStrm(pPiOutStrm),
153 pShapeBoundRect(pBoundRect),
154 nCountCount(0),
155 nCountSize(0),
156 bHasComplexData(false)
157{
158 pSortStruct.reserve(64);
159}
160
162 : EscherPropertyContainer(nullptr, nullptr, nullptr)
163{}
164
166 EscherGraphicProvider& rGraphProv,
167 SvStream* pPiOutStrm,
168 tools::Rectangle& rBoundRect ) :
169 EscherPropertyContainer(&rGraphProv, pPiOutStrm, &rBoundRect)
170{}
171
173{
174};
175
177 sal_uInt16 nPropID,
178 bool bBlib,
179 sal_uInt32 nSizeReduction,
180 SvMemoryStream& rStream)
181{
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;
185 aBuf.reserve(nSize);
186
187 for(sal_uInt64 a(0); a < nSize; a++)
188 {
189 aBuf.push_back(*pBuf++);
190 }
191
192 sal_uInt32 nPropValue(static_cast<sal_uInt32>(nSize));
193
194 if(0 != nSizeReduction && nPropValue > nSizeReduction)
195 {
196 nPropValue -= nSizeReduction;
197 }
198
199 AddOpt(nPropID, bBlib, nPropValue, aBuf);
200}
201
203 sal_uInt16 nPropID,
204 sal_uInt32 nPropValue,
205 bool bBlib)
206{
207 AddOpt(nPropID, bBlib, nPropValue, std::vector<sal_uInt8>());
208}
209
211 sal_uInt16 nPropID,
212 std::u16string_view rString)
213{
214 std::vector<sal_uInt8> aBuf;
215 aBuf.reserve(rString.size() * 2 + 2);
216
217 for(size_t i(0); i < rString.size(); i++)
218 {
219 const sal_Unicode nUnicode(rString[i]);
220 aBuf.push_back(static_cast<sal_uInt8>(nUnicode));
221 aBuf.push_back(static_cast<sal_uInt8>(nUnicode >> 8));
222 }
223
224 aBuf.push_back(0);
225 aBuf.push_back(0);
226
227 AddOpt(nPropID, true, aBuf.size(), aBuf);
228}
229
231 sal_uInt16 nPropID,
232 bool bBlib,
233 sal_uInt32 nPropValue,
234 const std::vector<sal_uInt8>& rProp)
235{
236 if ( bBlib ) // bBlib is only valid when fComplex = 0
237 nPropID |= 0x4000;
238 if ( !rProp.empty() )
239 nPropID |= 0x8000; // fComplex = sal_True;
240
241 for( size_t i = 0; i < pSortStruct.size(); i++ )
242 {
243 if ( ( pSortStruct[ i ].nPropId &~0xc000 ) == ( nPropID &~0xc000 ) ) // check, whether the Property only gets replaced
244 {
245 pSortStruct[ i ].nPropId = nPropID;
246 if ( !pSortStruct[ i ].nProp.empty() )
247 {
248 nCountSize -= pSortStruct[ i ].nProp.size();
249 }
250 pSortStruct[ i ].nProp = rProp;
251 pSortStruct[ i ].nPropValue = nPropValue;
252 if ( !rProp.empty() )
253 nCountSize += rProp.size();
254 return;
255 }
256 }
257 nCountCount++;
258 nCountSize += 6;
259 pSortStruct.emplace_back();
260 pSortStruct.back().nPropId = nPropID; // insert property
261 pSortStruct.back().nProp = rProp;
262 pSortStruct.back().nPropValue = nPropValue;
263
264 if ( !rProp.empty() )
265 {
266 nCountSize += rProp.size();
267 bHasComplexData = true;
268 }
269}
270
271bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId, sal_uInt32& rPropValue ) const
272{
273 EscherPropSortStruct aPropStruct;
274
275 if ( GetOpt( nPropId, aPropStruct ) )
276 {
277 rPropValue = aPropStruct.nPropValue;
278 return true;
279 }
280 return false;
281}
282
283bool EscherPropertyContainer::GetOpt( sal_uInt16 nPropId, EscherPropSortStruct& rPropValue ) const
284{
285 for( size_t i = 0; i < pSortStruct.size(); i++ )
286 {
287 if ( ( pSortStruct[ i ].nPropId &~0xc000 ) == ( nPropId &~0xc000 ) )
288 {
289 rPropValue = pSortStruct[ i ];
290 return true;
291 }
292 }
293 return false;
294}
295
297{
298 return pSortStruct;
299}
300
301extern "C" {
302
303static int EscherPropSortFunc( const void* p1, const void* p2 )
304{
305 sal_Int16 nID1 = static_cast<EscherPropSortStruct const *>(p1)->nPropId &~0xc000;
306 sal_Int16 nID2 = static_cast<EscherPropSortStruct const *>(p2)->nPropId &~0xc000;
307
308 if( nID1 < nID2 )
309 return -1;
310 else if( nID1 > nID2 )
311 return 1;
312 else
313 return 0;
314}
315
316}
317
318void EscherPropertyContainer::Commit( SvStream& rSt, sal_uInt16 nVersion, sal_uInt16 nRecType )
319{
320 rSt.WriteUInt16( ( nCountCount << 4 ) | ( nVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nCountSize );
321 if ( pSortStruct.empty() )
322 return;
323
324 qsort( pSortStruct.data(), pSortStruct.size(), sizeof( EscherPropSortStruct ), EscherPropSortFunc );
325
326 for ( size_t i = 0; i < pSortStruct.size(); i++ )
327 {
328 sal_uInt32 nPropValue = pSortStruct[ i ].nPropValue;
329 sal_uInt16 nPropId = pSortStruct[ i ].nPropId;
330
331 rSt.WriteUInt16( nPropId )
332 .WriteUInt32( nPropValue );
333 }
334 if ( bHasComplexData )
335 {
336 for ( size_t i = 0; i < pSortStruct.size(); i++ )
337 {
338 if ( !pSortStruct[ i ].nProp.empty() )
339 rSt.WriteBytes(
340 pSortStruct[i].nProp.data(),
341 pSortStruct[i].nProp.size());
342 }
343 }
344}
345
347{
348 sal_uInt32 nTextPathFlags = 0;
349 GetOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags );
350 return ( nTextPathFlags & 0x4000 ) != 0;
351}
352
353sal_uInt32 EscherPropertyContainer::ImplGetColor( const sal_uInt32 nSOColor, bool bSwap )
354{
355 if ( bSwap )
356 {
357 sal_uInt32 nColor = nSOColor & 0xff00; // green
358 nColor |= static_cast<sal_uInt8>(nSOColor) << 16; // red
359 nColor |= static_cast<sal_uInt8>( nSOColor >> 16 ); // blue
360 return nColor;
361 }
362 else
363 return nSOColor & 0xffffff;
364}
365
367 const awt::Gradient* pGradient,
368 sal_uInt32 nStartColor )
369{
370 sal_uInt32 nIntensity = 100;
371 Color aColor;
372
373 if ( pGradient )
374 {
375 if ( nStartColor & 1 )
376 {
377 nIntensity = pGradient->StartIntensity;
378 aColor = Color(ColorTransparency, pGradient->StartColor);
379 }
380 else
381 {
382 nIntensity = pGradient->EndIntensity;
383 aColor = Color(ColorTransparency, pGradient->EndColor);
384 }
385 }
386 sal_uInt32 nRed = ( aColor.GetRed() * nIntensity ) / 100;
387 sal_uInt32 nGreen = ( ( aColor.GetGreen() * nIntensity ) / 100 ) << 8;
388 sal_uInt32 nBlue = ( ( aColor.GetBlue() * nIntensity ) / 100 ) << 16;
389 return nRed | nGreen | nBlue;
390}
391
393 const awt::Gradient & rGradient )
394{
395 sal_uInt32 nFillType = ESCHER_FillShadeScale;
396 sal_uInt32 nAngle = 0;
397 sal_uInt32 nFillFocus = 0;
398 sal_uInt32 nFillLR = 0;
399 sal_uInt32 nFillTB = 0;
400 sal_uInt32 nFirstColor = 0;
401 bool bWriteFillTo = false;
402
403 switch ( rGradient.Style )
404 {
405 case awt::GradientStyle_LINEAR :
406 case awt::GradientStyle_AXIAL :
407 {
408 nFillType = ESCHER_FillShadeScale;
409 nAngle = (rGradient.Angle * 0x10000) / 10;
410 nFillFocus = (sal::static_int_cast<int>(rGradient.Style) ==
411 sal::static_int_cast<int>(css::awt::GradientStyle_LINEAR)) ? 0 : 50;
412 }
413 break;
414 case awt::GradientStyle_RADIAL :
415 case awt::GradientStyle_ELLIPTICAL :
416 case awt::GradientStyle_SQUARE :
417 case awt::GradientStyle_RECT :
418 {
419 nFillLR = (rGradient.XOffset * 0x10000) / 100;
420 nFillTB = (rGradient.YOffset * 0x10000) / 100;
421 if ( ((nFillLR > 0) && (nFillLR < 0x10000)) || ((nFillTB > 0) && (nFillTB < 0x10000)) )
422 nFillType = ESCHER_FillShadeShape;
423 else
424 nFillType = ESCHER_FillShadeCenter;
425 nFirstColor = 1;
426 bWriteFillTo = true;
427 }
428 break;
429 case awt::GradientStyle::GradientStyle_MAKE_FIXED_SIZE : break;
430 }
431 AddOpt( ESCHER_Prop_fillType, nFillType );
432 AddOpt( ESCHER_Prop_fillAngle, nAngle );
433 AddOpt( ESCHER_Prop_fillColor, GetGradientColor( &rGradient, nFirstColor ) );
434 AddOpt( ESCHER_Prop_fillBackColor, GetGradientColor( &rGradient, nFirstColor ^ 1 ) );
435 AddOpt( ESCHER_Prop_fillFocus, nFillFocus );
436 if ( bWriteFillTo )
437 {
438 AddOpt( ESCHER_Prop_fillToLeft, nFillLR );
439 AddOpt( ESCHER_Prop_fillToTop, nFillTB );
442 }
443}
444
446 const uno::Reference<beans::XPropertySet> & rXPropSet , bool bTransparentGradient)
447{
448 uno::Any aAny;
449 awt::Gradient const * pGradient = nullptr;
450
451 sal_uInt32 nFillType = ESCHER_FillShadeScale;
452 sal_Int32 nAngle = 0;
453 sal_uInt32 nFillFocus = 0;
454 sal_uInt32 nFillLR = 0;
455 sal_uInt32 nFillTB = 0;
456 sal_uInt32 nFirstColor = 0;// like the control var nChgColors in import logic
457 bool bWriteFillTo = false;
458
459 // Transparency gradient: Means the third setting in transparency page is set
460 if (bTransparentGradient && EscherPropertyValueHelper::GetPropertyValue(
461 aAny, rXPropSet, "FillTransparenceGradient" ) )
462 {
463 pGradient = o3tl::doAccess<awt::Gradient>(aAny);
464
465 uno::Any aAnyTemp;
467 aAnyTemp, rXPropSet, "FillStyle" ) )
468 {
469 drawing::FillStyle eFS;
470 if ( ! ( aAnyTemp >>= eFS ) )
471 eFS = drawing::FillStyle_SOLID;
472 // solid and transparency
473 if ( eFS == drawing::FillStyle_SOLID)
474 {
476 aAnyTemp, rXPropSet, "FillColor" ) )
477 {
478 const_cast<awt::Gradient *>(pGradient)->StartColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAnyTemp), false );
479 const_cast<awt::Gradient *>(pGradient)->EndColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAnyTemp), false );
480 }
481 }
482 // gradient and transparency.
483 else if( eFS == drawing::FillStyle_GRADIENT )
484 {
486 aAny, rXPropSet, "FillGradient" ) )
487 pGradient = o3tl::doAccess<awt::Gradient>(aAny);
488 }
489 }
490
491 }
492 // Not transparency gradient
494 aAny, rXPropSet, "FillGradient" ) )
495 {
496 pGradient = o3tl::doAccess<awt::Gradient>(aAny);
497 }
498
499 if ( pGradient )
500 {
501 switch ( pGradient->Style )
502 {
503 case awt::GradientStyle_LINEAR :
504 case awt::GradientStyle_AXIAL :
505 {
506 nFillType = ESCHER_FillShadeScale;
507 nAngle = pGradient->Angle;
508 while ( nAngle > 0 ) nAngle -= 3600;
509 while ( nAngle <= -3600 ) nAngle += 3600;
510 // Value of the real number = Integral + (Fractional / 65536.0)
511 nAngle = ( nAngle * 0x10000) / 10;
512
513 nFillFocus = (pGradient->Style == awt::GradientStyle_LINEAR) ?
514 ( pGradient->XOffset + pGradient->YOffset )/2 : -50;
515 if( !nFillFocus )
516 nFirstColor=nFirstColor ^ 1;
517 if ( !nAngle )
518 nFirstColor=nFirstColor ^ 1;
519 }
520 break;
521 case awt::GradientStyle_RADIAL :
522 case awt::GradientStyle_ELLIPTICAL :
523 case awt::GradientStyle_SQUARE :
524 case awt::GradientStyle_RECT :
525 {
526 // according to the import logic and rect type fill** value
527 nFillLR = (pGradient->XOffset * 0x10000) / 100;
528 nFillTB = (pGradient->YOffset * 0x10000) / 100;
529 if ( ((nFillLR > 0) && (nFillLR < 0x10000)) || ((nFillTB > 0) && (nFillTB < 0x10000)) )
530 nFillType = ESCHER_FillShadeShape;
531 else
532 nFillType = ESCHER_FillShadeCenter;
533 nFirstColor = 1;
534 bWriteFillTo = true;
535 }
536 break;
537 default: break;
538 }
539 }
540
541 AddOpt( ESCHER_Prop_fillType, nFillType );
542 AddOpt( ESCHER_Prop_fillAngle, nAngle );
543 AddOpt( ESCHER_Prop_fillColor, GetGradientColor( pGradient, nFirstColor ) );
544 AddOpt( ESCHER_Prop_fillBackColor, GetGradientColor( pGradient, nFirstColor ^ 1 ) );
545 AddOpt( ESCHER_Prop_fillFocus, nFillFocus );
546 if ( bWriteFillTo )
547 {
548 // according to rect type fillTo** value
549 if(nFillLR)
550 {
551 AddOpt( ESCHER_Prop_fillToLeft, nFillLR );
553 }
554 if(nFillTB)
555 {
556 AddOpt( ESCHER_Prop_fillToTop, nFillTB );
558 }
559 }
560
561 // Transparency gradient
562 if (bTransparentGradient && EscherPropertyValueHelper::GetPropertyValue(
563 aAny, rXPropSet, "FillTransparenceGradient" ) )
564 {
565 pGradient = o3tl::doAccess<awt::Gradient>(aAny);
566 if ( pGradient )
567 {
568 sal_uInt32 nBlue = GetGradientColor( pGradient, nFirstColor ) >> 16;
569 AddOpt( ESCHER_Prop_fillOpacity,( ( 100 - ( nBlue * 100 / 255 ) ) << 16 ) / 100 );
570 nBlue = GetGradientColor( pGradient, nFirstColor ^ 1 ) >>16 ;
571 AddOpt( ESCHER_Prop_fillBackOpacity,( ( 100 - ( nBlue * 100 / 255 ) ) << 16 )/ 100 );
572 }
573 }
574}
575
577 const uno::Reference<beans::XPropertySet> & rXPropSet,
578 bool bEdge , const uno::Reference<drawing::XShape> & rXShape )
579{
580 if ( rXShape.is() )
581 {
583 if ( pObj )
584 {
585 const SfxItemSet& aAttr( pObj->GetMergedItemSet() );
586 // transparency with gradient. Means the third setting in transparency page is set
587 bool bTransparentGradient = ( aAttr.GetItemState( XATTR_FILLFLOATTRANSPARENCE ) == SfxItemState::SET ) &&
588 aAttr.Get( XATTR_FILLFLOATTRANSPARENCE ).IsEnabled();
589 CreateFillProperties( rXPropSet, bEdge, bTransparentGradient );
590 }
591 }
592}
593
595 const uno::Reference<beans::XPropertySet> & rXPropSet,
596 bool bEdge , bool bTransparentGradient)
597
598{
599 uno::Any aAny;
602 static constexpr OUStringLiteral aPropName( u"FillStyle" );
603
605 aAny, rXPropSet, aPropName ) )
606 {
607 drawing::FillStyle eFS;
608 if ( ! ( aAny >>= eFS ) )
609 eFS = drawing::FillStyle_SOLID;
610 sal_uInt32 nFillBackColor = 0;
611 switch( eFS )
612 {
613 case drawing::FillStyle_GRADIENT :
614 {
615 CreateGradientProperties( rXPropSet , bTransparentGradient );
617 }
618 break;
619
620 case drawing::FillStyle_BITMAP :
621 {
622 CreateGraphicProperties(rXPropSet, "FillBitmap", true);
624 AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
625 }
626 break;
627 case drawing::FillStyle_HATCH :
628 {
629 CreateGraphicProperties( rXPropSet, "FillHatch", true );
630 }
631 break;
632 case drawing::FillStyle_SOLID :
633 default:
634 {
635 if ( bTransparentGradient )
636 CreateGradientProperties( rXPropSet , bTransparentGradient );
637 else
638 {
639 beans::PropertyState ePropState = EscherPropertyValueHelper::GetPropertyState(
640 rXPropSet, aPropName );
641 if ( ePropState == beans::PropertyState_DIRECT_VALUE )
643
645 aAny, rXPropSet, "FillColor" ) )
646 {
647 sal_uInt32 nFillColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
648 nFillBackColor = nFillColor ^ 0xffffff;
649 AddOpt( ESCHER_Prop_fillColor, nFillColor );
650 }
652 AddOpt( ESCHER_Prop_fillBackColor, nFillBackColor );
653 }
654 break;
655 }
656 case drawing::FillStyle_NONE :
658 break;
659 }
660 if ( eFS != drawing::FillStyle_NONE )
661 {
662 sal_uInt16 nTransparency = ( EscherPropertyValueHelper::GetPropertyValue(
663 aAny, rXPropSet, "FillTransparence", true ) )
664 ? *o3tl::doAccess<sal_Int16>(aAny) : 0;
665 if ( nTransparency )
666 AddOpt( ESCHER_Prop_fillOpacity, ( ( 100 - nTransparency ) << 16 ) / 100 );
667 }
668 }
669 CreateLineProperties( rXPropSet, bEdge );
670}
671
673 const uno::Reference< beans::XPropertySet > & rXPropSet, sal_uInt32 nTextId,
674 const bool bIsCustomShape, const bool bIsTextFrame )
675{
676 uno::Any aAny;
677 text::WritingMode eWM( text::WritingMode_LR_TB );
678 drawing::TextVerticalAdjust eVA( drawing::TextVerticalAdjust_TOP );
679 drawing::TextHorizontalAdjust eHA( drawing::TextHorizontalAdjust_LEFT );
680
681 sal_Int32 nLeft ( 0 );
682 sal_Int32 nTop ( 0 );
683 sal_Int32 nRight ( 0 );
684 sal_Int32 nBottom ( 0 );
685
686 // used with normal shapes:
687 bool bAutoGrowWidth ( false );
688 const bool bAutoGrowHeight ( false ); //#ii63936 not setting autogrowheight, because minframeheight would be ignored
689 // used with ashapes:
690 bool bWordWrap ( false );
691 bool bAutoGrowSize ( false );
692
693 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWritingMode", true ) )
694 aAny >>= eWM;
695 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextVerticalAdjust", true ) )
696 aAny >>= eVA;
697 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextHorizontalAdjust", true ) )
698 aAny >>= eHA;
699 if ( bIsCustomShape )
700 {
701 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextWordWrap" ) )
702 aAny >>= bWordWrap;
703 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", true ) )
704 aAny >>= bAutoGrowSize;
705 }
706 else if ( bIsTextFrame )
707 {
708 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowWidth", true ) )
709 aAny >>= bAutoGrowWidth;
710
711// i63936 not setting autogrowheight, because otherwise
712// the minframeheight of the text will be ignored
713//
714// if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextAutoGrowHeight", sal_True ) )
715// aAny >>= bAutoGrowHeight;
716 }
717 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextLeftDistance" ) )
718 aAny >>= nLeft;
719 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextUpperDistance" ) )
720 aAny >>= nTop;
721 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextRightDistance" ) )
722 aAny >>= nRight;
723 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "TextLowerDistance" ) )
724 aAny >>= nBottom;
725
728 sal_uInt32 nTextAttr = 0x40004; // rotate text with shape
729
730 if ( eWM == text::WritingMode_TB_RL )
731 { // vertical writing
732 switch ( eHA )
733 {
734 case drawing::TextHorizontalAdjust_LEFT :
735 eAnchor = ESCHER_AnchorBottom;
736 break;
737 case drawing::TextHorizontalAdjust_CENTER :
738 eAnchor = ESCHER_AnchorMiddle;
739 break;
740 default :
741 case drawing::TextHorizontalAdjust_BLOCK :
742 case drawing::TextHorizontalAdjust_RIGHT :
743 eAnchor = ESCHER_AnchorTop;
744 break;
745 }
746 if ( eVA == drawing::TextVerticalAdjust_CENTER )
747 {
748 switch ( eAnchor )
749 {
752 break;
755 break;
756 default :
757 case ESCHER_AnchorTop :
758 eAnchor = ESCHER_AnchorTopCentered;
759 break;
760 }
761 }
762 if ( bIsCustomShape )
763 {
764 if ( bWordWrap )
765 eWrapMode = ESCHER_WrapSquare;
766 else
767 eWrapMode = ESCHER_WrapNone;
768 if ( bAutoGrowSize )
769 nTextAttr |= 0x20002;
770 }
771 else
772 {
773 if ( bAutoGrowHeight )
774 eWrapMode = ESCHER_WrapNone;
775 if ( bAutoGrowWidth )
776 nTextAttr |= 0x20002;
777 }
778
779 AddOpt( ESCHER_Prop_txflTextFlow, ESCHER_txflTtoBA ); // rotate text within shape by 90
780 }
781 else
782 { // normal from left to right
783 switch ( eVA )
784 {
785 case drawing::TextVerticalAdjust_CENTER :
786 eAnchor = ESCHER_AnchorMiddle;
787 break;
788
789 case drawing::TextVerticalAdjust_BOTTOM :
790 eAnchor = ESCHER_AnchorBottom;
791 break;
792
793 default :
794 case drawing::TextVerticalAdjust_TOP :
795 eAnchor = ESCHER_AnchorTop;
796 break;
797 }
798 if ( eHA == drawing::TextHorizontalAdjust_CENTER )
799 {
800 switch( eAnchor )
801 {
804 break;
807 break;
808 case ESCHER_AnchorTop :
809 eAnchor = ESCHER_AnchorTopCentered;
810 break;
811 default: break;
812 }
813 }
814 if ( bIsCustomShape )
815 {
816 if ( bWordWrap )
817 eWrapMode = ESCHER_WrapSquare;
818 else
819 eWrapMode = ESCHER_WrapNone;
820 if ( bAutoGrowSize )
821 nTextAttr |= 0x20002;
822 }
823 else
824 {
825 if ( bAutoGrowWidth )
826 eWrapMode = ESCHER_WrapNone;
827 if ( bAutoGrowHeight )
828 nTextAttr |= 0x20002;
829 }
830 }
831 AddOpt( ESCHER_Prop_dxTextLeft, nLeft * 360 );
832 AddOpt( ESCHER_Prop_dxTextRight, nRight * 360 );
833 AddOpt( ESCHER_Prop_dyTextTop, nTop * 360 );
834 AddOpt( ESCHER_Prop_dyTextBottom, nBottom * 360 );
835
836 AddOpt( ESCHER_Prop_WrapText, eWrapMode );
837 AddOpt( ESCHER_Prop_AnchorText, eAnchor );
839
840 if ( nTextId )
841 AddOpt( ESCHER_Prop_lTxid, nTextId );
842
843 // n#404221: In case of rotation we need to write the txtflTextFlow
844 // attribute too.
845 // fdo#58204: not custom shapes (TODO: other cases when it doesn't work?)
846 if (!bIsTextFrame || bIsCustomShape)
847 return;
848
850 aAny, rXPropSet, "RotateAngle", true ) ?
851 static_cast<sal_uInt16>( ( *o3tl::doAccess<sal_Int32>(aAny) ) + 5 ) / 10 : 0;
852 if (nAngle==900)
853 {
855 }
856 if (nAngle==2700)
857 {
859 }
860}
861
862bool EscherPropertyContainer::GetLineArrow( const bool bLineStart,
863 const uno::Reference<beans::XPropertySet> & rXPropSet,
864 ESCHER_LineEnd& reLineEnd, sal_Int32& rnArrowLength, sal_Int32& rnArrowWidth )
865{
866 const OUString sLine ( bLineStart ? OUString("LineStart") : OUString("LineEnd") );
867 const OUString sLineName ( bLineStart ? OUString("LineStartName") : OUString("LineEndName") );
868
869 bool bIsArrow = false;
870
871 uno::Any aAny;
872 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, sLine ) )
873 {
875 if ( aPolyPoly.Count() && aPolyPoly[ 0 ].GetSize() )
876 {
877 bIsArrow = true;
878
879 reLineEnd = ESCHER_LineArrowEnd;
880 rnArrowLength = 1;
881 rnArrowWidth = 1;
882
883 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, sLineName ) )
884 {
885 OUString aArrowStartName = *o3tl::doAccess<OUString>(aAny);
886 sal_uInt16 nWhich = bLineStart ? sal_uInt16(XATTR_LINESTART) : sal_uInt16(XATTR_LINEEND);
887
888 // remove extra space separated number
889 sal_Int32 nPos = aArrowStartName.lastIndexOf(' ');
890 if (nPos > -1 && aArrowStartName.lastIndexOf(' ', nPos) > -1)
891 aArrowStartName = aArrowStartName.copy(0, nPos);
892
893 OUString aApiName = SvxUnogetApiNameForItem(nWhich, aArrowStartName);
894 bool bIsMapped = true;
895 if ( !aApiName.isEmpty() )
896 {
897
898 // TODO: calculate the best option for ArrowLength and ArrowWidth
899 if ( aApiName == "Arrow concave" )
900 reLineEnd = ESCHER_LineArrowStealthEnd;
901 else if ( aApiName == "Square 45" )
902 reLineEnd = ESCHER_LineArrowDiamondEnd;
903 else if ( aApiName == "Small Arrow" )
904 reLineEnd = ESCHER_LineArrowEnd;
905 else if ( aApiName == "Dimension Lines" )
906 {
907 rnArrowLength = 0;
908 rnArrowWidth = 2;
909 reLineEnd = ESCHER_LineArrowOvalEnd;
910 }
911 else if ( aApiName == "Double Arrow" )
912 reLineEnd = ESCHER_LineArrowEnd;
913 else if ( aApiName == "Rounded short Arrow" )
914 reLineEnd = ESCHER_LineArrowEnd;
915 else if ( aApiName == "Symmetric Arrow" )
916 reLineEnd = ESCHER_LineArrowEnd;
917 else if ( aApiName == "Line Arrow" )
918 reLineEnd = ESCHER_LineArrowOpenEnd;
919 else if ( aApiName == "Rounded large Arrow" )
920 reLineEnd = ESCHER_LineArrowEnd;
921 else if ( aApiName == "Circle" )
922 reLineEnd = ESCHER_LineArrowOvalEnd;
923 else if ( aApiName == "Square" )
924 reLineEnd = ESCHER_LineArrowDiamondEnd;
925 else if ( aApiName == "Arrow" )
926 reLineEnd = ESCHER_LineArrowEnd;
927 else
928 bIsMapped = false;
929
930 }
931 if ( !bIsMapped && comphelper::string::getTokenCount(aArrowStartName, ' ') == 2 )
932 {
933 sal_Int32 nIdx{ 0 };
934 std::u16string_view aArrowName( o3tl::getToken(aArrowStartName, 0, ' ', nIdx ) );
935 if ( aArrowName == u"msArrowEnd" )
936 reLineEnd = ESCHER_LineArrowEnd;
937 else if ( aArrowName == u"msArrowOpenEnd" )
938 reLineEnd = ESCHER_LineArrowOpenEnd;
939 else if ( aArrowName == u"msArrowStealthEnd" )
940 reLineEnd = ESCHER_LineArrowStealthEnd;
941 else if ( aArrowName == u"msArrowDiamondEnd" )
942 reLineEnd = ESCHER_LineArrowDiamondEnd;
943 else if ( aArrowName == u"msArrowOvalEnd" )
944 reLineEnd = ESCHER_LineArrowOvalEnd;
945 else
946 nIdx = -1;
947
948 // now we have the arrow, and try to determine the arrow size;
949 if ( nIdx>0 )
950 {
951 std::u16string_view aArrowSize = o3tl::getToken(aArrowStartName, 0, ' ', nIdx );
952 sal_Int32 nArrowSize = o3tl::toInt32(aArrowSize);
953 rnArrowWidth = ( nArrowSize - 1 ) / 3;
954 rnArrowLength = nArrowSize - ( rnArrowWidth * 3 ) - 1;
955 }
956 }
957 }
958 }
959 }
960 return bIsArrow;
961}
962
964 const uno::Reference<beans::XPropertySet> & rXPropSet, bool bEdge )
965{
966 uno::Any aAny;
967 sal_uInt32 nLineFlags = 0x80008;
968
969 ESCHER_LineEnd eLineEnd;
970 sal_Int32 nArrowLength;
971 sal_Int32 nArrowWidth;
972
973 bool bSwapLineEnds = false;
974 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "CircleKind", true ) )
975 {
976 drawing::CircleKind eCircleKind;
977 if ( aAny >>= eCircleKind )
978 {
979 if ( eCircleKind == drawing::CircleKind_ARC )
980 bSwapLineEnds = true;
981 }
982 }
983 if ( GetLineArrow( !bSwapLineEnds, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) )
984 {
988 nLineFlags |= 0x100010;
989 }
990 if ( GetLineArrow( bSwapLineEnds, rXPropSet, eLineEnd, nArrowLength, nArrowWidth ) )
991 {
992 AddOpt( ESCHER_Prop_lineEndArrowLength, nArrowLength );
995 nLineFlags |= 0x100010;
996 }
997
998 // support LineCaps
999 if(EscherPropertyValueHelper::GetPropertyValue(aAny, rXPropSet, "LineCap"))
1000 {
1001 drawing::LineCap aLineCap(drawing::LineCap_BUTT);
1002
1003 if(aAny >>= aLineCap)
1004 {
1005 switch (aLineCap)
1006 {
1007 default: /* drawing::LineCap_BUTT */
1008 {
1010 break;
1011 }
1012 case drawing::LineCap_ROUND:
1013 {
1015 break;
1016 }
1017 case drawing::LineCap_SQUARE:
1018 {
1020 break;
1021 }
1022 }
1023 }
1024 }
1025
1026 sal_uInt32 nLineWidth = ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineWidth" ) )
1027 ? *o3tl::doAccess<sal_uInt32>(aAny) : 0;
1028 if ( nLineWidth > 1 )
1029 AddOpt( ESCHER_Prop_lineWidth, nLineWidth * 360 ); // 100TH MM -> PT , 1PT = 12700 EMU
1030
1031 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineStyle" ) )
1032 {
1033 drawing::LineStyle eLS;
1034 if ( aAny >>= eLS )
1035 {
1036 switch ( eLS )
1037 {
1038 case drawing::LineStyle_NONE :
1039 AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); // 80000
1040 break;
1041
1042 case drawing::LineStyle_DASH :
1043 {
1044 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineDash" ) )
1045 {
1047 auto pLineDash = o3tl::doAccess<drawing::LineDash>(aAny);
1048 switch ( pLineDash->Style )
1049 {
1050 case drawing::DashStyle_ROUND :
1051 case drawing::DashStyle_ROUNDRELATIVE :
1052 AddOpt( ESCHER_Prop_lineEndCapStyle, 0 ); // set Style Round
1053 break;
1054 default : break;
1055 }
1056 // Try to detect exact prstDash styles. Use a similar method as in oox export.
1057 // Map it to a roughly fitting prstDash in other cases.
1058 bool bIsConverted = false;
1059 bool bIsRelative = pLineDash->Style == drawing::DashStyle_RECTRELATIVE
1060 || pLineDash->Style == drawing::DashStyle_ROUNDRELATIVE;
1061 sal_Int16 nDashes = pLineDash->Dashes;
1062 sal_Int16 nDots = pLineDash->Dots;
1063 sal_Int32 nDashLen = pLineDash->DashLen;
1064 sal_Int32 nDotLen = pLineDash->DotLen;
1065 sal_Int32 nDistance = pLineDash->Distance;
1066
1067 // Caution! The names are misleading. "dot" is always the first dash and "dash"
1068 // the second one, regardless of the actual length. All prstDash
1069 // definitions start with the longer dash and have exact one longer dash.
1070 // Preset line style definitions for binary format are the same as for OOXML.
1071 if (bIsRelative && nDots == 1)
1072 {
1073 // I'm not sure that LO always uses 100%, because in case of absolute values, LO
1074 // sets length to 0 but treats it as 100%, if the attribute is missing in ODF.
1075 // So to be sure set 100% explicitly in case of relative too.
1076 if (nDashes > 0 && nDashLen == 0)
1077 nDashLen = 100;
1078 if (nDotLen == 0)
1079 nDotLen = 100;
1080 bIsConverted = true;
1081 if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
1082 eDash = ESCHER_LineDotGEL;
1083 else if (nDotLen == 400 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
1084 eDash = ESCHER_LineDashGEL;
1085 else if (nDotLen == 400 && nDashes == 1 && nDashLen == 100 && nDistance == 300)
1086 eDash = ESCHER_LineDashDotGEL;
1087 else if (nDotLen == 800 && nDashes == 0 && nDashLen == 0 && nDistance == 300)
1088 eDash = ESCHER_LineLongDashGEL;
1089 else if (nDotLen == 800 && nDashes == 1 && nDashLen == 100 && nDistance == 300)
1091 else if (nDotLen == 800 && nDashes == 2 && nDashLen == 100 && nDistance == 300)
1093 else if (nDotLen == 100 && nDashes == 0 && nDashLen == 0 && nDistance == 100)
1094 eDash = ESCHER_LineDotSys;
1095 else if (nDotLen == 300 && nDashes == 0 && nDashLen == 0 && nDistance == 100)
1096 eDash = ESCHER_LineDashSys;
1097 else if (nDotLen == 300 && nDashes == 1 && nDashLen == 100 && nDistance == 100)
1098 eDash = ESCHER_LineDashDotSys;
1099 else if (nDotLen == 300 && nDashes == 2 && nDashLen == 100 && nDistance == 100)
1101 else
1102 bIsConverted = false;
1103 }
1104
1105 if (!bIsConverted)
1106 { // Map the style roughly to preset line styles.
1107 if (((!(pLineDash->Dots)) || (!(pLineDash->Dashes)))
1108 || (pLineDash->DotLen == pLineDash->DashLen))
1109 {
1110 sal_Int32 nLen = pLineDash->DotLen;
1111 if (pLineDash->Dashes)
1112 nLen = pLineDash->DashLen;
1113 if (nLen >= nDistance)
1114 eDash = ESCHER_LineLongDashGEL;
1115 else if (pLineDash->Dots)
1116 eDash = ESCHER_LineDotSys;
1117 else
1118 eDash = ESCHER_LineDashGEL;
1119 }
1120 else // X Y
1121 {
1122 if (pLineDash->Dots != pLineDash->Dashes)
1123 {
1124 if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance))
1126 else
1128 }
1129 else // X Y Y
1130 {
1131 if ((pLineDash->DashLen > nDistance) || (pLineDash->DotLen > nDistance))
1133 else
1134 eDash = ESCHER_LineDashDotGEL;
1135 }
1136 }
1137 }
1139 }
1140 }
1141 [[fallthrough]];
1142 case drawing::LineStyle_SOLID :
1143 default:
1144 {
1145 AddOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
1146 }
1147 break;
1148 }
1149 }
1150 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineColor" ) )
1151 {
1152 sal_uInt32 nLineColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny) );
1153 AddOpt( ESCHER_Prop_lineColor, nLineColor );
1154 AddOpt( ESCHER_Prop_lineBackColor, nLineColor ^ 0xffffff );
1155 }
1156 }
1157
1159 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "LineJoint", true ) )
1160 {
1161 drawing::LineJoint eLJ;
1162 if ( aAny >>= eLJ )
1163 {
1164 switch ( eLJ )
1165 {
1166 case drawing::LineJoint_NONE :
1167 case drawing::LineJoint_BEVEL :
1168 eLineJoin = ESCHER_LineJoinBevel;
1169 break;
1170 default:
1171 case drawing::LineJoint_MIDDLE :
1172 case drawing::LineJoint_MITER :
1173 eLineJoin = ESCHER_LineJoinMiter;
1174 break;
1175 case drawing::LineJoint_ROUND :
1176 eLineJoin = ESCHER_LineJoinRound;
1177 break;
1178 }
1179 }
1180 }
1181 AddOpt( ESCHER_Prop_lineJoinStyle, eLineJoin );
1182
1184 aAny, rXPropSet, "LineTransparence", true ) )
1185 {
1186 sal_Int16 nTransparency = 0;
1187 if ( aAny >>= nTransparency )
1188 AddOpt( ESCHER_Prop_lineOpacity, ( ( 100 - nTransparency ) << 16 ) / 100 );
1189 }
1190
1191
1192 if ( !bEdge )
1193 {
1194 AddOpt( ESCHER_Prop_fFillOK, 0x1001 );
1196 }
1197}
1198
1199static Size lcl_SizeToEmu(Size aPrefSize, const MapMode& aPrefMapMode)
1200{
1201 Size aRetSize;
1202 if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
1203 aRetSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM));
1204 else
1205 aRetSize = OutputDevice::LogicToLogic(aPrefSize, aPrefMapMode, MapMode(MapUnit::Map100thMM));
1206 return aRetSize;
1207}
1208
1209void EscherPropertyContainer::ImplCreateGraphicAttributes( const uno::Reference<beans::XPropertySet> & rXPropSet,
1210 sal_uInt32 nBlibId, bool bCreateCroppingAttributes )
1211{
1212 uno::Any aAny;
1213
1214 sal_uInt32 nPicFlags = 0;
1215 drawing::ColorMode eColorMode( drawing::ColorMode_STANDARD );
1216 sal_Int16 nLuminance = 0;
1217 sal_Int32 nContrast = 0;
1218
1219 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "GraphicColorMode" ) )
1220 aAny >>= eColorMode;
1221 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustLuminance" ) )
1222 aAny >>= nLuminance;
1223 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustContrast" ) )
1224 {
1225 sal_Int16 nC = sal_Int16();
1226 aAny >>= nC;
1227 nContrast = nC;
1228 }
1229
1230 if ( eColorMode == drawing::ColorMode_WATERMARK )
1231 {
1232 eColorMode = drawing::ColorMode_STANDARD;
1233 nLuminance += 70;
1234 if ( nLuminance > 100 )
1235 nLuminance = 100;
1236 nContrast -= 70;
1237 if ( nContrast < -100 )
1238 nContrast = -100;
1239 }
1240 if ( eColorMode == drawing::ColorMode_GREYS )
1241 nPicFlags |= 0x40004;
1242 else if ( eColorMode == drawing::ColorMode_MONO )
1243 nPicFlags |= 0x60006;
1244
1245 if ( nContrast )
1246 {
1247 nContrast += 100;
1248 if ( nContrast == 100)
1249 nContrast = 0x10000;
1250 else if ( nContrast < 100 )
1251 {
1252 nContrast *= 0x10000;
1253 nContrast /= 100;
1254 }
1255 else if ( nContrast < 200 )
1256 nContrast = ( 100 * 0x10000 ) / ( 200 - nContrast );
1257 else
1258 nContrast = 0x7fffffff;
1259 AddOpt( ESCHER_Prop_pictureContrast, nContrast );
1260 }
1261 if ( nLuminance )
1262 AddOpt( ESCHER_Prop_pictureBrightness, nLuminance * 327 );
1263 if ( nPicFlags )
1264 AddOpt( ESCHER_Prop_pictureActive, nPicFlags );
1265
1266 if ( !(bCreateCroppingAttributes && pGraphicProvider) )
1267 return;
1268
1269 Size aPrefSize;
1270 MapMode aPrefMapMode;
1271 if ( !pGraphicProvider->GetPrefSize( nBlibId, aPrefSize, aPrefMapMode ) )
1272 return;
1273
1274 Size aCropSize(lcl_SizeToEmu(aPrefSize, aPrefMapMode));
1275 if ( !(aCropSize.Width() && aCropSize.Height()) )
1276 return;
1277
1278 if ( !EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "GraphicCrop" ) )
1279 return;
1280
1281 text::GraphicCrop aGraphCrop;
1282 if ( !(aAny >>= aGraphCrop) )
1283 return;
1284
1285 if ( aGraphCrop.Left )
1286 {
1287 sal_uInt32 nLeft = ( aGraphCrop.Left * 65536 ) / aCropSize.Width();
1289 }
1290 if ( aGraphCrop.Top )
1291 {
1292 sal_uInt32 nTop = ( aGraphCrop.Top * 65536 ) / aCropSize.Height();
1294 }
1295 if ( aGraphCrop.Right )
1296 {
1297 sal_uInt32 nRight = ( aGraphCrop.Right * 65536 ) / aCropSize.Width();
1299 }
1300 if ( aGraphCrop.Bottom )
1301 {
1302 sal_uInt32 nBottom = ( aGraphCrop.Bottom * 65536 ) / aCropSize.Height();
1304 }
1305}
1306
1307void EscherPropertyContainer::CreateShapeProperties( const uno::Reference<drawing::XShape> & rXShape )
1308{
1309 uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
1310 if ( !aXPropSet.is() )
1311 return;
1312
1313 bool bVisible = false;
1314 bool bPrintable = false;
1315 uno::Any aAny;
1316 sal_uInt32 nShapeAttr = 0;
1317 if (EscherPropertyValueHelper::GetPropertyValue(aAny, aXPropSet, "Visible", true) && (aAny >>= bVisible))
1318 {
1319 if ( !bVisible )
1320 nShapeAttr |= 0x20002; // set fHidden = true
1321 }
1322 // This property (fPrint) isn't used in Excel anymore, leaving it for legacy reasons
1323 // one change, based on XLSX: hidden implies not printed, let's not export the fPrint property in that case
1324 if (bVisible && EscherPropertyValueHelper::GetPropertyValue(aAny, aXPropSet, "Printable", true) && (aAny >>= bPrintable))
1325 {
1326 if ( !bPrintable )
1327 nShapeAttr |= 0x10000; // set fPrint = false;
1328 }
1329 if ( nShapeAttr )
1330 AddOpt( ESCHER_Prop_fPrint, nShapeAttr );
1331}
1332
1333bool EscherPropertyContainer::CreateOLEGraphicProperties(const uno::Reference<drawing::XShape> & rXShape)
1334{
1335 bool bRetValue = false;
1336
1337 if ( rXShape.is() )
1338 {
1339 SdrObject* pObject = SdrObject::getSdrObjectFromXShape(rXShape); // SJ: leaving unoapi, because currently there is
1340 if (auto pOle2Obj = dynamic_cast<const SdrOle2Obj*>(pObject)) // no access to the native graphic object
1341 {
1342 const Graphic* pGraphic = pOle2Obj->GetGraphic();
1343 if (pGraphic)
1344 {
1345 GraphicObject aGraphicObject(*pGraphic);
1346 bRetValue = CreateGraphicProperties(rXShape, aGraphicObject);
1347 }
1348 }
1349 }
1350 return bRetValue;
1351}
1352
1353bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference<drawing::XShape> & rXShape, const GraphicObject& rGraphicObj)
1354{
1355 bool bRetValue = false;
1356 OString aUniqueId(rGraphicObj.GetUniqueID());
1357 if ( !aUniqueId.isEmpty() )
1358 {
1360 uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
1361
1362 if ( pGraphicProvider && pPicOutStrm && pShapeBoundRect && aXPropSet.is() )
1363 {
1364 uno::Any aAny;
1365 std::unique_ptr<awt::Rectangle> pVisArea;
1366 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "VisibleArea" ) )
1367 {
1368 pVisArea.reset(new awt::Rectangle);
1369 aAny >>= *pVisArea;
1370 }
1371 sal_uInt32 nBlibId = pGraphicProvider->GetBlibID( *pPicOutStrm, rGraphicObj, pVisArea.get() );
1372 if ( nBlibId )
1373 {
1374 AddOpt( ESCHER_Prop_pib, nBlibId, true );
1375 ImplCreateGraphicAttributes( aXPropSet, nBlibId, false );
1376 bRetValue = true;
1377 }
1378 }
1379 }
1380 return bRetValue;
1381}
1382
1383bool EscherPropertyContainer::CreateMediaGraphicProperties(const uno::Reference<drawing::XShape> & rXShape)
1384{
1385 bool bRetValue = false;
1386 if ( rXShape.is() )
1387 {
1388 SdrObject* pSdrObject(SdrObject::getSdrObjectFromXShape(rXShape)); // SJ: leaving unoapi, because currently there is
1389 if (auto pSdrMediaObj = dynamic_cast<const SdrMediaObj*>(pSdrObject)) // no access to the native graphic object
1390 {
1391 GraphicObject aGraphicObject(pSdrMediaObj->getSnapshot());
1392 bRetValue = CreateGraphicProperties(rXShape, aGraphicObject);
1393 }
1394 }
1395 return bRetValue;
1396}
1397
1399{
1400 if (rGraphicObject.GetType() != GraphicType::NONE)
1401 {
1402 EscherGraphicProvider aProvider;
1403 SvMemoryStream aMemStrm;
1404
1405 if (aProvider.GetBlibID( aMemStrm, rGraphicObject))
1406 {
1407 AddOpt(ESCHER_Prop_fillBlip, true, 0, aMemStrm);
1408 return true;
1409 }
1410 }
1411 return false;
1412}
1413
1415 uno::Reference<awt::XBitmap> const & rxBitmap, drawing::BitmapMode eBitmapMode )
1416{
1417 uno::Reference<graphic::XGraphic> xGraphic(rxBitmap, uno::UNO_QUERY);
1418 if (!xGraphic.is())
1419 return;
1420 Graphic aGraphic(xGraphic);
1421 if (aGraphic.IsNone())
1422 return;
1423 GraphicObject aGraphicObject(std::move(aGraphic));
1424 if (aGraphicObject.GetType() == GraphicType::NONE)
1425 return;
1426 if (ImplCreateEmbeddedBmp(aGraphicObject))
1427 {
1428 // bitmap mode property
1429 bool bRepeat = eBitmapMode == drawing::BitmapMode_REPEAT;
1431 }
1432}
1433
1434namespace {
1435
1436Graphic lclDrawHatch( const drawing::Hatch& rHatch, const Color& rBackColor, bool bFillBackground, const tools::Rectangle& rRect )
1437{
1438 // #i121183# For hatch, do no longer create a bitmap with the fixed size of 28x28 pixels. Also
1439 // do not create a bitmap in page size, that would explode file sizes (and have no good quality).
1440 // Better use a MetaFile graphic in page size; thus we have good quality due to vector format and
1441 // no bit file sizes.
1443 GDIMetaFile aMtf;
1444
1445 pVDev->SetOutputSizePixel(Size(2, 2));
1446 pVDev->EnableOutput(false);
1447 pVDev->SetMapMode(MapMode(MapUnit::Map100thMM));
1448 aMtf.Clear();
1449 aMtf.Record(pVDev);
1450 pVDev->SetLineColor();
1451 pVDev->SetFillColor(bFillBackground ? rBackColor : COL_TRANSPARENT);
1452 pVDev->DrawRect(rRect);
1453 pVDev->DrawHatch(tools::PolyPolygon(rRect), Hatch(static_cast<HatchStyle>(rHatch.Style), Color(ColorTransparency, rHatch.Color), rHatch.Distance,
1454 Degree10(rHatch.Angle)));
1455 aMtf.Stop();
1456 aMtf.WindStart();
1457 aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
1458 aMtf.SetPrefSize(rRect.GetSize());
1459
1460 return Graphic(aMtf);
1461}
1462
1463} // namespace
1464
1465void EscherPropertyContainer::CreateEmbeddedHatchProperties(const drawing::Hatch& rHatch, const Color& rBackColor, bool bFillBackground )
1466{
1467 const tools::Rectangle aRect(pShapeBoundRect ? *pShapeBoundRect : tools::Rectangle(Point(0,0), Size(28000, 21000)));
1468 Graphic aGraphic(lclDrawHatch(rHatch, rBackColor, bFillBackground, aRect));
1469 GraphicObject aGraphicObject(std::move(aGraphic));
1470
1471 if (ImplCreateEmbeddedBmp(aGraphicObject))
1473}
1474
1475bool EscherPropertyContainer::CreateGraphicProperties(const uno::Reference<beans::XPropertySet> & rXPropSet,
1476 const OUString& rSource,
1477 const bool bCreateFillBitmap,
1478 const bool bCreateCroppingAttributes,
1479 const bool bFillBitmapModeAllowed,
1480 const bool bOOxmlExport )
1481{
1482 bool bRetValue = false;
1483 bool bCreateFillStyles = false;
1484
1485 std::unique_ptr<GraphicAttr> pGraphicAttr;
1486 uno::Reference<graphic::XGraphic> xGraphic;
1487
1488 uno::Any aAny;
1489
1490 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, rSource ) )
1491 {
1492 bool bMirrored = false;
1493 bool bRotate = true;
1494 bool bIsGraphicMtf = false;
1495 sal_Int16 nTransparency(0);
1496 sal_Int16 nRed(0);
1497 sal_Int16 nGreen(0);
1498 sal_Int16 nBlue(0);
1499 double fGamma(1.0);
1500 drawing::BitmapMode eBitmapMode(drawing::BitmapMode_NO_REPEAT);
1501 OUString aGraphicUrl;
1502
1503 sal_uInt16 nAngle = 0;
1504 if ( rSource == "MetaFile" )
1505 {
1506 auto & aSeq = *o3tl::doAccess<uno::Sequence<sal_Int8>>(aAny);
1507 const sal_Int8* pArray = aSeq.getConstArray();
1508 sal_uInt32 nArrayLength = aSeq.getLength();
1509
1510 // the metafile is already rotated
1511 bRotate = false;
1512
1513 if (pArray && nArrayLength)
1514 {
1515 Graphic aGraphic;
1516 SvMemoryStream aStream(const_cast<sal_Int8 *>(pArray), nArrayLength, StreamMode::READ);
1517 ErrCode nErrCode = GraphicConverter::Import(aStream, aGraphic, ConvertDataFormat::WMF);
1518 if ( nErrCode == ERRCODE_NONE )
1519 {
1520 xGraphic = aGraphic.GetXGraphic();
1521 bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile;
1522 }
1523 }
1524 }
1525 else if (rSource == "Bitmap" || rSource == "FillBitmap")
1526 {
1527 auto xBitmap = aAny.get<uno::Reference<awt::XBitmap>>();
1528 if (xBitmap.is())
1529 {
1530 xGraphic.set(xBitmap, uno::UNO_QUERY);
1531 Graphic aGraphic(xGraphic);
1532 bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile;
1533 }
1534 }
1535 else if ( rSource == "Graphic" )
1536 {
1537 xGraphic = aAny.get<uno::Reference<graphic::XGraphic>>();
1538 bCreateFillStyles = true;
1539 }
1540 else if ( rSource == "FillHatch" )
1541 {
1542 drawing::Hatch aHatch;
1543 if ( aAny >>= aHatch )
1544 {
1545 Color aBackColor;
1546 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillColor" ) )
1547 {
1548 aBackColor = Color(ColorTransparency, ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny), false ));
1549 }
1550 bool bFillBackground = false;
1551 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBackground", true ) )
1552 {
1553 aAny >>= bFillBackground;
1554 }
1555
1556 const tools::Rectangle aRect(Point(0, 0), pShapeBoundRect ? pShapeBoundRect->GetSize() : Size(28000, 21000));
1557 Graphic aGraphic(lclDrawHatch(aHatch, aBackColor, bFillBackground, aRect));
1558 xGraphic = aGraphic.GetXGraphic();
1559 eBitmapMode = drawing::BitmapMode_REPEAT;
1560 bIsGraphicMtf = aGraphic.GetType() == GraphicType::GdiMetafile;
1561 }
1562 }
1563
1564 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "IsMirrored", true ) )
1565 aAny >>= bMirrored;
1566
1567 // #121074# transparency of graphic is not supported in MS formats, get and apply it
1568 // in the GetTransformedGraphic call in GetBlibID
1569 if(EscherPropertyValueHelper::GetPropertyValue(aAny, rXPropSet, "Transparency"))
1570 {
1571 aAny >>= nTransparency;
1572 }
1573
1574 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustRed" ) )
1575 {
1576 aAny >>= nRed;
1577 }
1578
1579 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustGreen" ) )
1580 {
1581 aAny >>= nGreen;
1582 }
1583
1584 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "AdjustBlue" ) )
1585 {
1586 aAny >>= nBlue;
1587 }
1588
1589 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "Gamma" ) )
1590 {
1591 aAny >>= fGamma;
1592 }
1593
1594 if ( bCreateFillBitmap && bFillBitmapModeAllowed )
1595 {
1596 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapMode", true ) )
1597 aAny >>= eBitmapMode;
1598 }
1599 else
1600 {
1601 nAngle = bRotate && EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "RotateAngle", true )
1602 ? static_cast<sal_uInt16>( ( *o3tl::doAccess<sal_Int32>(aAny) ) + 5 ) / 10
1603 : 0;
1604 }
1605
1606 if (xGraphic.is())
1607 {
1608 Graphic aGraphic(xGraphic);
1609 aGraphicUrl = aGraphic.getOriginURL();
1610 }
1611
1612 if (!aGraphicUrl.isEmpty())
1613 {
1614 bool bConverted = false;
1615
1616 // externally, linked graphic? convert to embedded
1617 // one, if transformations are needed. this is because
1618 // everything < msoxp cannot even handle rotated
1619 // bitmaps.
1620 // And check whether the graphic link target is
1621 // actually supported by mso.
1622 INetURLObject aTmp( aGraphicUrl );
1623 GraphicDescriptor aDescriptor(aTmp);
1624 (void)aDescriptor.Detect();
1625 const GraphicFileFormat nFormat = aDescriptor.GetFileFormat();
1626
1627 // can MSO handle it?
1628 if ( bMirrored || nAngle || nTransparency || nRed || nGreen || nBlue || (1.0 != fGamma) ||
1629 (nFormat != GraphicFileFormat::BMP &&
1630 nFormat != GraphicFileFormat::GIF &&
1631 nFormat != GraphicFileFormat::JPG &&
1632 nFormat != GraphicFileFormat::PNG &&
1633 nFormat != GraphicFileFormat::TIF &&
1634 nFormat != GraphicFileFormat::PCT &&
1635 nFormat != GraphicFileFormat::WMF &&
1636 nFormat != GraphicFileFormat::WMZ &&
1637 nFormat != GraphicFileFormat::EMF &&
1638 nFormat != GraphicFileFormat::EMZ) )
1639 {
1640 std::unique_ptr<SvStream> pIn(::utl::UcbStreamHelper::CreateStream(
1641 aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE ), StreamMode::READ ));
1642 if ( pIn )
1643 {
1644 Graphic aGraphic;
1645 ErrCode nErrCode = GraphicConverter::Import( *pIn, aGraphic );
1646
1647 if ( nErrCode == ERRCODE_NONE )
1648 {
1649 xGraphic = aGraphic.GetXGraphic();
1650 bConverted = true;
1651 }
1652 // else: simply keep the graphic link
1653 }
1654 }
1655
1656 if (!bConverted && pGraphicProvider )
1657 {
1658 const OUString& rBaseURI( pGraphicProvider->GetBaseURI() );
1659 INetURLObject aBaseURI( rBaseURI );
1660 if( aBaseURI.GetProtocol() == aTmp.GetProtocol() )
1661 {
1662 OUString aRelUrl( INetURLObject::GetRelURL( rBaseURI, aGraphicUrl ) );
1663 if ( !aRelUrl.isEmpty() )
1664 aGraphicUrl = aRelUrl;
1665 }
1666 }
1667 }
1668
1669 if (!aGraphicUrl.isEmpty() || xGraphic.is())
1670 {
1671 if(bMirrored || nTransparency || nRed || nGreen || nBlue || (1.0 != fGamma))
1672 {
1673 pGraphicAttr.reset(new GraphicAttr);
1674
1675 if(bMirrored)
1676 {
1677 pGraphicAttr->SetMirrorFlags(BmpMirrorFlags::Horizontal);
1678 }
1679
1680 if(nTransparency)
1681 {
1682 pGraphicAttr->SetAlpha(255 - (nTransparency * 255) / 100);
1683 }
1684
1685 if(nRed)
1686 {
1687 pGraphicAttr->SetChannelR(nRed);
1688 }
1689
1690 if(nGreen)
1691 {
1692 pGraphicAttr->SetChannelG(nGreen);
1693 }
1694
1695 if(nBlue)
1696 {
1697 pGraphicAttr->SetChannelB(nBlue);
1698 }
1699
1700 if(1.0 != fGamma)
1701 {
1702 pGraphicAttr->SetGamma(fGamma);
1703 }
1704 }
1705
1706 if(nAngle && bIsGraphicMtf)
1707 {
1708 AddOpt( ESCHER_Prop_Rotation, ( ( (static_cast<sal_Int32>(nAngle) << 16 ) / 10 ) + 0x8000 ) &~ 0xffff );
1709 }
1710
1711 if ( eBitmapMode == drawing::BitmapMode_REPEAT )
1712 {
1713 sal_Int32 nSizeX = 0,nSizeY = 0,nOffsetX = 0,nOffsetY = 0,nPosOffsetX = 0,nPosOffsetY = 0;
1714 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapSizeX", true ) )
1715 {
1716 aAny >>= nSizeX;
1717 }
1718 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapSizeY", true ) )
1719 {
1720 aAny >>= nSizeY;
1721 }
1722 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapOffsetX", true ) )
1723 {
1724 aAny >>= nOffsetX;
1725 }
1726 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapOffsetY", true ) )
1727 {
1728 aAny >>= nOffsetY;
1729 }
1730 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapPositionOffsetX", true ) )
1731 {
1732 aAny >>= nPosOffsetX;
1733 }
1734 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "FillBitmapPositionOffsetY", true ) )
1735 {
1736 aAny >>= nPosOffsetY;
1737 }
1738 if(nSizeX == -100 && nSizeY == -100 && nOffsetX == 0 && nOffsetY == 0 && nPosOffsetX == 0 && nPosOffsetY == 0)
1740 else
1742 }
1743 else
1745
1746 if (xGraphic.is())
1747 {
1748 Graphic aGraphic(xGraphic);
1749 if (!aGraphic.getOriginURL().isEmpty())
1750 {
1751 AddOpt(ESCHER_Prop_pibName, aGraphicUrl);
1752 sal_uInt32 nPibFlags = 0;
1753 GetOpt(ESCHER_Prop_pibFlags, nPibFlags);
1755 }
1756 else if (pGraphicProvider && pPicOutStrm && pShapeBoundRect) // write out embedded graphic
1757 {
1758 GraphicObject aGraphicObject(aGraphic);
1759 const sal_uInt32 nBlibId(pGraphicProvider->GetBlibID(*pPicOutStrm, aGraphicObject, nullptr, pGraphicAttr.get()));
1760
1761 if(nBlibId)
1762 {
1763 if(bCreateFillBitmap)
1764 {
1765 AddOpt(ESCHER_Prop_fillBlip, nBlibId, true);
1766 }
1767 else
1768 {
1769 AddOpt( ESCHER_Prop_pib, nBlibId, true );
1770 ImplCreateGraphicAttributes( rXPropSet, nBlibId, bCreateCroppingAttributes );
1771 }
1772
1773 bRetValue = true;
1774 }
1775 }
1776 else
1777 {
1778 EscherGraphicProvider aProvider;
1779 SvMemoryStream aMemStrm;
1780 GraphicObject aGraphicObject(std::move(aGraphic));
1781
1782 if (aProvider.GetBlibID(aMemStrm, aGraphicObject, nullptr, pGraphicAttr.get(), bOOxmlExport))
1783 {
1784 AddOpt(ESCHER_Prop_fillBlip, true, 0, aMemStrm);
1785 bRetValue = true;
1786 }
1787 }
1788 }
1789 }
1790 }
1791 pGraphicAttr.reset();
1792 if ( bCreateFillStyles )
1793 CreateFillProperties( rXPropSet, true );
1794
1795 return bRetValue;
1796}
1797
1798tools::PolyPolygon EscherPropertyContainer::GetPolyPolygon( const uno::Reference< drawing::XShape > & rXShape )
1799{
1800 tools::PolyPolygon aRetPolyPoly;
1801 uno::Reference< beans::XPropertySet > aXPropSet;
1802 uno::Any aAny( rXShape->queryInterface(
1804
1805 if ( aAny >>= aXPropSet )
1806 {
1807 bool bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygonBezier", true );
1808 if ( !bHasProperty )
1809 bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygon", true );
1810 if ( !bHasProperty )
1811 bHasProperty = EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "Polygon", true );
1812 if ( bHasProperty )
1813 aRetPolyPoly = GetPolyPolygon( aAny );
1814 }
1815 return aRetPolyPoly;
1816}
1817
1818// adapting to basegfx::B2DPolyPolygon now, has no sense to do corrections in the
1819// old tools::PolyPolygon creation code. Convert to that at return time
1821{
1823
1824 if(auto pBCC = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(rAny))
1825 {
1827 }
1828 else if(auto pCC = o3tl::tryAccess<drawing::PointSequenceSequence>(rAny))
1829 {
1831 }
1832 else if(auto pC = o3tl::tryAccess<drawing::PointSequence>(rAny))
1833 {
1835 }
1836
1837 basegfx::B2DPolyPolygon aRetval2;
1838
1839 for(sal_uInt32 a(0); a < aRetval.count(); a++)
1840 {
1841 if(0 != aRetval.getB2DPolygon(a).count())
1842 {
1843 aRetval2.append(aRetval.getB2DPolygon(a));
1844 }
1845 }
1846
1847 return tools::PolyPolygon(aRetval2);
1848}
1849
1851 const uno::Reference<beans::XPropertySet> & rXPropSet,
1852 sal_uInt32 nFlags,
1853 bool bBezier,
1854 awt::Rectangle& rGeoRect,
1855 tools::Polygon const * pPolygon )
1856{
1857 tools::PolyPolygon aPolyPolygon;
1858
1859 if(nullptr != pPolygon)
1860 {
1861 aPolyPolygon.Insert(*pPolygon);
1862 }
1863 else
1864 {
1865 uno::Any aAny;
1866
1868 aAny,
1869 rXPropSet,
1870 bBezier ? OUString("PolyPolygonBezier") : OUString("PolyPolygon"),
1871 true))
1872 {
1873 aPolyPolygon = GetPolyPolygon(aAny);
1874 }
1875 else
1876 {
1877 return false;
1878 }
1879 }
1880
1881 if(0 == aPolyPolygon.Count())
1882 {
1883 return false;
1884 }
1885
1886 if(0 != (nFlags & ESCHER_CREATEPOLYGON_LINE))
1887 {
1888 if((1 == aPolyPolygon.Count()) && (2 == aPolyPolygon[0].GetSize()))
1889 {
1890 const tools::Polygon& rPoly(aPolyPolygon[0]);
1891
1892 rGeoRect = awt::Rectangle(
1893 rPoly[0].X(),
1894 rPoly[0].Y(),
1895 rPoly[1].X() - rPoly[0].X(),
1896 rPoly[1].Y() - rPoly[0].Y());
1897
1898 return true;
1899 }
1900
1901 return false;
1902 }
1903
1904 const tools::Rectangle aRect(aPolyPolygon.GetBoundRect());
1905
1906 rGeoRect = awt::Rectangle(
1907 aRect.Left(),
1908 aRect.Top(),
1909 aRect.GetWidth(),
1910 aRect.GetHeight());
1911
1912 const sal_uInt16 nPolyCount(aPolyPolygon.Count());
1913 sal_uInt32 nTotalPoints(0);
1914
1915 std::vector< sal_uInt8 > aVertices
1916 {
1917 0, 0, 0, 0,
1918 static_cast<sal_uInt8>(0xf0),
1919 static_cast<sal_uInt8>(0xff)
1920 };
1921
1922 std::vector< sal_uInt8 > aSegments
1923 {
1924 0, 0, 0, 0,
1925 static_cast<sal_uInt8>(2),
1926 static_cast<sal_uInt8>(0)
1927 };
1928
1929 for(sal_uInt16 j(0); j < nPolyCount; ++j)
1930 {
1931 const tools::Polygon aPolygon(aPolyPolygon[j]);
1932 const sal_uInt16 nPoints(aPolygon.GetSize());
1933
1934 if(0 == nPoints)
1935 {
1936 continue;
1937 }
1938
1939 // Polygon start
1940 aSegments.push_back(static_cast<sal_uInt8>(0x0));
1941 aSegments.push_back(static_cast<sal_uInt8>(0x40));
1942
1943 sal_uInt16 nSegmentIgnoreCounter(0);
1944
1945 // write points from polygon to buffer
1946 for(sal_uInt16 i(0); i < nPoints; ++i)
1947 {
1948 Point aPoint(aPolygon[i]);
1949
1950 aPoint.AdjustX(-(rGeoRect.X));
1951 aPoint.AdjustY(-(rGeoRect.Y));
1952
1953 aVertices.push_back(static_cast<sal_uInt8>(aPoint.X()));
1954 aVertices.push_back(static_cast<sal_uInt8>(aPoint.X() >> 8));
1955 aVertices.push_back(static_cast<sal_uInt8>(aPoint.Y()));
1956 aVertices.push_back(static_cast<sal_uInt8>(aPoint.Y() >> 8));
1957
1958 nTotalPoints++;
1959
1960 if(0 != nSegmentIgnoreCounter)
1961 {
1962 nSegmentIgnoreCounter--;
1963 }
1964 else
1965 {
1966 aSegments.push_back(static_cast<sal_uInt8>(0));
1967
1968 if(bBezier)
1969 {
1970 aSegments.push_back(static_cast<sal_uInt8>(0xb3));
1971 }
1972 else
1973 {
1974 aSegments.push_back(static_cast<sal_uInt8>(0xac));
1975 }
1976
1977 if(i + 1 == nPoints)
1978 {
1979 if(nPolyCount > 1)
1980 {
1981 // end of polygon
1982 aSegments.push_back(static_cast<sal_uInt8>(1));
1983 aSegments.push_back(static_cast<sal_uInt8>(0x60));
1984 }
1985 }
1986 else
1987 {
1988 aSegments.push_back(static_cast<sal_uInt8>(1));
1989
1990 if(PolyFlags::Control == aPolygon.GetFlags(i + 1))
1991 {
1992 aSegments.push_back(static_cast<sal_uInt8>(0x20));
1993 nSegmentIgnoreCounter = 2;
1994 }
1995 else
1996 {
1997 aSegments.push_back(static_cast<sal_uInt8>(0));
1998 }
1999 }
2000 }
2001 }
2002 }
2003
2004 if(0 == nTotalPoints || aSegments.size() < 6 || aVertices.size() < 6)
2005 return false;
2006
2007 // Little endian
2008 aVertices[0] = static_cast<sal_uInt8>(nTotalPoints);
2009 aVertices[1] = static_cast<sal_uInt8>(nTotalPoints >> 8);
2010 aVertices[2] = static_cast<sal_uInt8>(nTotalPoints);
2011 aVertices[3] = static_cast<sal_uInt8>(nTotalPoints >> 8);
2012
2013 aSegments.push_back(static_cast<sal_uInt8>(0));
2014 aSegments.push_back(static_cast<sal_uInt8>(0x80));
2015
2016 const sal_uInt32 nSegmentBufSize(aSegments.size() - 6);
2017 aSegments[0] = static_cast<sal_uInt8>(nSegmentBufSize >> 1);
2018 aSegments[1] = static_cast<sal_uInt8>(nSegmentBufSize >> 9);
2019 aSegments[2] = static_cast<sal_uInt8>(nSegmentBufSize >> 1);
2020 aSegments[3] = static_cast<sal_uInt8>(nSegmentBufSize >> 9);
2021
2022 AddOpt(
2024 rGeoRect.Width);
2025 AddOpt(
2027 rGeoRect.Height);
2028 AddOpt(
2031 AddOpt(
2033 true,
2034 aVertices.size() - 6,
2035 aVertices);
2036 AddOpt(
2038 true,
2039 aSegments.size(),
2040 aSegments);
2041
2042 return true;
2043}
2044
2045
2046/*
2047in MS,the connector including 9 types :
2048"straightConnector1",
2049"bentConnector2","bentConnector3","bentConnector4","bentConnector5"
2050"curvedConnector2","curvedConnector3","curvedConnector4","curvedConnector5"
2051in AOO,including 4 types:"standard","lines","line","curve"
2052when save as MS file, the connector must be convert to corresponding type.
2053"line" and "lines" <-> "straightConnector1"
2054"standard" <-> "bentConnector2-5"
2055"curve" <-> "curvedConnector2-5"
2056*/
2057static sal_Int32 lcl_GetAdjustValueCount( const XPolygon& rPoly )
2058{
2059 int nRet = 0;
2060 switch ( rPoly.GetSize() )
2061 {
2062 case 2 :
2063 case 3:
2064 nRet = 0;
2065 break;
2066 case 4:
2067 nRet = 1;
2068 break;
2069 case 5:
2070 nRet = 2;
2071 break;
2072 default:
2073 if ( rPoly.GetSize()>=6 )
2074 nRet = 3;
2075 break;
2076 }
2077 return nRet;
2078}
2079
2080// Adjust value decide the position which connector should turn a corner
2081static sal_Int32 lcl_GetConnectorAdjustValue ( const XPolygon& rPoly, sal_uInt16 nIndex )
2082{
2083 sal_uInt16 k = rPoly.GetSize();
2084 OSL_ASSERT ( k >= ( 3 + nIndex ) );
2085
2086 Point aPt;
2087 Point aStart = rPoly[0];
2088 Point aEnd = rPoly[k-1];
2089 if ( aEnd.Y() == aStart.Y() )
2090 aEnd.setY( aStart.Y() +4 );
2091 if ( aEnd.X() == aStart.X() )
2092 aEnd.setX( aStart.X() +4 );
2093
2094 bool bVertical = ( rPoly[1].X()-aStart.X() ) == 0 ;
2095 // vertical and horizon alternate
2096 if ( nIndex%2 == 1 ) bVertical = !bVertical;
2097 aPt = rPoly[ nIndex + 1];
2098
2099 sal_Int32 nAdjustValue;
2100 if ( bVertical )
2101 nAdjustValue = ( aPt.Y()-aStart.Y())* 21600 /(aEnd.Y()-aStart.Y());
2102 else
2103 nAdjustValue = ( aPt.X()-aStart.X() )* 21600 /(aEnd.X()-aStart.X());
2104
2105 return nAdjustValue;
2106}
2107
2108
2109static void lcl_Rotate(Degree100 nAngle, Point center, Point& pt)
2110{
2111 nAngle = NormAngle36000(nAngle);
2112
2113 int cs, sn;
2114 switch (nAngle.get())
2115 {
2116 case 0:
2117 cs =1;
2118 sn =0;
2119 break;
2120 case 9000:
2121 cs =0;
2122 sn =1;
2123 break;
2124 case 18000:
2125 cs = -1;
2126 sn = 0;
2127 break;
2128 case 27000:
2129 cs = 0;
2130 sn = -1;
2131 break;
2132 default:
2133 return;
2134 }
2135 sal_Int32 x0 =pt.X()-center.X();
2136 sal_Int32 y0 =pt.Y()-center.Y();
2137 pt.setX(center.X()+ x0*cs-y0*sn );
2138 pt.setY(center.Y()+ y0*cs+x0*sn );
2139}
2140/*
2141 FlipV defines that the shape will be flipped vertically about the center of its bounding box.
2142Generally, draw the connector from top to bottom, from left to right when meet the adjust value,
2143but when (X1>X2 or Y1>Y2),the draw director must be reverse, FlipV or FlipH should be set to true.
2144*/
2145static bool lcl_GetAngle(tools::Polygon &rPoly, ShapeFlag& rShapeFlags,sal_Int32& nAngle )
2146{
2147 Point aStart = rPoly[0];
2148 Point aEnd = rPoly[rPoly.GetSize()-1];
2149 nAngle = ( rPoly[1].X() == aStart.X() ) ? 9000: 0 ;
2150 Point p1(aStart.X(),aStart.Y());
2151 Point p2(aEnd.X(),aEnd.Y());
2152 if ( nAngle )
2153 {
2154 Point center((aEnd.X()+aStart.X())>>1,(aEnd.Y()+aStart.Y())>>1);
2155 lcl_Rotate(Degree100(-nAngle), center,p1);
2156 lcl_Rotate(Degree100(-nAngle), center,p2);
2157 }
2158 if ( p1.X() > p2.X() )
2159 {
2160 if ( nAngle )
2161 rShapeFlags |= ShapeFlag::FlipV;
2162 else
2163 rShapeFlags |= ShapeFlag::FlipH;
2164
2165 }
2166 if ( p1.Y() > p2.Y() )
2167 {
2168 if ( nAngle )
2169 rShapeFlags |= ShapeFlag::FlipH;
2170 else
2171 rShapeFlags |= ShapeFlag::FlipV;
2172 }
2173
2174 if ( (rShapeFlags&ShapeFlag::FlipH) && (rShapeFlags&ShapeFlag::FlipV) )
2175 {
2176 rShapeFlags &= ~ShapeFlag( ShapeFlag::FlipH | ShapeFlag::FlipV );
2177 nAngle +=18000;
2178 }
2179
2180 if ( nAngle )
2181 {
2182 // Set angle properties
2183 nAngle *= 655;
2184 nAngle += 0x8000;
2185 nAngle &=~0xffff; // round nAngle to whole number of degrees
2186 return true;
2187 }
2188 return false;
2189}
2191 const uno::Reference<drawing::XShape> & rXShape,
2192 EscherSolverContainer& rSolverContainer, awt::Rectangle& rGeoRect,
2193 sal_uInt16& rShapeType, ShapeFlag& rShapeFlags )
2194{
2195 bool bRetValue = false;
2196 rShapeType = 0;
2197 rShapeFlags = ShapeFlag::NONE;
2198
2199 if ( rXShape.is() )
2200 {
2201 uno::Reference<beans::XPropertySet> aXPropSet;
2202 uno::Reference<drawing::XShape> aShapeA, aShapeB;
2203 uno::Any aAny( rXShape->queryInterface( cppu::UnoType<beans::XPropertySet>::get()));
2204 if ( aAny >>= aXPropSet )
2205 {
2206 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeKind", true ) )
2207 {
2208 drawing::ConnectorType eCt;
2209 aAny >>= eCt;
2210 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeStartPoint" ) )
2211 {
2212 awt::Point aStartPoint = *o3tl::doAccess<awt::Point>(aAny);
2213 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeEndPoint" ) )
2214 {
2215 awt::Point aEndPoint = *o3tl::doAccess<awt::Point>(aAny);
2216
2218 rGeoRect = awt::Rectangle( aStartPoint.X, aStartPoint.Y,
2219 ( aEndPoint.X - aStartPoint.X ) + 1, ( aEndPoint.Y - aStartPoint.Y ) + 1 );
2220 // set standard's FLIP in below code
2221 if ( eCt != drawing::ConnectorType_STANDARD)
2222 {
2223 if ( rGeoRect.Height < 0 ) // justify
2224 {
2225 rShapeFlags |= ShapeFlag::FlipV;
2226 rGeoRect.Y = aEndPoint.Y;
2227 rGeoRect.Height = -rGeoRect.Height;
2228 }
2229 if ( rGeoRect.Width < 0 )
2230 {
2231 rShapeFlags |= ShapeFlag::FlipH;
2232 rGeoRect.X = aEndPoint.X;
2233 rGeoRect.Width = -rGeoRect.Width;
2234 }
2235 }
2236 sal_uInt32 nAdjustValue1, nAdjustValue2;
2237 nAdjustValue1 = nAdjustValue2 = 0x2a30;
2238
2239 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeStartConnection" ) )
2240 aAny >>= aShapeA;
2241 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "EdgeEndConnection" ) )
2242 aAny >>= aShapeB;
2243 rSolverContainer.AddConnector( rXShape, aStartPoint, aShapeA, aEndPoint, aShapeB );
2244 switch ( eCt )
2245 {
2246 case drawing::ConnectorType_CURVE :
2247 {
2250 AddOpt( ESCHER_Prop_adjustValue, nAdjustValue1 );
2251 AddOpt( ESCHER_Prop_adjust2Value, -static_cast<sal_Int32>(nAdjustValue2) );
2252 }
2253 break;
2254
2255 case drawing::ConnectorType_STANDARD :// Connector 2->5
2256 {
2257 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "PolyPolygonBezier" ) )
2258 {
2259 tools::PolyPolygon aPolyPolygon = GetPolyPolygon( aAny );
2260 tools::Polygon aPoly;
2261 if ( aPolyPolygon.Count() > 0 )
2262 {
2264 aPoly = aPolyPolygon[ 0 ];
2265 sal_Int32 nAdjCount = lcl_GetAdjustValueCount( aPoly );
2266 rShapeType = static_cast<sal_uInt16>( ESCHER_ShpInst_BentConnector2 + nAdjCount);
2267 for ( sal_Int32 i = 0 ; i < nAdjCount; ++ i)
2268 AddOpt( static_cast<sal_uInt16>( ESCHER_Prop_adjustValue+i) , lcl_GetConnectorAdjustValue( aPoly, i ) );
2269 }
2270 sal_Int32 nAngle=0;
2271 if (lcl_GetAngle(aPoly,rShapeFlags,nAngle ))
2272 {
2273 AddOpt( ESCHER_Prop_Rotation, nAngle );
2274 }
2275 }
2276 else
2277 {
2278 rShapeType = ESCHER_ShpInst_BentConnector3;
2280 }
2281 }
2282 break;
2283 default:
2284 case drawing::ConnectorType_LINE :
2285 case drawing::ConnectorType_LINES : // Connector 2->5
2286 {
2289 }
2290 break;
2291 }
2292 CreateLineProperties( aXPropSet, false );
2293 bRetValue = true;
2294 }
2295 }
2296 }
2297 }
2298 }
2299 return bRetValue;
2300}
2301
2303 const uno::Reference<beans::XPropertySet> & rXPropSet )
2304{
2305 uno::Any aAny;
2306
2307 sal_uInt32 nLineFlags = 0; // default : shape has no line
2308 sal_uInt32 nFillFlags = 0x10; // shape is filled
2309
2310 GetOpt( ESCHER_Prop_fNoLineDrawDash, nLineFlags );
2311 GetOpt( ESCHER_Prop_fNoFillHitTest, nFillFlags );
2312
2313 sal_uInt32 nDummy;
2314 bool bGraphic = GetOpt( DFF_Prop_pib, nDummy ) || GetOpt( DFF_Prop_pibName, nDummy ) || GetOpt( DFF_Prop_pibFlags, nDummy );
2315
2316 sal_uInt32 nShadowFlags = 0x20000;
2317 if ( ( nLineFlags & 8 ) || ( nFillFlags & 0x10 ) || bGraphic )
2318 {
2319 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "Shadow", true ) )
2320 {
2321 bool bHasShadow = false; // shadow is possible only if at least a fillcolor, linecolor or graphic is set
2322 if ( (aAny >>= bHasShadow) && bHasShadow )
2323 {
2324 nShadowFlags |= 2;
2325 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowColor" ) )
2326 AddOpt( ESCHER_Prop_shadowColor, ImplGetColor( *o3tl::doAccess<sal_uInt32>(aAny) ) );
2327 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowXDistance" ) )
2328 AddOpt( ESCHER_Prop_shadowOffsetX, *o3tl::doAccess<sal_Int32>(aAny) * 360 );
2329 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowYDistance" ) )
2330 AddOpt( ESCHER_Prop_shadowOffsetY, *o3tl::doAccess<sal_Int32>(aAny) * 360 );
2331 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, rXPropSet, "ShadowTransparence" ) )
2332 AddOpt( ESCHER_Prop_shadowOpacity, 0x10000 - (static_cast<sal_uInt32>(*o3tl::doAccess<sal_uInt16>(aAny)) * 655 ) );
2333 }
2334 }
2335 }
2336 AddOpt( ESCHER_Prop_fshadowObscured, nShadowFlags );
2337}
2338
2339sal_Int32 EscherPropertyContainer::GetValueForEnhancedCustomShapeParameter( const drawing::EnhancedCustomShapeParameter& rParameter,
2340 const std::vector< sal_Int32 >& rEquationOrder, bool bAdjustTrans )
2341{
2342 sal_Int32 nValue = 0;
2343 if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
2344 {
2345 double fValue(0.0);
2346 if ( rParameter.Value >>= fValue )
2347 nValue = static_cast<sal_Int32>(fValue);
2348 }
2349 else
2350 rParameter.Value >>= nValue;
2351
2352 switch( rParameter.Type )
2353 {
2354 case drawing::EnhancedCustomShapeParameterType::EQUATION :
2355 {
2356 size_t nIndex = static_cast<size_t>(nValue);
2357 OSL_ASSERT(nIndex < rEquationOrder.size());
2358 if ( nIndex < rEquationOrder.size() )
2359 {
2360 nValue = static_cast<sal_uInt16>(rEquationOrder[ nIndex ]);
2361 nValue |= sal_uInt32(0x80000000);
2362 }
2363 }
2364 break;
2365 case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT:
2366 {
2367 if(bAdjustTrans)
2368 {
2369 sal_uInt32 nAdjustValue = 0;
2370 bool bGot = GetOpt(static_cast<sal_uInt16>( DFF_Prop_adjustValue + nValue ), nAdjustValue);
2371 if(bGot) nValue = static_cast<sal_Int32>(nAdjustValue);
2372 }
2373 }
2374 break;
2375 case drawing::EnhancedCustomShapeParameterType::NORMAL :
2376 default:
2377 break;
2378/* not sure if it is allowed to set following values
2379(but they are not yet used)
2380 case drawing::EnhancedCustomShapeParameterType::BOTTOM :
2381 case drawing::EnhancedCustomShapeParameterType::RIGHT :
2382 case drawing::EnhancedCustomShapeParameterType::TOP :
2383 case drawing::EnhancedCustomShapeParameterType::LEFT :
2384*/
2385 }
2386 return nValue;
2387}
2388
2389static bool GetValueForEnhancedCustomShapeHandleParameter( sal_Int32& nRetValue, const drawing::EnhancedCustomShapeParameter& rParameter )
2390{
2391 bool bSpecial = false;
2392 nRetValue = 0;
2393 if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
2394 {
2395 double fValue(0.0);
2396 if ( rParameter.Value >>= fValue )
2397 nRetValue = static_cast<sal_Int32>(fValue);
2398 }
2399 else
2400 rParameter.Value >>= nRetValue;
2401
2402 switch( rParameter.Type )
2403 {
2404 case drawing::EnhancedCustomShapeParameterType::EQUATION :
2405 {
2406 nRetValue += 3;
2407 bSpecial = true;
2408 }
2409 break;
2410 case drawing::EnhancedCustomShapeParameterType::ADJUSTMENT :
2411 {
2412 nRetValue += 0x100;
2413 bSpecial = true;
2414 }
2415 break;
2416 case drawing::EnhancedCustomShapeParameterType::TOP :
2417 case drawing::EnhancedCustomShapeParameterType::LEFT :
2418 {
2419 nRetValue = 0;
2420 bSpecial = true;
2421 }
2422 break;
2423 case drawing::EnhancedCustomShapeParameterType::RIGHT :
2424 case drawing::EnhancedCustomShapeParameterType::BOTTOM :
2425 {
2426 nRetValue = 1;
2427 bSpecial = true;
2428 }
2429 break;
2430 case drawing::EnhancedCustomShapeParameterType::NORMAL :
2431 {
2432
2433 }
2434 break;
2435 }
2436 return bSpecial;
2437}
2438
2440 const SdrObjCustomShape& rSdrObjCustomShape,
2441 std::vector< EnhancedCustomShapeEquation >& rEquations,
2442 std::vector< sal_Int32 >& rEquationOrder )
2443{
2444 uno::Sequence< OUString > sEquationSource;
2445 const SdrCustomShapeGeometryItem& rGeometryItem =
2446 rSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
2447 const uno::Any* pAny = rGeometryItem.GetPropertyValueByName( "Equations" );
2448 if ( pAny )
2449 *pAny >>= sEquationSource;
2450 sal_Int32 nEquationSourceCount = sEquationSource.getLength();
2451 if ( !(nEquationSourceCount && (nEquationSourceCount <= 128)) )
2452 return;
2453
2454 sal_Int32 i;
2455 for ( i = 0; i < nEquationSourceCount; i++ )
2456 {
2457 EnhancedCustomShape2d aCustomShape2d(
2458 const_cast< SdrObjCustomShape& >(rSdrObjCustomShape));
2459 try
2460 {
2461 std::shared_ptr< EnhancedCustomShape::ExpressionNode > aExpressNode(
2462 EnhancedCustomShape::FunctionParser::parseFunction(
2463 sEquationSource[ i ], aCustomShape2d));
2464 drawing::EnhancedCustomShapeParameter aPara( aExpressNode->fillNode( rEquations, nullptr, 0 ) );
2465 if ( aPara.Type != drawing::EnhancedCustomShapeParameterType::EQUATION )
2466 {
2468 aEquation.nOperation = 0;
2469 EnhancedCustomShape::FillEquationParameter( aPara, 0, aEquation );
2470 rEquations.push_back( aEquation );
2471 }
2472 }
2473 catch ( const EnhancedCustomShape::ParseError& )
2474 {
2475 EnhancedCustomShapeEquation aEquation; // ups, we should not be here,
2476 aEquation.nOperation = 0; // creating a default equation with value 1
2477 aEquation.nPara[ 0 ] = 1; // hoping that this will not break anything
2478 rEquations.push_back( aEquation );
2479 }
2480 catch ( ... )
2481 {
2482 EnhancedCustomShapeEquation aEquation; // #i112309# EnhancedCustomShape::Parse error
2483 aEquation.nOperation = 0; // not caught on linux platform
2484 aEquation.nPara[ 0 ] = 1;
2485 rEquations.push_back( aEquation );
2486 }
2487 rEquationOrder.push_back( rEquations.size() - 1 );
2488 }
2489 // now updating our old equation indices, they are marked with a bit in the hiword of nOperation
2490 for (auto & equation : rEquations)
2491 {
2492 sal_uInt32 nMask = 0x20000000;
2493 for( i = 0; i < 3; i++ )
2494 {
2495 if ( equation.nOperation & nMask )
2496 {
2497 equation.nOperation ^= nMask;
2498 const size_t nIndex(equation.nPara[ i ] & 0x3ff);
2499
2500 // #i124661# check index access, there are cases where this is out of bound leading
2501 // to errors up to crashes when executed
2502 if(nIndex < rEquationOrder.size())
2503 {
2504 equation.nPara[ i ] = rEquationOrder[ nIndex ] | 0x400;
2505 }
2506 else
2507 {
2508 OSL_ENSURE(false, "Attempted out of bound access to rEquationOrder of CustomShape (!)");
2509 }
2510 }
2511 nMask <<= 1;
2512 }
2513 }
2514}
2515
2517 const SdrObjCustomShape& rSdrObjCustomShape,
2518 const MSO_SPT eShapeType)
2519{
2520 switch(eShapeType)
2521 {
2522 // if the custom shape is not default shape of ppt, return false;
2523 case mso_sptTearDrop:
2524 return false;
2525
2526 default:
2527 break;
2528 }
2529
2538}
2539
2540void EscherPropertyContainer::LookForPolarHandles( const MSO_SPT eShapeType, sal_Int32& nAdjustmentsWhichNeedsToBeConverted )
2541{
2542 const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eShapeType );
2543 if ( !(pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles) )
2544 return;
2545
2546 sal_Int32 k, nkCount = pDefCustomShape->nHandles;
2547 const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
2548 for ( k = 0; k < nkCount; k++, pData++ )
2549 {
2550 if ( pData->nFlags & SvxMSDffHandleFlags::POLAR )
2551 {
2552 if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) )
2553 nAdjustmentsWhichNeedsToBeConverted |= ( 1 << k );
2554 }
2555 }
2556}
2557
2558bool EscherPropertyContainer::GetAdjustmentValue( const drawing::EnhancedCustomShapeAdjustmentValue & rkProp, sal_Int32 nIndex, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, sal_Int32& nValue )
2559{
2560 if ( rkProp.State != beans::PropertyState_DIRECT_VALUE )
2561 return false;
2562
2563 bool bUseFixedFloat = ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << nIndex ) ) != 0;
2564 if ( rkProp.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
2565 {
2566 double fValue(0.0);
2567 rkProp.Value >>= fValue;
2568 if ( bUseFixedFloat )
2569 fValue *= 65536.0;
2570 nValue = static_cast<sal_Int32>(fValue);
2571 }
2572 else
2573 {
2574 rkProp.Value >>= nValue;
2575 if ( bUseFixedFloat )
2576 nValue <<= 16;
2577 }
2578
2579 return true;
2580}
2581
2582void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeType, const uno::Reference< drawing::XShape > & rXShape )
2583{
2584 uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
2585 if ( !aXPropSet.is() )
2586 return;
2587
2588 SdrObjCustomShape* pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(rXShape));
2589 if(!pSdrObjCustomShape)
2590 {
2591 return;
2592 }
2593
2594 SdrObjCustomShape& rSdrObjCustomShape = *pSdrObjCustomShape;
2595 uno::Any aGeoPropSet = aXPropSet->getPropertyValue( "CustomShapeGeometry" );
2596 uno::Sequence< beans::PropertyValue > aGeoPropSeq;
2597 if ( !(aGeoPropSet >>= aGeoPropSeq) )
2598 return;
2599
2600 static constexpr OUStringLiteral sViewBox ( u"ViewBox" );
2601 static constexpr OUStringLiteral sTextRotateAngle ( u"TextRotateAngle" );
2602 static constexpr OUStringLiteral sExtrusion ( u"Extrusion" );
2603 static constexpr OUStringLiteral sEquations ( u"Equations" );
2604 static constexpr OUStringLiteral sPath ( u"Path" );
2605 static constexpr OUStringLiteral sTextPath ( u"TextPath" );
2606 static constexpr OUStringLiteral sHandles ( u"Handles" );
2607 static constexpr OUStringLiteral sAdjustmentValues ( u"AdjustmentValues" );
2608
2609 bool bAdjustmentValuesProp = false;
2610 uno::Any aAdjustmentValuesProp;
2611 bool bPathCoordinatesProp = false;
2612 uno::Any aPathCoordinatesProp;
2613
2614 sal_Int32 nAdjustmentsWhichNeedsToBeConverted = 0;
2615 uno::Sequence< beans::PropertyValues > aHandlesPropSeq;
2616 bool bPredefinedHandlesUsed = true;
2617 const bool bIsDefaultObject(
2619 rSdrObjCustomShape,
2620 eShapeType));
2621
2622 // convert property "Equations" into std::vector< EnhancedCustomShapeEquationEquation >
2623 std::vector< EnhancedCustomShapeEquation > aEquations;
2624 std::vector< sal_Int32 > aEquationOrder;
2626 rSdrObjCustomShape,
2627 aEquations,
2628 aEquationOrder);
2629
2630 sal_Int32 i, nCount = aGeoPropSeq.getLength();
2631 for ( i = 0; i < nCount; i++ )
2632 {
2633 const beans::PropertyValue& rProp = aGeoPropSeq[ i ];
2634 if ( rProp.Name == sViewBox )
2635 {
2636 if ( !bIsDefaultObject )
2637 {
2638 awt::Rectangle aViewBox;
2639 if ( rProp.Value >>= aViewBox )
2640 {
2641 AddOpt( DFF_Prop_geoLeft, aViewBox.X );
2642 AddOpt( DFF_Prop_geoTop, aViewBox.Y );
2643 AddOpt( DFF_Prop_geoRight, aViewBox.X + aViewBox.Width );
2644 AddOpt( DFF_Prop_geoBottom,aViewBox.Y + aViewBox.Height );
2645 }
2646 }
2647 }
2648 else if ( rProp.Name == sTextRotateAngle )
2649 {
2650 double f = 0;
2651 if ( rProp.Value >>= f )
2652 {
2653 double fTextRotateAngle = fmod( f, 360.0 );
2654 if ( fTextRotateAngle < 0 )
2655 fTextRotateAngle = 360 + fTextRotateAngle;
2656 if ( ( fTextRotateAngle < 271.0 ) && ( fTextRotateAngle > 269.0 ) )
2658 else if ( ( fTextRotateAngle < 181.0 ) && ( fTextRotateAngle > 179.0 ) )
2660 else if ( ( fTextRotateAngle < 91.0 ) && ( fTextRotateAngle > 79.0 ) )
2662 }
2663 }
2664 else if ( rProp.Name == sExtrusion )
2665 {
2666 uno::Sequence< beans::PropertyValue > aExtrusionPropSeq;
2667 if ( rProp.Value >>= aExtrusionPropSeq )
2668 {
2669 sal_uInt32 nLightFaceFlagsOrg, nLightFaceFlags;
2670 sal_uInt32 nFillHarshFlagsOrg, nFillHarshFlags;
2671 nLightFaceFlagsOrg = nLightFaceFlags = 0x000001;
2672 nFillHarshFlagsOrg = nFillHarshFlags = 0x00001e;
2673 if ( GetOpt( DFF_Prop_fc3DLightFace, nLightFaceFlags ) )
2674 nLightFaceFlagsOrg = nLightFaceFlags;
2675 if ( GetOpt( DFF_Prop_fc3DFillHarsh, nFillHarshFlags ) )
2676 nFillHarshFlagsOrg = nFillHarshFlags;
2677
2678 sal_Int32 r, nrCount = aExtrusionPropSeq.getLength();
2679 for ( r = 0; r < nrCount; r++ )
2680 {
2681 const beans::PropertyValue& rrProp = aExtrusionPropSeq[ r ];
2682
2683 if ( rrProp.Name == sExtrusion )
2684 {
2685 bool bExtrusionOn;
2686 if ( rrProp.Value >>= bExtrusionOn )
2687 {
2688 nLightFaceFlags |= 0x80000;
2689 if ( bExtrusionOn )
2690 nLightFaceFlags |= 8;
2691 else
2692 nLightFaceFlags &=~8;
2693 }
2694 }
2695 else if ( rrProp.Name == "Brightness" )
2696 {
2697 double fExtrusionBrightness = 0;
2698 if ( rrProp.Value >>= fExtrusionBrightness )
2699 AddOpt( DFF_Prop_c3DAmbientIntensity, static_cast<sal_Int32>( fExtrusionBrightness * 655.36 ) );
2700 }
2701 else if ( rrProp.Name == "Depth" )
2702 {
2703 double fDepth = 0;
2704 double fFraction = 0;
2705 drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
2706 if ( ( rrProp.Value >>= aDepthParaPair ) && ( aDepthParaPair.First.Value >>= fDepth ) && ( aDepthParaPair.Second.Value >>= fFraction ) )
2707 {
2708 double fForeDepth = fDepth * fFraction;
2709 double fBackDepth = fDepth - fForeDepth;
2710
2711 fBackDepth *= 360.0;
2712 AddOpt( DFF_Prop_c3DExtrudeBackward, static_cast<sal_Int32>(fBackDepth) );
2713
2714 if ( fForeDepth != 0.0 )
2715 {
2716 fForeDepth *= 360.0;
2717 AddOpt( DFF_Prop_c3DExtrudeForward, static_cast<sal_Int32>(fForeDepth) );
2718 }
2719 }
2720 }
2721 else if ( rrProp.Name == "Diffusion" )
2722 {
2723 double fExtrusionDiffusion = 0;
2724 if ( rrProp.Value >>= fExtrusionDiffusion )
2725 AddOpt( DFF_Prop_c3DDiffuseAmt, static_cast<sal_Int32>( fExtrusionDiffusion * 655.36 ) );
2726 }
2727 else if ( rrProp.Name == "NumberOfLineSegments" )
2728 {
2729 sal_Int32 nExtrusionNumberOfLineSegments = 0;
2730 if ( rrProp.Value >>= nExtrusionNumberOfLineSegments )
2731 AddOpt( DFF_Prop_c3DTolerance, nExtrusionNumberOfLineSegments );
2732 }
2733 else if ( rrProp.Name == "LightFace" )
2734 {
2735 bool bExtrusionLightFace;
2736 if ( rrProp.Value >>= bExtrusionLightFace )
2737 {
2738 nLightFaceFlags |= 0x10000;
2739 if ( bExtrusionLightFace )
2740 nLightFaceFlags |= 1;
2741 else
2742 nLightFaceFlags &=~1;
2743 }
2744 }
2745 else if ( rrProp.Name == "FirstLightHarsh" )
2746 {
2747 bool bExtrusionFirstLightHarsh;
2748 if ( rrProp.Value >>= bExtrusionFirstLightHarsh )
2749 {
2750 nFillHarshFlags |= 0x20000;
2751 if ( bExtrusionFirstLightHarsh )
2752 nFillHarshFlags |= 2;
2753 else
2754 nFillHarshFlags &=~2;
2755 }
2756 }
2757 else if ( rrProp.Name == "SecondLightHarsh" )
2758 {
2759 bool bExtrusionSecondLightHarsh;
2760 if ( rrProp.Value >>= bExtrusionSecondLightHarsh )
2761 {
2762 nFillHarshFlags |= 0x10000;
2763 if ( bExtrusionSecondLightHarsh )
2764 nFillHarshFlags |= 1;
2765 else
2766 nFillHarshFlags &=~1;
2767 }
2768 }
2769 else if ( rrProp.Name == "FirstLightLevel" )
2770 {
2771 double fExtrusionFirstLightLevel = 0;
2772 if ( rrProp.Value >>= fExtrusionFirstLightLevel )
2773 AddOpt( DFF_Prop_c3DKeyIntensity, static_cast<sal_Int32>( fExtrusionFirstLightLevel * 655.36 ) );
2774 }
2775 else if ( rrProp.Name == "SecondLightLevel" )
2776 {
2777 double fExtrusionSecondLightLevel = 0;
2778 if ( rrProp.Value >>= fExtrusionSecondLightLevel )
2779 AddOpt( DFF_Prop_c3DFillIntensity, static_cast<sal_Int32>( fExtrusionSecondLightLevel * 655.36 ) );
2780 }
2781 else if ( rrProp.Name == "FirstLightDirection" )
2782 {
2783 drawing::Direction3D aExtrusionFirstLightDirection;
2784 if ( rrProp.Value >>= aExtrusionFirstLightDirection )
2785 {
2786 AddOpt( DFF_Prop_c3DKeyX, static_cast<sal_Int32>(aExtrusionFirstLightDirection.DirectionX) );
2787 AddOpt( DFF_Prop_c3DKeyY, static_cast<sal_Int32>(aExtrusionFirstLightDirection.DirectionY) );
2788 AddOpt( DFF_Prop_c3DKeyZ, static_cast<sal_Int32>(aExtrusionFirstLightDirection.DirectionZ) );
2789 }
2790 }
2791 else if ( rrProp.Name == "SecondLightDirection" )
2792 {
2793 drawing::Direction3D aExtrusionSecondLightPosition;
2794 if ( rrProp.Value >>= aExtrusionSecondLightPosition )
2795 {
2796 AddOpt( DFF_Prop_c3DFillX, static_cast<sal_Int32>(aExtrusionSecondLightPosition.DirectionX) );
2797 AddOpt( DFF_Prop_c3DFillY, static_cast<sal_Int32>(aExtrusionSecondLightPosition.DirectionY) );
2798 AddOpt( DFF_Prop_c3DFillZ, static_cast<sal_Int32>(aExtrusionSecondLightPosition.DirectionZ) );
2799 }
2800 }
2801 else if ( rrProp.Name == "Metal" )
2802 {
2803 bool bExtrusionMetal;
2804 if ( rrProp.Value >>= bExtrusionMetal )
2805 {
2806 nLightFaceFlags |= 0x40000;
2807 if ( bExtrusionMetal )
2808 nLightFaceFlags |= 4;
2809 else
2810 nLightFaceFlags &=~4;
2811 }
2812 }
2813 else if ( rrProp.Name == "ShadeMode" )
2814 {
2815 drawing::ShadeMode eExtrusionShadeMode;
2816 if ( rrProp.Value >>= eExtrusionShadeMode )
2817 {
2818 sal_uInt32 nRenderMode;
2819 switch( eExtrusionShadeMode )
2820 {
2821 default:
2822 case drawing::ShadeMode_FLAT :
2823 case drawing::ShadeMode_PHONG :
2824 case drawing::ShadeMode_SMOOTH :
2825 nRenderMode = mso_FullRender;
2826 break;
2827 case drawing::ShadeMode_DRAFT :
2828 {
2829 nRenderMode = mso_Wireframe;
2830 }
2831 break;
2832 }
2833 AddOpt( DFF_Prop_c3DRenderMode, nRenderMode );
2834 }
2835 }
2836 else if ( rrProp.Name == "RotateAngle" )
2837 {
2838 double fExtrusionAngleX = 0;
2839 double fExtrusionAngleY = 0;
2840 drawing::EnhancedCustomShapeParameterPair aRotateAnglePair;
2841 if ( ( rrProp.Value >>= aRotateAnglePair ) && ( aRotateAnglePair.First.Value >>= fExtrusionAngleX ) && ( aRotateAnglePair.Second.Value >>= fExtrusionAngleY ) )
2842 {
2843 fExtrusionAngleX *= 65536;
2844 fExtrusionAngleY *= 65536;
2845 AddOpt( DFF_Prop_c3DXRotationAngle, static_cast<sal_Int32>(fExtrusionAngleX) );
2846 AddOpt( DFF_Prop_c3DYRotationAngle, static_cast<sal_Int32>(fExtrusionAngleY) );
2847 }
2848 }
2849 else if ( rrProp.Name == "RotationCenter" )
2850 {
2851 drawing::Direction3D aExtrusionRotationCenter;
2852 if ( rrProp.Value >>= aExtrusionRotationCenter )
2853 {
2854 // tdf#145904 X- and Y-component is fraction, Z-component in EMU
2855 AddOpt( DFF_Prop_c3DRotationCenterX, static_cast<sal_Int32>( aExtrusionRotationCenter.DirectionX * 65536.0 ) );
2856 AddOpt( DFF_Prop_c3DRotationCenterY, static_cast<sal_Int32>( aExtrusionRotationCenter.DirectionY * 65536.0 ) );
2857 AddOpt( DFF_Prop_c3DRotationCenterZ, static_cast<sal_Int32>( aExtrusionRotationCenter.DirectionZ * 360.0 ) );
2858 nFillHarshFlags &=~8; // don't use AutoRotationCenter;
2859 }
2860 }
2861 else if ( rrProp.Name == "Shininess" )
2862 {
2863 double fExtrusionShininess = 0;
2864 if ( rrProp.Value >>= fExtrusionShininess )
2865 {
2866 // ODF to MS Office conversion invers to msdffimp.cxx
2867 fExtrusionShininess = basegfx::fround(fExtrusionShininess / 10.0);
2868 AddOpt( DFF_Prop_c3DShininess, static_cast<sal_Int32>(fExtrusionShininess) );
2869 }
2870 }
2871 else if ( rrProp.Name == "Skew" )
2872 {
2873 double fSkewAmount = 0;
2874 double fSkewAngle = 0;
2875 drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
2876 if ( ( rrProp.Value >>= aSkewParaPair ) && ( aSkewParaPair.First.Value >>= fSkewAmount ) && ( aSkewParaPair.Second.Value >>= fSkewAngle ) )
2877 {
2878 AddOpt( DFF_Prop_c3DSkewAmount, static_cast<sal_Int32>(fSkewAmount) );
2879 AddOpt( DFF_Prop_c3DSkewAngle, static_cast<sal_Int32>( fSkewAngle * 65536 ) );
2880 }
2881 }
2882 else if ( rrProp.Name == "Specularity" )
2883 {
2884 double fExtrusionSpecularity = 0;
2885 if ( rrProp.Value >>= fExtrusionSpecularity )
2886 AddOpt( DFF_Prop_c3DSpecularAmt, static_cast<sal_Int32>( fExtrusionSpecularity * 655.36 ) );
2887 }
2888 else if ( rrProp.Name == "ProjectionMode" )
2889 {
2890 drawing::ProjectionMode eExtrusionProjectionMode;
2891 if ( rrProp.Value >>= eExtrusionProjectionMode )
2892 {
2893 nFillHarshFlags |= 0x40000;
2894 if ( eExtrusionProjectionMode == drawing::ProjectionMode_PARALLEL )
2895 nFillHarshFlags |= 4;
2896 else
2897 nFillHarshFlags &=~4;
2898 }
2899 }
2900 else if ( rrProp.Name == "ViewPoint" )
2901 {
2902 drawing::Position3D aExtrusionViewPoint;
2903 if ( rrProp.Value >>= aExtrusionViewPoint )
2904 {
2905 aExtrusionViewPoint.PositionX *= 360.0;
2906 aExtrusionViewPoint.PositionY *= 360.0;
2907 aExtrusionViewPoint.PositionZ *= 360.0;
2908 AddOpt( DFF_Prop_c3DXViewpoint, static_cast<sal_Int32>(aExtrusionViewPoint.PositionX) );
2909 AddOpt( DFF_Prop_c3DYViewpoint, static_cast<sal_Int32>(aExtrusionViewPoint.PositionY) );
2910 AddOpt( DFF_Prop_c3DZViewpoint, static_cast<sal_Int32>(aExtrusionViewPoint.PositionZ) );
2911 }
2912 }
2913 else if ( rrProp.Name == "Origin" )
2914 {
2915 double fExtrusionOriginX = 0;
2916 double fExtrusionOriginY = 0;
2917 drawing::EnhancedCustomShapeParameterPair aOriginPair;
2918 if ( ( rrProp.Value >>= aOriginPair ) && ( aOriginPair.First.Value >>= fExtrusionOriginX ) && ( aOriginPair.Second.Value >>= fExtrusionOriginY ) )
2919 {
2920 AddOpt( DFF_Prop_c3DOriginX, static_cast<sal_Int32>( fExtrusionOriginX * 65536 ) );
2921 AddOpt( DFF_Prop_c3DOriginY, static_cast<sal_Int32>( fExtrusionOriginY * 65536 ) );
2922 }
2923 }
2924 else if ( rrProp.Name == "Color" )
2925 {
2926 bool bExtrusionColor;
2927 if ( rrProp.Value >>= bExtrusionColor )
2928 {
2929 nLightFaceFlags |= 0x20000;
2930 if ( bExtrusionColor )
2931 {
2932 nLightFaceFlags |= 2;
2933 uno::Any aFillColor2;
2934 if ( EscherPropertyValueHelper::GetPropertyValue( aFillColor2, aXPropSet, "FillColor2", true ) )
2935 {
2936 sal_uInt32 nFillColor = ImplGetColor( *o3tl::doAccess<sal_uInt32>(aFillColor2) );
2937 AddOpt( DFF_Prop_c3DExtrusionColor, nFillColor );
2938 }
2939 }
2940 else
2941 nLightFaceFlags &=~2;
2942 }
2943 }
2944 }
2945 if ( nLightFaceFlags != nLightFaceFlagsOrg )
2946 AddOpt( DFF_Prop_fc3DLightFace, nLightFaceFlags );
2947 if ( nFillHarshFlags != nFillHarshFlagsOrg )
2948 AddOpt( DFF_Prop_fc3DFillHarsh, nFillHarshFlags );
2949 }
2950 }
2951 else if ( rProp.Name == sEquations )
2952 {
2953 if ( !bIsDefaultObject )
2954 {
2955 sal_uInt16 nElements = static_cast<sal_uInt16>(aEquations.size());
2956 if ( nElements )
2957 {
2958 sal_uInt16 nElementSize = 8;
2959 sal_uInt32 nStreamSize = nElementSize * nElements + 6;
2960 SvMemoryStream aMemStrm( nStreamSize );
2961 aMemStrm.WriteUInt16( nElements )
2963 .WriteUInt16( nElementSize );
2964
2965 for (auto const& equation : aEquations)
2966 {
2967 aMemStrm.WriteUInt16( equation.nOperation )
2968 .WriteInt16(
2969 std::clamp(
2970 equation.nPara[ 0 ], sal_Int32(SAL_MIN_INT16),
2971 sal_Int32(SAL_MAX_INT16)) )
2972 .WriteInt16(
2973 std::clamp(
2974 equation.nPara[ 1 ], sal_Int32(SAL_MIN_INT16),
2975 sal_Int32(SAL_MAX_INT16)) )
2976 .WriteInt16(
2977 std::clamp(
2978 equation.nPara[ 2 ], sal_Int32(SAL_MIN_INT16),
2979 sal_Int32(SAL_MAX_INT16)) );
2980 }
2981
2982 AddOpt(DFF_Prop_pFormulas, true, 6, aMemStrm);
2983 }
2984 else
2985 {
2986 AddOpt(DFF_Prop_pFormulas, 0, true);
2987 }
2988 }
2989 }
2990 else if ( rProp.Name == sPath )
2991 {
2992 uno::Sequence< beans::PropertyValue > aPathPropSeq;
2993 if ( rProp.Value >>= aPathPropSeq )
2994 {
2995 sal_uInt32 nPathFlags, nPathFlagsOrg;
2996 nPathFlagsOrg = nPathFlags = 0x39;
2997 if ( GetOpt( DFF_Prop_fFillOK, nPathFlags ) )
2998 nPathFlagsOrg = nPathFlags;
2999
3000 sal_Int32 r, nrCount = aPathPropSeq.getLength();
3001 for ( r = 0; r < nrCount; r++ )
3002 {
3003 const beans::PropertyValue& rrProp = aPathPropSeq[ r ];
3004
3005 if ( rrProp.Name == "ExtrusionAllowed" )
3006 {
3007 bool bExtrusionAllowed;
3008 if ( rrProp.Value >>= bExtrusionAllowed )
3009 {
3010 nPathFlags |= 0x100000;
3011 if ( bExtrusionAllowed )
3012 nPathFlags |= 16;
3013 else
3014 nPathFlags &=~16;
3015 }
3016 }
3017 else if ( rrProp.Name == "ConcentricGradientFillAllowed" )
3018 {
3019 bool bConcentricGradientFillAllowed;
3020 if ( rrProp.Value >>= bConcentricGradientFillAllowed )
3021 {
3022 nPathFlags |= 0x20000;
3023 if ( bConcentricGradientFillAllowed )
3024 nPathFlags |= 2;
3025 else
3026 nPathFlags &=~2;
3027 }
3028 }
3029 else if ( rrProp.Name == "TextPathAllowed" )
3030 {
3031 bool bTextPathAllowed;
3032 if ( rrProp.Value >>= bTextPathAllowed )
3033 {
3034 nPathFlags |= 0x40000;
3035 if ( bTextPathAllowed )
3036 nPathFlags |= 4;
3037 else
3038 nPathFlags &=~4;
3039 }
3040 }
3041 else if ( rrProp.Name == "Coordinates" )
3042 {
3043 if ( !bIsDefaultObject )
3044 {
3045 aPathCoordinatesProp = rrProp.Value;
3046 bPathCoordinatesProp = true;
3047 }
3048 }
3049 else if ( rrProp.Name == "GluePoints" )
3050 {
3051 if ( !bIsDefaultObject )
3052 {
3053 uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aGluePoints;
3054 if ( rrProp.Value >>= aGluePoints )
3055 {
3056 // creating the vertices
3057 sal_uInt16 nElements = static_cast<sal_uInt16>(aGluePoints.getLength());
3058 if ( nElements )
3059 {
3060 sal_uInt16 j, nElementSize = 8;
3061 sal_uInt32 nStreamSize = nElementSize * nElements + 6;
3062 SvMemoryStream aMemStrm( nStreamSize );
3063 aMemStrm.WriteUInt16( nElements )
3065 .WriteUInt16( nElementSize );
3066 for( j = 0; j < nElements; j++ )
3067 {
3068 sal_Int32 X = GetValueForEnhancedCustomShapeParameter( aGluePoints[ j ].First, aEquationOrder );
3069 sal_Int32 Y = GetValueForEnhancedCustomShapeParameter( aGluePoints[ j ].Second, aEquationOrder );
3070 aMemStrm.WriteInt32( X )
3071 .WriteInt32( Y );
3072 }
3073
3074 AddOpt(DFF_Prop_connectorPoints, true, 6, aMemStrm); // -6
3075 }
3076 else
3077 {
3079 }
3080 }
3081 }
3082 }
3083 else if ( rrProp.Name == "GluePointType" )
3084 {
3085 sal_Int16 nGluePointType = sal_Int16();
3086 if ( rrProp.Value >>= nGluePointType )
3087 AddOpt( DFF_Prop_connectorType, static_cast<sal_uInt16>(nGluePointType) );
3088 }
3089 else if ( rrProp.Name == "Segments" )
3090 {
3091 if ( !bIsDefaultObject )
3092 {
3093 uno::Sequence<drawing::EnhancedCustomShapeSegment> aSegments;
3094 if ( rrProp.Value >>= aSegments )
3095 {
3096 // creating seginfo
3097 if ( aSegments.hasElements() )
3098 {
3099 sal_uInt16 j, nElements = static_cast<sal_uInt16>(aSegments.getLength());
3100 sal_uInt16 nElementSize = 2;
3101 sal_uInt32 nStreamSize = nElementSize * nElements + 6;
3102 SvMemoryStream aMemStrm( nStreamSize );
3103 aMemStrm.WriteUInt16( nElements )
3105 .WriteUInt16( nElementSize );
3106 for ( j = 0; j < nElements; j++ )
3107 {
3108 // The segment type is stored in the upper 3 bits
3109 // and segment count is stored in the lower 13
3110 // bits.
3111 //
3112 // If the segment type is msopathEscape, the lower 13 bits
3113 // are divided in a 5 bit escape code and 8 bit
3114 // vertex count (not segment count!)
3115 sal_uInt16 nVal = static_cast<sal_uInt16>(aSegments[ j ].Count);
3116 switch( aSegments[ j ].Command )
3117 {
3119 case drawing::EnhancedCustomShapeSegmentCommand::LINETO :
3120 break;
3121 case drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
3122 nVal = (msopathMoveTo << 13);
3123 break;
3124 case drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
3125 {
3126 nVal |= (msopathCurveTo << 13);
3127 }
3128 break;
3129 case drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
3130 {
3131 nVal = 1;
3132 nVal |= (msopathClose << 13);
3133 }
3134 break;
3135 case drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
3136 {
3137 nVal = (msopathEnd << 13);
3138 }
3139 break;
3140 case drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
3141 {
3142 nVal = (msopathEscape << 13) | (10 << 8);
3143 }
3144 break;
3145 case drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
3146 {
3147 nVal = (msopathEscape << 13) | (11 << 8);
3148 }
3149 break;
3150 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
3151 {
3152 nVal *= 3;
3153 nVal |= (msopathEscape << 13) | (1 << 8);
3154 }
3155 break;
3156 case drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
3157 {
3158 nVal *= 3;
3159 nVal |= (msopathEscape << 13) | (2 << 8);
3160 }
3161 break;
3162 case drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
3163 {
3164 nVal <<= 2;
3165 nVal |= (msopathEscape << 13) | (3 << 8);
3166 }
3167 break;
3168 case drawing::EnhancedCustomShapeSegmentCommand::ARC :
3169 {
3170 nVal <<= 2;
3171 nVal |= (msopathEscape << 13) | (4 << 8);
3172 }
3173 break;
3174 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
3175 {
3176 nVal <<= 2;
3177 nVal |= (msopathEscape << 13) | (5 << 8);
3178 }
3179 break;
3180 case drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
3181 {
3182 nVal <<= 2;
3183 nVal |= (msopathEscape << 13) | (6 << 8);
3184 }
3185 break;
3186 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
3187 {
3188 nVal |= (msopathEscape << 13) | (7 << 8);
3189 }
3190 break;
3191 case drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
3192 {
3193 nVal |= (msopathEscape << 13) | (8 << 8);
3194 }
3195 break;
3196 }
3197 aMemStrm.WriteUInt16( nVal );
3198 }
3199
3200 AddOpt(DFF_Prop_pSegmentInfo, false, 6, aMemStrm);
3201 }
3202 else
3203 {
3204 AddOpt(DFF_Prop_pSegmentInfo, 0, true);
3205 }
3206 }
3207 }
3208 }
3209 else if ( rrProp.Name == "StretchX" )
3210 {
3211 if ( !bIsDefaultObject )
3212 {
3213 sal_Int32 nStretchX = 0;
3214 if ( rrProp.Value >>= nStretchX )
3215 AddOpt( DFF_Prop_stretchPointX, nStretchX );
3216 }
3217 }
3218 else if ( rrProp.Name == "StretchY" )
3219 {
3220 if ( !bIsDefaultObject )
3221 {
3222 sal_Int32 nStretchY = 0;
3223 if ( rrProp.Value >>= nStretchY )
3224 AddOpt( DFF_Prop_stretchPointY, nStretchY );
3225 }
3226 }
3227 else if ( rrProp.Name == "TextFrames" )
3228 {
3229 if ( !bIsDefaultObject )
3230 {
3231 uno::Sequence<drawing::EnhancedCustomShapeTextFrame> aPathTextFrames;
3232 if ( rrProp.Value >>= aPathTextFrames )
3233 {
3234 if ( aPathTextFrames.hasElements() )
3235 {
3236 sal_uInt16 j, nElements = static_cast<sal_uInt16>(aPathTextFrames.getLength());
3237 sal_uInt16 nElementSize = 16;
3238 sal_uInt32 nStreamSize = nElementSize * nElements + 6;
3239 SvMemoryStream aMemStrm( nStreamSize );
3240 aMemStrm.WriteUInt16( nElements )
3242 .WriteUInt16( nElementSize );
3243 for ( j = 0; j < nElements; j++ )
3244 {
3245 sal_Int32 nLeft = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].TopLeft.First, aEquationOrder );
3246 sal_Int32 nTop = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].TopLeft.Second, aEquationOrder );
3247 sal_Int32 nRight = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].BottomRight.First, aEquationOrder );
3248 sal_Int32 nBottom = GetValueForEnhancedCustomShapeParameter( aPathTextFrames[ j ].BottomRight.Second, aEquationOrder );
3249
3250 aMemStrm.WriteInt32( nLeft )
3251 .WriteInt32( nTop )
3252 .WriteInt32( nRight )
3253 .WriteInt32( nBottom );
3254 }
3255
3256 AddOpt(DFF_Prop_textRectangles, true, 6, aMemStrm);
3257 }
3258 else
3259 {
3261 }
3262 }
3263 }
3264 }
3265 }
3266 if ( nPathFlags != nPathFlagsOrg )
3267 AddOpt( DFF_Prop_fFillOK, nPathFlags );
3268 }
3269 }
3270 else if ( rProp.Name == sTextPath )
3271 {
3272 uno::Sequence< beans::PropertyValue > aTextPathPropSeq;
3273 if ( rProp.Value >>= aTextPathPropSeq )
3274 {
3275 sal_uInt32 nTextPathFlagsOrg, nTextPathFlags;
3276 nTextPathFlagsOrg = nTextPathFlags = 0xffff1000; // default
3277 if ( GetOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags ) )
3278 nTextPathFlagsOrg = nTextPathFlags;
3279
3280 sal_Int32 r, nrCount = aTextPathPropSeq.getLength();
3281 for ( r = 0; r < nrCount; r++ )
3282 {
3283 const beans::PropertyValue& rrProp = aTextPathPropSeq[ r ];
3284
3285 if ( rrProp.Name == sTextPath )
3286 {
3287 bool bTextPathOn;
3288 if ( rrProp.Value >>= bTextPathOn )
3289 {
3290 nTextPathFlags |= 0x40000000;
3291 if ( bTextPathOn )
3292 {
3293 nTextPathFlags |= 0x4000;
3294
3295 sal_uInt32 nPathFlags = 0x39;
3296 GetOpt( DFF_Prop_fFillOK, nPathFlags ); // SJ: can be removed if we are supporting the TextPathAllowed property in XML
3297 nPathFlags |= 0x40004;
3298 AddOpt( DFF_Prop_fFillOK, nPathFlags );
3299 }
3300 else
3301 nTextPathFlags &=~0x4000;
3302 }
3303 }
3304 else if ( rrProp.Name == "TextPathMode" )
3305 {
3306 drawing::EnhancedCustomShapeTextPathMode eTextPathMode;
3307 if ( rrProp.Value >>= eTextPathMode )
3308 {
3309 nTextPathFlags |= 0x05000000;
3310 nTextPathFlags &=~0x500; // TextPathMode_NORMAL
3311 if ( eTextPathMode == drawing::EnhancedCustomShapeTextPathMode_PATH )
3312 nTextPathFlags |= 0x100;
3313 else if ( eTextPathMode == drawing::EnhancedCustomShapeTextPathMode_SHAPE )
3314 nTextPathFlags |= 0x500;
3315 }
3316 }
3317 else if ( rrProp.Name == "ScaleX" )
3318 {
3319 bool bTextPathScaleX;
3320 if ( rrProp.Value >>= bTextPathScaleX )
3321 {
3322 nTextPathFlags |= 0x00400000;
3323 if ( bTextPathScaleX )
3324 nTextPathFlags |= 0x40;
3325 else
3326 nTextPathFlags &=~0x40;
3327 }
3328 }
3329 else if ( rrProp.Name == "SameLetterHeights" )
3330 {
3331 bool bSameLetterHeights;
3332 if ( rrProp.Value >>= bSameLetterHeights )
3333 {
3334 nTextPathFlags |= 0x00800000;
3335 if ( bSameLetterHeights )
3336 nTextPathFlags |= 0x80;
3337 else
3338 nTextPathFlags &=~0x80;
3339 }
3340 }
3341 }
3342 if ( nTextPathFlags & 0x4000 ) // Is FontWork ?
3343 {
3344 // FontWork Text
3345 OUString aText;
3346 uno::Reference< text::XSimpleText > xText( rXShape, uno::UNO_QUERY );
3347 if ( xText.is() )
3348 aText = xText->getString();
3349 if ( aText.isEmpty() )
3350 aText = "your text"; // TODO: moving into a resource
3351 AddOpt( DFF_Prop_gtextUNICODE, aText );
3352
3353 // FontWork Font
3354 OUString aFontName;
3355 uno::Any aAny = aXPropSet->getPropertyValue( "CharFontName" );
3356 aAny >>= aFontName;
3357 if ( aFontName.isEmpty() )
3358 aFontName = "Arial Black";
3359 AddOpt( DFF_Prop_gtextFont, aFontName );
3360
3361 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharScaleWidth", true ) )
3362 {
3363 sal_Int16 nCharScaleWidth = 100;
3364 if ( aAny >>= nCharScaleWidth )
3365 {
3366 if ( nCharScaleWidth != 100 )
3367 {
3368 sal_Int32 nVal = nCharScaleWidth * 655;
3370 }
3371 }
3372 }
3373 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharHeight", true ) )
3374 {
3375 float fCharHeight = 0.0;
3376 if ( aAny >>= fCharHeight )
3377 {
3378 sal_Int32 nTextSize = static_cast< sal_Int32 > ( fCharHeight * 65536 );
3379 AddOpt(ESCHER_Prop_gtextSize, nTextSize);
3380 }
3381 }
3382 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharKerning", true ) )
3383 {
3384 sal_Int16 nCharKerning = sal_Int16();
3385 if ( aAny >>= nCharKerning )
3386 {
3387 nTextPathFlags |= 0x10000000;
3388 if ( nCharKerning )
3389 nTextPathFlags |= 0x1000;
3390 else
3391 nTextPathFlags &=~0x1000;
3392 }
3393 }
3394 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharPosture", true ) )
3395 {
3396 awt::FontSlant eFontSlant;
3397 if ( aAny >>= eFontSlant )
3398 {
3399 nTextPathFlags |= 0x100010;
3400 if ( eFontSlant != awt::FontSlant_NONE )
3401 nTextPathFlags |= 0x10;
3402 else
3403 nTextPathFlags &=~0x10;
3404 }
3405 }
3406 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "CharWeight", true ) )
3407 {
3408 float fFontWidth = 0;
3409 if ( aAny >>= fFontWidth )
3410 {
3411 nTextPathFlags |= 0x200020;
3412 if ( fFontWidth > awt::FontWeight::NORMAL )
3413 nTextPathFlags |= 0x20;
3414 else
3415 nTextPathFlags &=~0x20;
3416 }
3417 }
3418 // export gTextAlign attr
3419 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aXPropSet, "TextHorizontalAdjust", true ) )
3420 {
3422 drawing::TextHorizontalAdjust eHA( drawing::TextHorizontalAdjust_LEFT );
3423 aAny >>= eHA;
3424 switch( eHA )
3425 {
3426 case drawing::TextHorizontalAdjust_LEFT :
3427 gTextAlign = mso_alignTextLeft;
3428 break;
3429 case drawing::TextHorizontalAdjust_CENTER:
3430 gTextAlign = mso_alignTextCenter;
3431 break;
3432 case drawing::TextHorizontalAdjust_RIGHT:
3433 gTextAlign = mso_alignTextRight;
3434 break;
3435 case drawing::TextHorizontalAdjust_BLOCK:
3436 {
3437 drawing::TextFitToSizeType const eFTS(
3438 rSdrObjCustomShape.GetMergedItem( SDRATTR_TEXT_FITTOSIZE ).GetValue() );
3439 if (eFTS == drawing::TextFitToSizeType_ALLLINES ||
3440 eFTS == drawing::TextFitToSizeType_PROPORTIONAL)
3441 {
3442 gTextAlign = mso_alignTextStretch;
3443 }
3444 else
3445 {
3446 gTextAlign = mso_alignTextWordJust;
3447 }
3448 break;
3449 }
3450 default:
3451 break;
3452 }
3453 AddOpt(DFF_Prop_gtextAlign,gTextAlign);
3454 }
3455 }
3456 if((nTextPathFlags & 0x4000) != 0) // Is Font work
3457 {
3458 OutlinerParaObject* pOutlinerParaObject(rSdrObjCustomShape.GetOutlinerParaObject());
3459 if ( pOutlinerParaObject && pOutlinerParaObject->IsEffectivelyVertical() )
3460 nTextPathFlags |= 0x2000;
3461 }
3462
3463 // Use gtextFStretch for Watermark like MSO does
3464 nTextPathFlags |= use_gtextFBestFit | gtextFBestFit
3467
3468 if ( nTextPathFlags != nTextPathFlagsOrg )
3469 AddOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags );
3470 }
3471 }
3472 else if ( rProp.Name == sHandles )
3473 {
3474 if ( !bIsDefaultObject )
3475 {
3476 bPredefinedHandlesUsed = false;
3477 if ( rProp.Value >>= aHandlesPropSeq )
3478 {
3479 sal_uInt16 nElements = static_cast<sal_uInt16>(aHandlesPropSeq.getLength());
3480 if ( nElements )
3481 {
3482 sal_uInt16 k, nElementSize = 36;
3483 sal_uInt32 nStreamSize = nElementSize * nElements + 6;
3484 SvMemoryStream aMemStrm( nStreamSize );
3485 aMemStrm.WriteUInt16( nElements )
3487 .WriteUInt16( nElementSize );
3488
3489 for ( k = 0; k < nElements; k++ )
3490 {
3491 sal_uInt32 nFlags = 0;
3492 sal_Int32 nXPosition = 0;
3493 sal_Int32 nYPosition = 0;
3494 sal_Int32 nXMap = 0;
3495 sal_Int32 nYMap = 0;
3496 sal_Int32 nXRangeMin = 0x80000000;
3497 sal_Int32 nXRangeMax = 0x7fffffff;
3498 sal_Int32 nYRangeMin = 0x80000000;
3499 sal_Int32 nYRangeMax = 0x7fffffff;
3500
3501 const uno::Sequence< beans::PropertyValue >& rPropSeq = aHandlesPropSeq[ k ];
3502 for ( const beans::PropertyValue& rPropVal: rPropSeq )
3503 {
3504 if ( rPropVal.Name == "Position" )
3505 {
3506 drawing::EnhancedCustomShapeParameterPair aPosition;
3507 if ( rPropVal.Value >>= aPosition )
3508 {
3509 GetValueForEnhancedCustomShapeHandleParameter( nXPosition, aPosition.First );
3510 GetValueForEnhancedCustomShapeHandleParameter( nYPosition, aPosition.Second );
3511 }
3512 }
3513 else if ( rPropVal.Name == "MirroredX" )
3514 {
3515 bool bMirroredX;
3516 if ( rPropVal.Value >>= bMirroredX )
3517 {
3518 if ( bMirroredX )
3519 nFlags |= 1;
3520 }
3521 }
3522 else if ( rPropVal.Name == "MirroredY" )
3523 {
3524 bool bMirroredY;
3525 if ( rPropVal.Value >>= bMirroredY )
3526 {
3527 if ( bMirroredY )
3528 nFlags |= 2;
3529 }
3530 }
3531 else if ( rPropVal.Name == "Switched" )
3532 {
3533 bool bSwitched;
3534 if ( rPropVal.Value >>= bSwitched )
3535 {
3536 if ( bSwitched )
3537 nFlags |= 4;
3538 }
3539 }
3540 else if ( rPropVal.Name == "Polar" )
3541 {
3542 drawing::EnhancedCustomShapeParameterPair aPolar;
3543 if ( rPropVal.Value >>= aPolar )
3544 {
3545 if ( GetValueForEnhancedCustomShapeHandleParameter( nXMap, aPolar.First ) )
3546 nFlags |= 0x800;
3547 if ( GetValueForEnhancedCustomShapeHandleParameter( nYMap, aPolar.Second ) )
3548 nFlags |= 0x1000;
3549 nFlags |= 8;
3550 }
3551 }
3552 else if ( rPropVal.Name == "RadiusRangeMinimum" )
3553 {
3554 nYRangeMin = sal_Int32(0xff4c0000); // the range of angles seems to be a not
3555 nYRangeMax = sal_Int32(0x00b40000); // used feature, so we are defaulting this
3556
3557 drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
3558 if ( rPropVal.Value >>= aRadiusRangeMinimum )
3559 {
3560 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin, aRadiusRangeMinimum ) )
3561 nFlags |= 0x80;
3562 nFlags |= 0x2000;
3563 }
3564 }
3565 else if ( rPropVal.Name == "RadiusRangeMaximum" )
3566 {
3567 nYRangeMin = sal_Int32(0xff4c0000); // the range of angles seems to be a not
3568 nYRangeMax = sal_Int32(0x00b40000); // used feature, so we are defaulting this
3569
3570 drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
3571 if ( rPropVal.Value >>= aRadiusRangeMaximum )
3572 {
3573 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax, aRadiusRangeMaximum ) )
3574 nFlags |= 0x100;
3575 nFlags |= 0x2000;
3576 }
3577 }
3578 else if ( rPropVal.Name == "RangeXMinimum" )
3579 {
3580 drawing::EnhancedCustomShapeParameter aXRangeMinimum;
3581 if ( rPropVal.Value >>= aXRangeMinimum )
3582 {
3583 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMin, aXRangeMinimum ) )
3584 nFlags |= 0x80;
3585 nFlags |= 0x20;
3586 }
3587 }
3588 else if ( rPropVal.Name == "RangeXMaximum" )
3589 {
3590 drawing::EnhancedCustomShapeParameter aXRangeMaximum;
3591 if ( rPropVal.Value >>= aXRangeMaximum )
3592 {
3593 if ( GetValueForEnhancedCustomShapeHandleParameter( nXRangeMax, aXRangeMaximum ) )
3594 nFlags |= 0x100;
3595 nFlags |= 0x20;
3596 }
3597 }
3598 else if ( rPropVal.Name == "RangeYMinimum" )
3599 {
3600 drawing::EnhancedCustomShapeParameter aYRangeMinimum;
3601 if ( rPropVal.Value >>= aYRangeMinimum )
3602 {
3603 if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMin, aYRangeMinimum ) )
3604 nFlags |= 0x200;
3605 nFlags |= 0x20;
3606 }
3607 }
3608 else if ( rPropVal.Name == "RangeYMaximum" )
3609 {
3610 drawing::EnhancedCustomShapeParameter aYRangeMaximum;
3611 if ( rPropVal.Value >>= aYRangeMaximum )
3612 {
3613 if ( GetValueForEnhancedCustomShapeHandleParameter( nYRangeMax, aYRangeMaximum ) )
3614 nFlags |= 0x400;
3615 nFlags |= 0x20;
3616 }
3617 }
3618 }
3619 aMemStrm.WriteUInt32( nFlags )
3620 .WriteInt32( nXPosition )
3621 .WriteInt32( nYPosition )
3622 .WriteInt32( nXMap )
3623 .WriteInt32( nYMap )
3624 .WriteInt32( nXRangeMin )
3625 .WriteInt32( nXRangeMax )
3626 .WriteInt32( nYRangeMin )
3627 .WriteInt32( nYRangeMax );
3628
3629 if ( nFlags & 8 )
3630 nAdjustmentsWhichNeedsToBeConverted |= ( 1 << ( nYPosition - 0x100 ) );
3631 }
3632
3633 AddOpt(DFF_Prop_Handles, true, 6, aMemStrm);
3634 }
3635 else
3636 {
3637 AddOpt(DFF_Prop_Handles, 0, true);
3638 }
3639 }
3640 }
3641 }
3642 else if ( rProp.Name == sAdjustmentValues )
3643 {
3644 // it is required, that the information which handle is polar has already be read,
3645 // so we are able to change the polar value to a fixed float
3646 aAdjustmentValuesProp = rProp.Value;
3647 bAdjustmentValuesProp = true;
3648 }
3649 }
3650 if ( bAdjustmentValuesProp )
3651 {
3652 uno::Sequence<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentSeq;
3653 if ( aAdjustmentValuesProp >>= aAdjustmentSeq )
3654 {
3655 if ( bPredefinedHandlesUsed )
3656 LookForPolarHandles( eShapeType, nAdjustmentsWhichNeedsToBeConverted );
3657
3658 sal_Int32 k, nValue = 0, nAdjustmentValues = aAdjustmentSeq.getLength();
3659 for ( k = 0; k < nAdjustmentValues; k++ )
3660 if( GetAdjustmentValue( aAdjustmentSeq[ k ], k, nAdjustmentsWhichNeedsToBeConverted, nValue ) )
3661 AddOpt( static_cast<sal_uInt16>( DFF_Prop_adjustValue + k ), static_cast<sal_uInt32>(nValue) );
3662 }
3663 }
3664 if( !bPathCoordinatesProp )
3665 return;
3666
3667 uno::Sequence<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
3668 if ( !(aPathCoordinatesProp >>= aCoordinates) )
3669 return;
3670
3671 // creating the vertices
3672 if (aCoordinates.hasElements())
3673 {
3674 sal_uInt16 j, nElements = static_cast<sal_uInt16>(aCoordinates.getLength());
3675 sal_uInt16 nElementSize = 8;
3676 sal_uInt32 nStreamSize = nElementSize * nElements + 6;
3677 SvMemoryStream aMemStrm( nStreamSize );
3678 aMemStrm.WriteUInt16( nElements )
3680 .WriteUInt16( nElementSize );
3681 for( j = 0; j < nElements; j++ )
3682 {
3683 sal_Int32 X = GetValueForEnhancedCustomShapeParameter( aCoordinates[ j ].First, aEquationOrder, true );
3684 sal_Int32 Y = GetValueForEnhancedCustomShapeParameter( aCoordinates[ j ].Second, aEquationOrder, true );
3685 aMemStrm.WriteInt32( X )
3686 .WriteInt32( Y );
3687 }
3688
3689 AddOpt(DFF_Prop_pVertices, true, 6, aMemStrm); // -6
3690 }
3691 else
3692 {
3693 AddOpt(DFF_Prop_pVertices, 0, true);
3694 }
3695}
3696
3697MSO_SPT EscherPropertyContainer::GetCustomShapeType( const uno::Reference< drawing::XShape > & rXShape, ShapeFlag& nMirrorFlags, OUString& rShapeType, bool bOOXML )
3698{
3699 MSO_SPT eShapeType = mso_sptNil;
3700 nMirrorFlags = ShapeFlag::NONE;
3701 uno::Reference< beans::XPropertySet > aXPropSet( rXShape, uno::UNO_QUERY );
3702 if ( aXPropSet.is() )
3703 {
3704 try
3705 {
3706 uno::Any aGeoPropSet = aXPropSet->getPropertyValue( "CustomShapeGeometry" );
3707 uno::Sequence< beans::PropertyValue > aGeoPropSeq;
3708 if ( aGeoPropSet >>= aGeoPropSeq )
3709 {
3710 sal_Int32 i, nCount = aGeoPropSeq.getLength();
3711 for ( i = 0; i < nCount; i++ )
3712 {
3713 const beans::PropertyValue& rProp = aGeoPropSeq[ i ];
3714 if ( rProp.Name == "Type" )
3715 {
3716 if ( rProp.Value >>= rShapeType )
3717 {
3718 if (bOOXML)
3719 {
3720 // In case of VML export, try to handle the
3721 // ooxml- prefix in rShapeType. If that fails,
3722 // just do the same as the binary export.
3723 eShapeType = msfilter::util::GETVMLShapeType(rShapeType);
3724 if (eShapeType == mso_sptNil)
3725 eShapeType = EnhancedCustomShapeTypeNames::Get(rShapeType);
3726 }
3727 else
3728 eShapeType = EnhancedCustomShapeTypeNames::Get( rShapeType );
3729 }
3730 }
3731 else if ( rProp.Name == "MirroredX" )
3732 {
3733 bool bMirroredX;
3734 if ( ( rProp.Value >>= bMirroredX ) && bMirroredX )
3735 nMirrorFlags |= ShapeFlag::FlipH;
3736 }
3737 else if ( rProp.Name == "MirroredY" )
3738 {
3739 bool bMirroredY;
3740 if ( ( rProp.Value >>= bMirroredY ) && bMirroredY )
3741 nMirrorFlags |= ShapeFlag::FlipV;
3742 }
3743 }
3744 }
3745 }
3746 catch( const uno::Exception& )
3747 {
3748 }
3749 }
3750 return eShapeType;
3751}
3752
3753
3754// Implement for form control export
3755bool EscherPropertyContainer::CreateBlipPropertiesforOLEControl(const uno::Reference<beans::XPropertySet> & rXPropSet,
3756 const uno::Reference<drawing::XShape> & rXShape)
3757{
3759 if ( !pShape )
3760 return false;
3761
3762 Graphic aGraphic(SdrExchangeView::GetObjGraphic(*pShape));
3763 const GraphicObject aGraphicObject(std::move(aGraphic));
3764
3765 if (!aGraphicObject.GetUniqueID().isEmpty())
3766 {
3768 {
3769 sal_uInt32 nBlibId = pGraphicProvider->GetBlibID(*pPicOutStrm, aGraphicObject);
3770 if ( nBlibId )
3771 {
3772 AddOpt( ESCHER_Prop_pib, nBlibId, true );
3773 ImplCreateGraphicAttributes( rXPropSet, nBlibId, false );
3774 return true;
3775 }
3776 }
3777 }
3778
3779 return false;
3780}
3781
3783{
3784}
3785
3787{
3788}
3789
3790bool EscherPersistTable::PtIsID( sal_uInt32 nID )
3791{
3792 return std::any_of(maPersistTable.begin(), maPersistTable.end(),
3793 [&nID](const auto& rxEntry) { return rxEntry->mnID == nID; });
3794}
3795
3796void EscherPersistTable::PtInsert( sal_uInt32 nID, sal_uInt32 nOfs )
3797{
3798 maPersistTable.push_back( std::make_unique<EscherPersistEntry>( nID, nOfs ) );
3799}
3800
3801void EscherPersistTable::PtDelete( sal_uInt32 nID )
3802{
3803 auto it = std::find_if(maPersistTable.begin(), maPersistTable.end(),
3804 [&nID](const std::unique_ptr<EscherPersistEntry>& rxEntry) { return rxEntry->mnID == nID; });
3805 if (it != maPersistTable.end())
3806 maPersistTable.erase( it );
3807}
3808
3809sal_uInt32 EscherPersistTable::PtGetOffsetByID( sal_uInt32 nID )
3810{
3811 for(auto const & pPtr : maPersistTable) {
3812 if ( pPtr->mnID == nID ) {
3813 return pPtr->mnOffset;
3814 }
3815 }
3816 return 0;
3817};
3818
3819void EscherPersistTable::PtReplace( sal_uInt32 nID, sal_uInt32 nOfs )
3820{
3821 for(auto const & pPtr : maPersistTable) {
3822 if ( pPtr->mnID == nID ) {
3823 pPtr->mnOffset = nOfs;
3824 return;
3825 }
3826 }
3827}
3828
3829void EscherPersistTable::PtReplaceOrInsert( sal_uInt32 nID, sal_uInt32 nOfs )
3830{
3831 for(auto const & pPtr : maPersistTable) {
3832 if ( pPtr->mnID == nID ) {
3833 pPtr->mnOffset = nOfs;
3834 return;
3835 }
3836 }
3837 PtInsert( nID, nOfs );
3838}
3839
3841 uno::Any& rAny,
3842 const uno::Reference<beans::XPropertySet> & rXPropSet,
3843 const OUString& rString,
3844 bool bTestPropertyAvailability)
3845{
3846 bool bRetValue = true;
3847 if ( bTestPropertyAvailability )
3848 {
3849 bRetValue = false;
3850 try
3851 {
3852 uno::Reference<beans::XPropertySetInfo>
3853 aXPropSetInfo( rXPropSet->getPropertySetInfo() );
3854 if ( aXPropSetInfo.is() )
3855 bRetValue = aXPropSetInfo->hasPropertyByName( rString );
3856 }
3857 catch( const uno::Exception& )
3858 {
3859 bRetValue = false;
3860 }
3861 }
3862 if ( bRetValue )
3863 {
3864 try
3865 {
3866 rAny = rXPropSet->getPropertyValue( rString );
3867 if ( !rAny.hasValue() )
3868 bRetValue = false;
3869 }
3870 catch( const uno::Exception& )
3871 {
3872 bRetValue = false;
3873 }
3874 }
3875 return bRetValue;
3876}
3877
3879 const uno::Reference<beans::XPropertySet> & rXPropSet,
3880 const OUString& rPropertyName )
3881{
3882 beans::PropertyState eRetValue = beans::PropertyState_AMBIGUOUS_VALUE;
3883 try
3884 {
3885 uno::Reference<beans::XPropertyState> aXPropState
3886 ( rXPropSet, uno::UNO_QUERY );
3887 if ( aXPropState.is() )
3888 eRetValue = aXPropState->getPropertyState( rPropertyName );
3889 }
3890 catch( const uno::Exception& )
3891 {
3892 }
3893 return eRetValue;
3894}
3895
3896EscherBlibEntry::EscherBlibEntry( sal_uInt32 nPictureOffset, const GraphicObject& rObject, const OString& rId,
3897 const GraphicAttr* pGraphicAttr ) :
3898 maPrefMapMode ( rObject.GetPrefMapMode() ),
3899 maPrefSize ( rObject.GetPrefSize() ),
3900 mnPictureOffset ( nPictureOffset ),
3901 mnRefCount ( 1 ),
3902 mnSizeExtra ( 0 ),
3903 mbIsEmpty ( true )
3904{
3905 mbIsNativeGraphicPossible = ( pGraphicAttr == nullptr );
3907 mnSize = 0;
3908
3909 sal_uInt32 nLen = static_cast<sal_uInt32>(rId.getLength());
3910 const char* pData = rId.getStr();
3911 GraphicType eType( rObject.GetType() );
3912 if (!(nLen && (eType != GraphicType::NONE)))
3913 return;
3914
3915 mnIdentifier[ 0 ] = rtl_crc32( 0,pData, nLen );
3916 mnIdentifier[ 1 ] = 0;
3917
3918 if ( pGraphicAttr )
3919 {
3920 if ( pGraphicAttr->IsSpecialDrawMode()
3921 || pGraphicAttr->IsMirrored()
3922 || pGraphicAttr->IsCropped()
3923 || pGraphicAttr->IsRotated()
3924 || pGraphicAttr->IsTransparent()
3925 || pGraphicAttr->IsAdjusted() )
3926 {
3927 SvMemoryStream aSt( sizeof( GraphicAttr ) );
3928 aSt.WriteUInt16( static_cast<sal_uInt16>(pGraphicAttr->GetDrawMode()) )
3929 .WriteUInt32( static_cast<sal_uInt32>(pGraphicAttr->GetMirrorFlags()) )
3930 .WriteInt32( pGraphicAttr->GetLeftCrop() )
3931 .WriteInt32( pGraphicAttr->GetTopCrop() )
3932 .WriteInt32( pGraphicAttr->GetRightCrop() )
3933 .WriteInt32( pGraphicAttr->GetBottomCrop() )
3934 .WriteUInt16( pGraphicAttr->GetRotation().get() )
3935 .WriteInt16( pGraphicAttr->GetLuminance() )
3936 .WriteInt16( pGraphicAttr->GetContrast() )
3937 .WriteInt16( pGraphicAttr->GetChannelR() )
3938 .WriteInt16( pGraphicAttr->GetChannelG() )
3939 .WriteInt16( pGraphicAttr->GetChannelB() )
3940 .WriteDouble( pGraphicAttr->GetGamma() );
3941 aSt.WriteBool( pGraphicAttr->IsInvert() )
3942 .WriteUChar( 255 - pGraphicAttr->GetAlpha() ); // transparency
3943 mnIdentifier[ 1 ] = rtl_crc32( 0, aSt.GetData(), aSt.Tell() );
3944 }
3945 else
3947 }
3948 sal_uInt32 i, nTmp, n1, n2;
3949 n1 = n2 = 0;
3950 for ( i = 0; i < nLen; i++ )
3951 {
3952 nTmp = n2 >> 28; // rotating 4 bit
3953 n2 <<= 4;
3954 n2 |= n1 >> 28;
3955 n1 <<= 4;
3956 n1 |= nTmp;
3957 n1 ^= *pData++ - '0';
3958 }
3959 mnIdentifier[ 2 ] = n1;
3960 mnIdentifier[ 3 ] = n2;
3961 mbIsEmpty = false;
3962};
3963
3964void EscherBlibEntry::WriteBlibEntry( SvStream& rSt, bool bWritePictureOffset, sal_uInt32 nResize )
3965{
3966 sal_uInt32 nPictureOffset = bWritePictureOffset ? mnPictureOffset : 0;
3967
3968 rSt.WriteUInt32( ( ESCHER_BSE << 16 ) | ( ( static_cast<sal_uInt16>(meBlibType) << 4 ) | 2 ) )
3969 .WriteUInt32( 36 + nResize )
3971
3972 switch ( meBlibType )
3973 {
3974 case EMF :
3975 case WMF : // converting EMF/WMF on OS2 to Pict
3976 rSt.WriteUChar( PICT );
3977 break;
3978 default:
3979 rSt.WriteUChar( meBlibType );
3980 }
3981
3982 rSt.WriteBytes(&mnIdentifier[0], 16);
3983 rSt.WriteUInt16( 0 )
3986 .WriteUInt32( nPictureOffset )
3987 .WriteUInt32( 0 );
3988}
3989
3991{
3992};
3993
3994bool EscherBlibEntry::operator==( const EscherBlibEntry& rEscherBlibEntry ) const
3995{
3996 for ( int i = 0; i < 3; i++ )
3997 {
3998 if ( mnIdentifier[ i ] != rEscherBlibEntry.mnIdentifier[ i ] )
3999 return false;
4000 }
4001 return true;
4002}
4003
4005 mnFlags ( nFlags )
4006{
4007}
4008
4010{
4011}
4012
4014{
4015 for( size_t i = 0; i < mvBlibEntrys.size(); i++ )
4016 {
4017 mvBlibEntrys[ i ]->mnPictureOffset += nOffset;
4018 }
4019}
4020
4022{
4023 mvBlibEntrys.push_back( std::unique_ptr<EscherBlibEntry>(p_EscherBlibEntry) );
4024 return mvBlibEntrys.size();
4025}
4026
4027sal_uInt32 EscherGraphicProvider::GetBlibStoreContainerSize( SvStream const * pMergePicStreamBSE ) const
4028{
4029 sal_uInt32 nSize = 44 * mvBlibEntrys.size() + 8;
4030 if ( pMergePicStreamBSE )
4031 {
4032 for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
4033 nSize += mvBlibEntrys[ i ]->mnSize + mvBlibEntrys[ i ]->mnSizeExtra;
4034 }
4035 return nSize;
4036}
4037
4039 sal_uInt32 nBlipId, sal_uInt32 nResize)
4040{
4041 if (nBlipId > mvBlibEntrys.size() || nBlipId == 0)
4042 return;
4043 mvBlibEntrys[nBlipId-1]->WriteBlibEntry(rSt, true/*bWritePictureOffSet*/, nResize);
4044}
4045
4047{
4048 sal_uInt32 nSize = GetBlibStoreContainerSize( pMergePicStreamBSE );
4049 if ( !nSize )
4050 return;
4051
4052 rSt.WriteUInt32( ( ESCHER_BstoreContainer << 16 ) | 0x1f )
4053 .WriteUInt32( nSize - 8 );
4054
4055 if ( pMergePicStreamBSE )
4056 {
4057 sal_uInt32 nBlipSize, nOldPos = pMergePicStreamBSE->Tell();
4058 const sal_uInt32 nBuf = 0x40000; // 256KB buffer
4059 std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ nBuf ]);
4060
4061 for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
4062 {
4063 EscherBlibEntry* pBlibEntry = mvBlibEntrys[ i ].get();
4064
4065 ESCHER_BlibType nBlibType = pBlibEntry->meBlibType;
4066 nBlipSize = pBlibEntry->mnSize + pBlibEntry->mnSizeExtra;
4067 pBlibEntry->WriteBlibEntry( rSt, false, nBlipSize );
4068
4069 // BLIP
4070 pMergePicStreamBSE->Seek( pBlibEntry->mnPictureOffset );
4071 sal_uInt16 n16;
4072 // record version and instance
4073 pMergePicStreamBSE->ReadUInt16( n16 );
4074 rSt.WriteUInt16( n16 );
4075 // record type
4076 pMergePicStreamBSE->ReadUInt16( n16 );
4077 rSt.WriteUInt16( ESCHER_BlipFirst + nBlibType );
4078 DBG_ASSERT( n16 == ESCHER_BlipFirst + nBlibType , "EscherGraphicProvider::WriteBlibStoreContainer: BLIP record types differ" );
4079 sal_uInt32 n32;
4080 // record size
4081 pMergePicStreamBSE->ReadUInt32( n32 );
4082 nBlipSize -= 8;
4083 rSt.WriteUInt32( nBlipSize );
4084 DBG_ASSERT( nBlipSize == n32, "EscherGraphicProvider::WriteBlibStoreContainer: BLIP sizes differ" );
4085 // record
4086 while ( nBlipSize )
4087 {
4088 sal_uInt32 nBytes = std::min( nBlipSize, nBuf );
4089 pMergePicStreamBSE->ReadBytes(pBuf.get(), nBytes);
4090 rSt.WriteBytes(pBuf.get(), nBytes);
4091 nBlipSize -= nBytes;
4092 }
4093 }
4094 pMergePicStreamBSE->Seek( nOldPos );
4095 }
4096 else
4097 {
4098 for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
4099 mvBlibEntrys[ i ]->WriteBlibEntry( rSt, true );
4100 }
4101}
4102
4103bool EscherGraphicProvider::GetPrefSize( const sal_uInt32 nBlibId, Size& rPrefSize, MapMode& rPrefMapMode )
4104{
4105 bool bInRange = nBlibId && ( ( nBlibId - 1 ) < mvBlibEntrys.size() );
4106 if ( bInRange )
4107 {
4108 EscherBlibEntry* pEntry = mvBlibEntrys[ nBlibId - 1 ].get();
4109 rPrefSize = pEntry->maPrefSize;
4110 rPrefMapMode = pEntry->maPrefMapMode;
4111 }
4112 return bInRange;
4113}
4114
4115sal_uInt32 EscherGraphicProvider::GetBlibID( SvStream& rPicOutStrm, GraphicObject const & rGraphicObject,
4116 const awt::Rectangle* pVisArea,
4117 const GraphicAttr* pGraphicAttr, const bool bOOxmlExport )
4118{
4119 sal_uInt32 nBlibId = 0;
4120
4121 std::unique_ptr<EscherBlibEntry> p_EscherBlibEntry( new EscherBlibEntry( rPicOutStrm.Tell(), rGraphicObject, rGraphicObject.GetUniqueID(), pGraphicAttr ) );
4122 if ( !p_EscherBlibEntry->IsEmpty() )
4123 {
4124 for ( size_t i = 0; i < mvBlibEntrys.size(); i++ )
4125 {
4126 if ( *( mvBlibEntrys[ i ] ) == *p_EscherBlibEntry )
4127 {
4128 mvBlibEntrys[ i ]->mnRefCount++;
4129 return i + 1;
4130 }
4131 }
4132
4133 bool bUseNativeGraphic( false );
4134
4135 Graphic aGraphic(rGraphicObject.GetTransformedGraphic(pGraphicAttr));
4136 GfxLink aGraphicLink;
4137 SvMemoryStream aStream;
4138
4139 const sal_uInt8* pGraphicAry = nullptr;
4140
4141 if ( p_EscherBlibEntry->mbIsNativeGraphicPossible && aGraphic.IsGfxLink() )
4142 {
4143 aGraphicLink = aGraphic.GetGfxLink();
4144
4145 p_EscherBlibEntry->mnSize = aGraphicLink.GetDataSize();
4146 pGraphicAry = aGraphicLink.GetData();
4147
4148 if ( p_EscherBlibEntry->mnSize && pGraphicAry )
4149 {
4150 switch ( aGraphicLink.GetType() )
4151 {
4152 case GfxLinkType::NativeJpg : p_EscherBlibEntry->meBlibType = PEG; break;
4153 case GfxLinkType::NativePng : p_EscherBlibEntry->meBlibType = PNG; break;
4154
4155 // #i15508# added BMP type for better exports; need to check this
4156 // checked - does not work that way, so keep out for now. It may
4157 // work somehow with direct DIB data, but that would need to be checked
4158 // carefully
4159 // for more comments please check RtfAttributeOutput::FlyFrameGraphic
4160 //
4161 // case GfxLinkType::NativeBmp : p_EscherBlibEntry->meBlibType = DIB; break;
4162
4163 case GfxLinkType::NativeWmf :
4164 {
4165 if ( aGraphicLink.IsEMF() )
4166 {
4167 p_EscherBlibEntry->meBlibType = EMF;
4168 }
4169 else if ( pGraphicAry && ( p_EscherBlibEntry->mnSize > 0x2c ) )
4170 {
4171 p_EscherBlibEntry->meBlibType = WMF;
4172 if ( ( pGraphicAry[ 0 ] == 0xd7 ) && ( pGraphicAry[ 1 ] == 0xcd )
4173 && ( pGraphicAry[ 2 ] == 0xc6 ) && ( pGraphicAry[ 3 ] == 0x9a ) )
4174 { // we have to get rid of the metafileheader
4175 pGraphicAry += 22;
4176 p_EscherBlibEntry->mnSize -= 22;
4177 }
4178 }
4179 }
4180 break;
4181 default: break;
4182 }
4183 if ( p_EscherBlibEntry->meBlibType != UNKNOWN )
4184 bUseNativeGraphic = true;
4185 }
4186 }
4187 if ( !bUseNativeGraphic )
4188 {
4189 GraphicType eGraphicType = aGraphic.GetType();
4190 if ( ( eGraphicType == GraphicType::Bitmap ) || ( eGraphicType == GraphicType::GdiMetafile ) )
4191 {
4192 ErrCode nErrCode;
4193 if ( !aGraphic.IsAnimated() )
4194 nErrCode = GraphicConverter::Export( aStream, aGraphic, ( eGraphicType == GraphicType::Bitmap ) ? ConvertDataFormat::PNG : ConvertDataFormat::EMF );
4195 else
4196 { // to store an animation, a gif has to be included into the msOG chunk of a png #I5583#
4198 SvMemoryStream aGIFStream;
4199 const char* const pString = "MSOFFICE9.0";
4200 aGIFStream.WriteBytes(pString, strlen(pString));
4201 nErrCode = rFilter.ExportGraphic( aGraphic, u"", aGIFStream,
4202 rFilter.GetExportFormatNumberForShortName( u"GIF" ) );
4204 nErrCode != ERRCODE_NONE, "filter.ms",
4205 "ExportGraphic to GIF failed with " << nErrCode);
4206 if (nErrCode == ERRCODE_NONE)
4207 {
4208 sal_uInt32 nGIFSreamLen = aGIFStream.Tell();
4209 uno::Sequence<sal_Int8> aGIFSeq( nGIFSreamLen );
4210 sal_Int8* pSeq = aGIFSeq.getArray();
4211 aGIFStream.Seek( STREAM_SEEK_TO_BEGIN );
4212 aGIFStream.ReadBytes(pSeq, nGIFSreamLen);
4213 beans::PropertyValue aChunkProp, aFilterProp;
4214 aChunkProp.Name = "msOG";
4215 aChunkProp.Value <<= aGIFSeq;
4216 uno::Sequence<beans::PropertyValue> aAdditionalChunkSequence{ aChunkProp };
4217 aFilterProp.Name = "AdditionalChunks";
4218 aFilterProp.Value <<= aAdditionalChunkSequence;
4219 uno::Sequence<beans::PropertyValue> aFilterData{ aFilterProp };
4220 nErrCode = rFilter.ExportGraphic( aGraphic, u"", aStream,
4221 rFilter.GetExportFormatNumberForShortName( u"PNG" ), &aFilterData );
4222 }
4223 }
4224 if ( nErrCode == ERRCODE_NONE )
4225 {
4226 p_EscherBlibEntry->meBlibType = ( eGraphicType == GraphicType::Bitmap ) ? PNG : EMF;
4227 p_EscherBlibEntry->mnSize = aStream.TellEnd();
4228 pGraphicAry = static_cast<sal_uInt8 const *>(aStream.GetData());
4229 }
4230 }
4231 }
4232
4233 ESCHER_BlibType eBlibType = p_EscherBlibEntry->meBlibType;
4234 if ( p_EscherBlibEntry->mnSize && pGraphicAry && ( eBlibType != UNKNOWN ) )
4235 {
4236 sal_uInt32 nExtra, nAtomSize = 0;
4237 sal_uInt32 nInstance, nUncompressedSize = p_EscherBlibEntry->mnSize;
4238
4240 {
4241 rPicOutStrm.WriteUInt32( 0x7f90000 | static_cast<sal_uInt16>( mvBlibEntrys.size() << 4 ) )
4242 .WriteUInt32( 0 );
4243 nAtomSize = rPicOutStrm.Tell();
4244 if ( eBlibType == PNG )
4245 rPicOutStrm.WriteUInt16( 0x0606 );
4246 else if ( eBlibType == WMF )
4247 rPicOutStrm.WriteUInt16( 0x0403 );
4248 else if ( eBlibType == EMF )
4249 rPicOutStrm.WriteUInt16( 0x0402 );
4250 else if ( eBlibType == PEG )
4251 rPicOutStrm.WriteUInt16( 0x0505 );
4252 }
4253
4254 // fdo#69607 do not compress WMF files if we are in OOXML export
4255 if ( ( eBlibType == PEG ) || ( eBlibType == PNG ) // || ( eBlibType == DIB )) // #i15508#
4256 || ( ( ( eBlibType == WMF ) || ( eBlibType == EMF ) ) && bOOxmlExport ) )
4257 {
4258 nExtra = 17;
4259 p_EscherBlibEntry->mnSizeExtra = nExtra + 8;
4260
4261 // #i15508# type see SvxMSDffManager::GetBLIPDirect (checked, does not work this way)
4262 // see RtfAttributeOutput::FlyFrameGraphic for more comments
4263 // maybe it would work with direct DIB data, but that would need thorough testing
4264 if( eBlibType == PNG )
4265 {
4266 nInstance = 0xf01e6e00;
4267 }
4268 else // if( eBlibType == PEG )
4269 {
4270 nInstance = 0xf01d46a0;
4271 }
4272 //else // eBlibType == DIB
4273 //{
4274 // nInstance = 0xf01d7A80;
4275 //}
4276
4277 // #i15508#
4278 //nInstance = ( eBlibType == PNG ) ? 0xf01e6e00 : 0xf01d46a0;
4279
4280
4281 rPicOutStrm.WriteUInt32( nInstance ).WriteUInt32( p_EscherBlibEntry->mnSize + nExtra );
4282 rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16);
4283 rPicOutStrm.WriteUChar( 0xff );
4284 rPicOutStrm.WriteBytes(pGraphicAry, p_EscherBlibEntry->mnSize);
4285 }
4286 else
4287 {
4288 ZCodec aZCodec( 0x8000, 0x8000 );
4289 aZCodec.BeginCompression();
4290 SvMemoryStream aDestStrm;
4291 aZCodec.Write( aDestStrm, pGraphicAry, p_EscherBlibEntry->mnSize );
4292 aZCodec.EndCompression();
4293 p_EscherBlibEntry->mnSize = aDestStrm.TellEnd();
4294 pGraphicAry = static_cast<sal_uInt8 const *>(aDestStrm.GetData());
4295 if ( p_EscherBlibEntry->mnSize && pGraphicAry )
4296 {
4297 nExtra = eBlibType == WMF ? 0x42 : 0x32; // !EMF -> no change
4298 p_EscherBlibEntry->mnSizeExtra = nExtra + 8;
4299 nInstance = ( eBlibType == WMF ) ? 0xf01b2170 : 0xf01a3d40; // !EMF -> no change
4300 rPicOutStrm.WriteUInt32( nInstance ).WriteUInt32( p_EscherBlibEntry->mnSize + nExtra );
4301 if ( eBlibType == WMF ) // !EMF -> no change
4302 rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16);
4303 rPicOutStrm.WriteBytes(p_EscherBlibEntry->mnIdentifier, 16);
4304
4305 /*
4306 ##913##
4307 For Word the stored size of the graphic is critical the
4308 metafile boundaries must match the actual graphics
4309 boundaries, and the width and height must be in EMU's
4310
4311 If you don't do it this way then objects edited in the
4312 msoffice app may show strange behaviour as the size jumps
4313 around, and the original size and scaling factor in word
4314 will be a very strange figure
4315 */
4316 sal_uInt32 nPrefWidth = p_EscherBlibEntry->maPrefSize.Width();
4317 sal_uInt32 nPrefHeight = p_EscherBlibEntry->maPrefSize.Height();
4318 sal_uInt32 nWidth, nHeight;
4319 if ( pVisArea )
4320 {
4321 nWidth = pVisArea->Width * 360;
4322 nHeight = pVisArea->Height * 360;
4323 }
4324 else
4325 {
4326 Size aPrefSize(lcl_SizeToEmu(p_EscherBlibEntry->maPrefSize, p_EscherBlibEntry->maPrefMapMode));
4327 nWidth = aPrefSize.Width() * 360;
4328 nHeight = aPrefSize.Height() * 360;
4329 }
4330 rPicOutStrm.WriteUInt32( nUncompressedSize ) // WMFSize without FileHeader
4331 .WriteInt32( 0 ) // since we can't find out anymore what the original size of
4332 .WriteInt32( 0 ) // the WMF (without Fileheader) was we write 10cm / x
4333 .WriteUInt32( nPrefWidth )
4334 .WriteUInt32( nPrefHeight )
4335 .WriteUInt32( nWidth )
4336 .WriteUInt32( nHeight )
4337 .WriteUInt32( p_EscherBlibEntry->mnSize )
4338 .WriteUInt16( 0xfe00 ); // compression Flags
4339 rPicOutStrm.WriteBytes(pGraphicAry, p_EscherBlibEntry->mnSize);
4340 }
4341 }
4342 if ( nAtomSize )
4343 {
4344 sal_uInt32 nPos = rPicOutStrm.Tell();
4345 rPicOutStrm.Seek( nAtomSize - 4 );
4346 rPicOutStrm.WriteUInt32( nPos - nAtomSize );
4347 rPicOutStrm.Seek( nPos );
4348 }
4349 nBlibId = ImplInsertBlib( p_EscherBlibEntry.release() );
4350 }
4351 }
4352 return nBlibId;
4353}
4354
4355namespace {
4356
4357struct EscherConnectorRule
4358{
4359 sal_uInt32 nRuleId;
4360 sal_uInt32 nShapeA; // SPID of shape A
4361 sal_uInt32 nShapeB; // SPID of shape B
4362 sal_uInt32 nShapeC; // SPID of connector shape
4363 sal_uInt32 ncptiA; // Connection site Index of shape A
4364 sal_uInt32 ncptiB; // Connection site Index of shape B
4365};
4366
4367}
4368
4370{
4371 uno::Reference<drawing::XShape>aXShape;
4372 sal_uInt32 n_EscherId;
4373
4374 EscherShapeListEntry(uno::Reference<drawing::XShape> xShape, sal_uInt32 nId)
4375 : aXShape(std::move(xShape))
4376 , n_EscherId(nId)
4377 {}
4378};
4379
4380sal_uInt32 EscherConnectorListEntry::GetClosestPoint( const tools::Polygon& rPoly, const awt::Point& rPoint )
4381{
4382 sal_uInt16 nCount = rPoly.GetSize();
4383 sal_uInt16 nClosest = nCount;
4384 double fDist = sal_uInt32(0xffffffff);
4385 while( nCount-- )
4386 {
4387 double fDistance = hypot( rPoint.X - rPoly[ nCount ].X(), rPoint.Y - rPoly[ nCount ].Y() );
4388 if ( fDistance < fDist )
4389 {
4390 nClosest = nCount;
4391 fDist = fDistance;
4392 }
4393 }
4394 return nClosest;
4395};
4396
4397
4398// for rectangles for ellipses for polygons
4399//
4400// nRule = 0 ->Top 0 ->Top nRule = index to a (Poly)Polygon point
4401// 1 ->Left 2 ->Left
4402// 2 ->Bottom 4 ->Bottom
4403// 3 ->Right 6 ->Right
4404
4406{
4407 sal_uInt32 nRule = 0;
4408
4409 uno::Any aAny;
4410 awt::Point aRefPoint( bFirst ? maPointA : maPointB );
4411 uno::Reference<drawing::XShape>
4412 aXShape( bFirst ? mXConnectToA : mXConnectToB );
4413
4414 OUString aString(aXShape->getShapeType());
4415 OStringBuffer aBuf(OUStringToOString(aString, RTL_TEXTENCODING_UTF8));
4416 aBuf.remove( 0, 13 ); // removing "com.sun.star."
4417 sal_Int16 nPos = aBuf.toString().indexOf("Shape");
4418 aBuf.remove(nPos, 5);
4419 OString aType = aBuf.makeStringAndClear();
4420
4421 uno::Reference<beans::XPropertySet>
4422 aPropertySet( aXShape, uno::UNO_QUERY );
4423
4424 if ((aType == "drawing.PolyPolygon") || (aType == "drawing.PolyLine"))
4425 {
4426 if ( aPropertySet.is() )
4427 {
4428 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet, "PolyPolygon" ) )
4429 {
4430 auto pSourcePolyPolygon =
4431 o3tl::doAccess<drawing::PointSequenceSequence>(aAny);
4432 sal_Int32 nOuterSequenceCount = pSourcePolyPolygon->getLength();
4433 drawing::PointSequence const * pOuterSequence = pSourcePolyPolygon->getConstArray();
4434
4435 if ( pOuterSequence )
4436 {
4437 sal_Int32 a, b, nIndex = 0;
4438 sal_uInt32 nDistance = 0xffffffff;
4439 for( a = 0; a < nOuterSequenceCount; a++ )
4440 {
4441 drawing::PointSequence const * pInnerSequence = pOuterSequence++;
4442 if ( pInnerSequence )
4443 {
4444 awt::Point const * pArray = pInnerSequence->getConstArray();
4445 if ( pArray )
4446 {
4447 for ( b = 0; b < pInnerSequence->getLength(); b++, nIndex++, pArray++ )
4448 {
4449 sal_uInt32 nDist = static_cast<sal_uInt32>(hypot( aRefPoint.X - pArray->X, aRefPoint.Y - pArray->Y ));
4450 if ( nDist < nDistance )
4451 {
4452 nRule = nIndex;
4453 nDistance = nDist;
4454 }
4455 }
4456 }
4457 }
4458 }
4459 }
4460 }
4461 }
4462 }
4463 else if ((aType == "drawing.OpenBezier") || (aType == "drawing.OpenFreeHand") || (aType == "drawing.PolyLinePath")
4464 || (aType == "drawing.ClosedBezier") || ( aType == "drawing.ClosedFreeHand") || (aType == "drawing.PolyPolygonPath") )
4465 {
4466 uno::Reference<beans::XPropertySet>
4467 aPropertySet2( aXShape, uno::UNO_QUERY );
4468 if ( aPropertySet2.is() )
4469 {
4470 if ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet2, "PolyPolygonBezier" ) )
4471 {
4472 auto pSourcePolyPolygon =
4473 o3tl::doAccess<drawing::PolyPolygonBezierCoords>(aAny);
4474 sal_Int32 nOuterSequenceCount = pSourcePolyPolygon->Coordinates.getLength();
4475
4476 // get pointer of inner sequences
4477 drawing::PointSequence const * pOuterSequence =
4478 pSourcePolyPolygon->Coordinates.getConstArray();
4479 drawing::FlagSequence const * pOuterFlags =
4480 pSourcePolyPolygon->Flags.getConstArray();
4481
4482 if ( pOuterSequence && pOuterFlags )
4483 {
4484 sal_Int32 a, b, nIndex = 0;
4485 sal_uInt32 nDistance = 0xffffffff;
4486
4487 for ( a = 0; a < nOuterSequenceCount; a++ )
4488 {
4489 drawing::PointSequence const * pInnerSequence = pOuterSequence++;
4490 drawing::FlagSequence const * pInnerFlags = pOuterFlags++;
4491 if ( pInnerSequence && pInnerFlags )
4492 {
4493 awt::Point const * pArray = pInnerSequence->getConstArray();
4494 drawing::PolygonFlags const * pFlags = pInnerFlags->getConstArray();
4495 if ( pArray && pFlags )
4496 {
4497 for ( b = 0; b < pInnerSequence->getLength(); b++, pArray++ )
4498 {
4499 drawing::PolygonFlags ePolyFlags = *pFlags++;
4500 if ( ePolyFlags == drawing::PolygonFlags_CONTROL )
4501 continue;
4502 sal_uInt32 nDist = static_cast<sal_uInt32>(hypot( aRefPoint.X - pArray->X, aRefPoint.Y - pArray->Y ));
4503 if ( nDist < nDistance )
4504 {
4505 nRule = nIndex;
4506 nDistance = nDist;
4507 }
4508 nIndex++;
4509 }
4510 }
4511 }
4512 }
4513 }
4514 }
4515 }
4516 }
4517 else
4518 {
4519 bool bRectangularConnection = true;
4520
4521 if (aType == "drawing.Custom")
4522 {
4523 if (auto pSdrObjCustomShape = dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(aXShape)))
4524 {
4525 const SdrCustomShapeGeometryItem& rGeometryItem =
4526 pSdrObjCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
4527
4528 OUString sShapeType;
4529 const uno::Any* pType = rGeometryItem.GetPropertyValueByName( "Type" );
4530 if ( pType )
4531 *pType >>= sShapeType;
4532 MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
4533
4534 uno::Any* pGluePointType = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( "Path", "GluePointType" );
4535
4536 sal_Int16 nGluePointType = sal_Int16();
4537 if ( !( pGluePointType &&
4538 ( *pGluePointType >>= nGluePointType ) ) )
4539 nGluePointType = GetCustomShapeConnectionTypeDefault( eSpType );
4540
4541 if ( nGluePointType == drawing::EnhancedCustomShapeGluePointType::CUSTOM )
4542 {
4543 const SdrGluePointList* pList = pSdrObjCustomShape->GetGluePointList();
4544 if ( pList )
4545 {
4546 tools::Polygon aPoly;
4547 sal_uInt16 nNum, nCnt = pList->GetCount();
4548 if ( nCnt )
4549 {
4550 for ( nNum = 0; nNum < nCnt; nNum++ )
4551 {
4552 const SdrGluePoint& rGP = (*pList)[ nNum ];
4553 Point aPt(rGP.GetAbsolutePos(*pSdrObjCustomShape));
4554 aPoly.Insert( POLY_APPEND, aPt );
4555 }
4556 nRule = GetClosestPoint( aPoly, aRefPoint );
4557 bRectangularConnection = false;
4558 }
4559 }
4560 }
4561 else if ( nGluePointType == drawing::EnhancedCustomShapeGluePointType::SEGMENTS )
4562 {
4563 tools::PolyPolygon aPolyPoly;
4564 rtl::Reference<SdrObject> pTemporaryConvertResultObject(pSdrObjCustomShape->DoConvertToPolyObj(true, true));
4565 SdrPathObj* pSdrPathObj(dynamic_cast< SdrPathObj* >(pTemporaryConvertResultObject.get()));
4566
4567 if(pSdrPathObj)
4568 {
4569 // #i74631# use explicit constructor here. Also XPolyPolygon is not necessary,
4570 // reducing to PolyPolygon
4571 aPolyPoly = tools::PolyPolygon(pSdrPathObj->GetPathPoly());
4572 }
4573
4574 // do *not* forget to delete the temporary used SdrObject - possible memory leak (!)
4575 pTemporaryConvertResultObject.clear();
4576 pSdrPathObj = nullptr;
4577
4578 if(0 != aPolyPoly.Count())
4579 {
4580 sal_Int16 nIndex = 0;
4581 sal_uInt16 a, b;
4582 sal_uInt32 nDistance = 0xffffffff;
4583
4584 for ( a = 0; a < aPolyPoly.Count(); a++ )
4585 {
4586 const tools::Polygon& rPoly = aPolyPoly.GetObject( a );
4587 for ( b = 0; b < rPoly.GetSize(); b++ )
4588 {
4589 if ( rPoly.GetFlags( b ) != PolyFlags::Normal )
4590 continue;
4591 const Point& rPt = rPoly[ b ];
4592 sal_uInt32 nDist = static_cast<sal_uInt32>(hypot( aRefPoint.X - rPt.X(), aRefPoint.Y - rPt.Y() ));
4593 if ( nDist < nDistance )
4594 {
4595 nRule = nIndex;
4596 nDistance = nDist;
4597 }
4598 nIndex++;
4599 }
4600 }
4601
4602 if ( nDistance != 0xffffffff )
4603 bRectangularConnection = false;
4604 }
4605 }
4606 }
4607 }
4608 if ( bRectangularConnection )
4609 {
4610 awt::Point aPoint( aXShape->getPosition() );
4611 awt::Size aSize( aXShape->getSize() );
4612
4613 tools::Rectangle aRect( Point( aPoint.X, aPoint.Y ), Size( aSize.Width, aSize.Height ) );
4614 Point aCenter( aRect.Center() );
4615 tools::Polygon aPoly( 4 );
4616
4617 aPoly[ 0 ] = Point( aCenter.X(), aRect.Top() );
4618 aPoly[ 1 ] = Point( aRect.Left(), aCenter.Y() );
4619 aPoly[ 2 ] = Point( aCenter.X(), aRect.Bottom() );
4620 aPoly[ 3 ] = Point( aRect.Right(), aCenter.Y() );
4621
4622 sal_Int32 nAngle = ( EscherPropertyValueHelper::GetPropertyValue( aAny, aPropertySet, "RotateAngle", true ) )
4623 ? *o3tl::doAccess<sal_Int32>(aAny) : 0;
4624 if ( nAngle )
4625 aPoly.Rotate( aRect.TopLeft(), Degree10(static_cast<sal_Int16>( ( nAngle + 5 ) / 10 )) );
4626 nRule = GetClosestPoint( aPoly, aRefPoint );
4627
4628 if (aType == "drawing.Ellipse")
4629 nRule <<= 1; // In PPT an ellipse has 8 ways to connect
4630 }
4631 }
4632 return nRule;
4633}
4634
4636{
4637}
4638
4640{
4641}
4642
4643void EscherSolverContainer::AddShape( const uno::Reference<drawing::XShape> & rXShape, sal_uInt32 nId )
4644{
4645 maShapeList.push_back( std::make_unique<EscherShapeListEntry>( rXShape, nId ) );
4646}
4647
4649 const uno::Reference<drawing::XShape> & rConnector,
4650 const awt::Point& rPA,
4651 uno::Reference<drawing::XShape> const & rConA,
4652 const awt::Point& rPB,
4653 uno::Reference<drawing::XShape> const & rConB
4654)
4655{
4656 maConnectorList.push_back( std::make_unique<EscherConnectorListEntry>( rConnector, rPA, rConA, rPB, rConB ) );
4657}
4658
4659sal_uInt32 EscherSolverContainer::GetShapeId( const uno::Reference<drawing::XShape> & rXShape ) const
4660{
4661 for (auto const & pPtr : maShapeList)
4662 {
4663 if ( rXShape == pPtr->aXShape )
4664 return pPtr->n_EscherId;
4665 }
4666 return 0;
4667}
4668
4670{
4671 sal_uInt32 nCount = maConnectorList.size();
4672 if ( !nCount )
4673 return;
4674
4675 sal_uInt32 nRecHdPos, nCurrentPos, nSize;
4676 rStrm .WriteUInt16( ( nCount << 4 ) | 0xf ) // open an ESCHER_SolverContainer
4678 .WriteUInt32( 0 );
4679
4680 nRecHdPos = rStrm.Tell() - 4;
4681
4682 EscherConnectorRule aConnectorRule;
4683 aConnectorRule.nRuleId = 2;
4684 for (auto const & pPtr : maConnectorList)
4685 {
4686 aConnectorRule.ncptiA = aConnectorRule.ncptiB = 0xffffffff;
4687 aConnectorRule.nShapeC = GetShapeId( pPtr->mXConnector );
4688 aConnectorRule.nShapeA = GetShapeId( pPtr->mXConnectToA );
4689 aConnectorRule.nShapeB = GetShapeId( pPtr->mXConnectToB );
4690
4691 if ( aConnectorRule.nShapeC )
4692 {
4693 if ( aConnectorRule.nShapeA )
4694 aConnectorRule.ncptiA = pPtr->GetConnectorRule( true );
4695 if ( aConnectorRule.nShapeB )
4696 aConnectorRule.ncptiB = pPtr->GetConnectorRule( false );
4697 }
4698 rStrm .WriteUInt32( ( ESCHER_ConnectorRule << 16 ) | 1 ) // atom hd
4699 .WriteUInt32( 24 )
4700 .WriteUInt32( aConnectorRule.nRuleId )
4701 .WriteUInt32( aConnectorRule.nShapeA )
4702 .WriteUInt32( aConnectorRule.nShapeB )
4703 .WriteUInt32( aConnectorRule.nShapeC )
4704 .WriteUInt32( aConnectorRule.ncptiA )
4705 .WriteUInt32( aConnectorRule.ncptiB );
4706
4707 aConnectorRule.nRuleId += 2;
4708 }
4709
4710 nCurrentPos = rStrm.Tell(); // close the ESCHER_SolverContainer
4711 nSize = ( nCurrentPos - nRecHdPos ) - 4;
4712 rStrm.Seek( nRecHdPos );
4713 rStrm.WriteUInt32( nSize );
4714 rStrm.Seek( nCurrentPos );
4715}
4716
4719 mpPicStrm( nullptr ),
4720 mbHasDggCont( false ),
4721 mbPicStrmQueried( false )
4722{
4723}
4724
4726{
4727}
4728
4730{
4731 // new drawing starts a new cluster in the cluster table (cluster identifiers are one-based)
4732 sal_uInt32 nClusterId = static_cast< sal_uInt32 >( maClusterTable.size() + 1 );
4733 // drawing identifiers are one-based
4734 sal_uInt32 nDrawingId = static_cast< sal_uInt32 >( maDrawingInfos.size() + 1 );
4735 // prepare new entries in the tables
4736 maClusterTable.emplace_back( nDrawingId );
4737 maDrawingInfos.emplace_back( nClusterId );
4738 // return the new drawing identifier
4739 return nDrawingId;
4740}
4741
4742sal_uInt32 EscherExGlobal::GenerateShapeId( sal_uInt32 nDrawingId, bool bIsInSpgr )
4743{
4744 // drawing identifier is one-based
4745 // make sure the drawing is valid (bnc#656503)
4746 if ( nDrawingId == 0 )
4747 return 0;
4748 // create index from the identifier
4749 size_t nDrawingIdx = nDrawingId - 1;
4750 OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GenerateShapeId - invalid drawing ID" );
4751 if( nDrawingIdx >= maDrawingInfos.size() )
4752 return 0;
4753 DrawingInfo& rDrawingInfo = maDrawingInfos[ nDrawingIdx ];
4754
4755 // cluster identifier in drawing info struct is one-based
4756 ClusterEntry* pClusterEntry = &maClusterTable[ rDrawingInfo.mnClusterId - 1 ];
4757
4758 // check cluster overflow, create new cluster entry
4759 if( pClusterEntry->mnNextShapeId == DFF_DGG_CLUSTER_SIZE )
4760 {
4761 // start a new cluster in the cluster table
4762 maClusterTable.emplace_back( nDrawingId );
4763 pClusterEntry = &maClusterTable.back();
4764 // new size of maClusterTable is equal to one-based identifier of the new cluster
4765 rDrawingInfo.mnClusterId = static_cast< sal_uInt32 >( maClusterTable.size() );
4766 }
4767
4768 // build shape identifier from cluster identifier and next free cluster shape identifier
4769 rDrawingInfo.mnLastShapeId = static_cast< sal_uInt32 >( rDrawingInfo.mnClusterId * DFF_DGG_CLUSTER_SIZE + pClusterEntry->mnNextShapeId );
4770 // update free shape identifier in cluster entry
4771 ++pClusterEntry->mnNextShapeId;
4772 /* Old code has counted the shapes only, if we are in a SPGRCONTAINER. Is
4773 this really intended? Maybe it's always true... */
4774 if( bIsInSpgr )
4775 ++rDrawingInfo.mnShapeCount;
4776
4777 // return the new shape identifier
4778 return rDrawingInfo.mnLastShapeId;
4779}
4780
4781sal_uInt32 EscherExGlobal::GetDrawingShapeCount( sal_uInt32 nDrawingId ) const
4782{
4783 size_t nDrawingIdx = nDrawingId - 1;
4784 OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GetDrawingShapeCount - invalid drawing ID" );
4785 return (nDrawingIdx < maDrawingInfos.size()) ? maDrawingInfos[ nDrawingIdx ].mnShapeCount : 0;
4786}
4787
4788sal_uInt32 EscherExGlobal::GetLastShapeId( sal_uInt32 nDrawingId ) const
4789{
4790 size_t nDrawingIdx = nDrawingId - 1;
4791 OSL_ENSURE( nDrawingIdx < maDrawingInfos.size(), "EscherExGlobal::GetLastShapeId - invalid drawing ID" );
4792 return (nDrawingIdx < maDrawingInfos.size()) ? maDrawingInfos[ nDrawingIdx ].mnLastShapeId : 0;
4793}
4794
4796{
4797 // 8 bytes header, 16 bytes fixed DGG data, 8 bytes for each cluster
4798 return static_cast< sal_uInt32 >( 24 + 8 * maClusterTable.size() );
4799}
4800
4802{
4803 sal_uInt32 nDggSize = GetDggAtomSize();
4804
4805 // write the DGG record header (do not include the 8 bytes of the header in the data size)
4806 rStrm.WriteUInt32( ESCHER_Dgg << 16 ).WriteUInt32( nDggSize - 8 );
4807
4808 // calculate and write the fixed DGG data
4809 sal_uInt32 nShapeCount = 0;
4810 sal_uInt32 nLastShapeId = 0;
4811 for (auto const& drawingInfo : maDrawingInfos)
4812 {
4813 nShapeCount += drawingInfo.mnShapeCount;
4814 nLastShapeId = ::std::max( nLastShapeId, drawingInfo.mnLastShapeId );
4815 }
4816 // the non-existing cluster with index #0 is counted too
4817 sal_uInt32 nClusterCount = static_cast< sal_uInt32 >( maClusterTable.size() + 1 );
4818 sal_uInt32 nDrawingCount = static_cast< sal_uInt32 >( maDrawingInfos.size() );
4819 rStrm.WriteUInt32( nLastShapeId ).WriteUInt32( nClusterCount ).WriteUInt32( nShapeCount ).WriteUInt32( nDrawingCount );
4820
4821 // write the cluster table
4822 for (auto const& elem : maClusterTable)
4823 rStrm.WriteUInt32( elem.mnDrawingId ).WriteUInt32( elem.mnNextShapeId );
4824}
4825
4827{
4828 if( !mbPicStrmQueried )
4829 {
4831 mbPicStrmQueried = true;
4832 }
4833 return mpPicStrm;
4834}
4835
4837{
4838 return nullptr;
4839}
4840
4841namespace {
4842
4843// Implementation of an empty stream that silently succeeds, but does nothing.
4844//
4845// In fact, this is a hack. The right solution is to abstract EscherEx to be
4846// able to work without SvStream; but at the moment it is better to live with
4847// this I guess.
4848class SvNullStream : public SvStream
4849{
4850protected:
4851 virtual std::size_t GetData( void* pData, std::size_t nSize ) override { memset( pData, 0, nSize ); return nSize; }
4852 virtual std::size_t PutData( const void*, std::size_t nSize ) override { return nSize; }
4853 virtual sal_uInt64 SeekPos( sal_uInt64 nPos ) override { return nPos; }
4854 virtual void SetSize( sal_uInt64 ) override {}
4855 virtual void FlushData() override {}
4856
4857public:
4858 SvNullStream() {}
4859};
4860
4861}
4862
4863EscherEx::EscherEx(std::shared_ptr<EscherExGlobal> xGlobal, SvStream* pOutStrm, bool bOOXML)
4864 : mxGlobal(std::move(xGlobal))
4865 , mpOutStrm(pOutStrm)
4866 , mnCurrentDg(0)
4867 , mnCountOfs(0)
4868 , mnGroupLevel(0)
4869 , mnHellLayerId(SDRLAYER_NOTFOUND)
4870 , mbEscherSpgr(false)
4871 , mbEscherDg(false)
4872 , mbOOXML(bOOXML)
4873{
4874 if (!mpOutStrm)
4875 {
4876 mxOwnStrm = std::make_unique<SvNullStream>();
4877 mpOutStrm = mxOwnStrm.get();
4878 }
4880 mpImplEESdrWriter.reset( new ImplEESdrWriter( *this ) );
4881}
4882
4884{
4885}
4886
4887void EscherEx::Flush( SvStream* pPicStreamMergeBSE /* = NULL */ )
4888{
4889 if ( !mxGlobal->HasDggContainer() )
4890 return;
4891
4892 // store the current stream position at ESCHER_Persist_CurrentPosition key
4894 if ( DoSeek( ESCHER_Persist_Dgg ) )
4895 {
4896 /* The DGG record is still not written. ESCHER_Persist_Dgg seeks
4897 to the place where the complete record has to be inserted. */
4898 InsertAtCurrentPos( mxGlobal->GetDggAtomSize() );
4899 mxGlobal->WriteDggAtom( *mpOutStrm );
4900
4901 if ( mxGlobal->HasGraphics() )
4902 {
4903 /* Calculate the total size of the BSTORECONTAINER including
4904 all BSE records containing the picture data contained in
4905 the passed in pPicStreamMergeBSE. */
4906 sal_uInt32 nBSCSize = mxGlobal->GetBlibStoreContainerSize( pPicStreamMergeBSE );
4907 if ( nBSCSize > 0 )
4908 {
4909 InsertAtCurrentPos( nBSCSize );
4910 mxGlobal->WriteBlibStoreContainer( *mpOutStrm, pPicStreamMergeBSE );
4911 }
4912 }
4913
4914 /* Forget the stream position stored for the DGG which is invalid
4915 after the call to InsertAtCurrentPos() anyway. */
4917 }
4918 // seek to initial position (may be different due to inserted DGG and BLIPs)
4920}
4921
4922void EscherEx::InsertAtCurrentPos( sal_uInt32 nBytes )
4923{
4924 sal_uInt32 nSize, nType, nSource, nBufSize, nToCopy, nCurPos = mpOutStrm->Tell();
4925
4926 // adjust persist table
4927 for(auto const & pPtr : maPersistTable) {
4928 sal_uInt32 nOfs = pPtr->mnOffset;
4929 if ( nOfs >= nCurPos ) {
4930 pPtr->mnOffset += nBytes;
4931 }
4932 }
4933
4934 // adapt container and atom sizes
4936 while ( mpOutStrm->Tell() < nCurPos )
4937 {
4938 mpOutStrm->ReadUInt32( nType ).ReadUInt32( nSize );
4939 sal_uInt32 nEndOfRecord = mpOutStrm->Tell() + nSize;
4940 bool bContainer = (nType & 0x0F) == 0x0F;
4941 /* Expand the record, if the insertion position is inside, or if the
4942 position is at the end of a container (expands always), or at the
4943 end of an atom and bExpandEndOfAtom is set. */
4944 if ( (nCurPos < nEndOfRecord) || ((nCurPos == nEndOfRecord) && bContainer) )
4945 {
4946 mpOutStrm->SeekRel( -4 );
4947 mpOutStrm->WriteUInt32( nSize + nBytes );
4948 if ( !bContainer )
4949 mpOutStrm->SeekRel( nSize );
4950 }
4951 else
4952 mpOutStrm->SeekRel( nSize );
4953 }
4954 for (auto & offset : mOffsets)
4955 {
4956 if ( offset > nCurPos )
4957 offset += nBytes;
4958 }
4959 nSource = mpOutStrm->TellEnd();
4960 nToCopy = nSource - nCurPos; // increase the size of the stream by nBytes
4961 std::unique_ptr<sal_uInt8[]> pBuf(new sal_uInt8[ 0x40000 ]); // 256KB Buffer
4962 while ( nToCopy )
4963 {
4964 nBufSize = ( nToCopy >= 0x40000 ) ? 0x40000 : nToCopy;
4965 nToCopy -= nBufSize;
4966 nSource -= nBufSize;
4967 mpOutStrm->Seek( nSource );
4968 mpOutStrm->ReadBytes(pBuf.get(), nBufSize);
4969 mpOutStrm->Seek( nSource + nBytes );
4970 mpOutStrm->WriteBytes(pBuf.get(), nBufSize);
4971 }
4972 mpOutStrm->Seek( nCurPos );
4973}
4974
4975void EscherEx::InsertPersistOffset( sal_uInt32 nKey, sal_uInt32 nOffset )
4976{
4977 PtInsert( ESCHER_Persist_PrivateEntry | nKey, nOffset );
4978}
4979
4980void EscherEx::ReplacePersistOffset( sal_uInt32 nKey, sal_uInt32 nOffset )
4981{
4982 PtReplace( ESCHER_Persist_PrivateEntry | nKey, nOffset );
4983}
4984
4985void EscherEx::SetEditAs( const OUString& rEditAs )
4986{
4987 mEditAs = rEditAs;
4988}
4989
4990sal_uInt32 EscherEx::GetPersistOffset( sal_uInt32 nKey )
4991{
4993}
4994
4995bool EscherEx::DoSeek( sal_uInt32 nKey )
4996{
4997 sal_uInt32 nPos = PtGetOffsetByID( nKey );
4998 if ( nPos )
4999 mpOutStrm->Seek( nPos );
5000 else
5001 {
5002 if (! PtIsID( nKey ) )
5003 return false;
5004 mpOutStrm->Seek( 0 );
5005 }
5006 return true;
5007}
5008
5009bool EscherEx::SeekToPersistOffset( sal_uInt32 nKey )
5010{
5011 return DoSeek( ESCHER_Persist_PrivateEntry | nKey );
5012}
5013
5014void EscherEx::InsertAtPersistOffset( sal_uInt32 nKey, sal_uInt32 nValue )
5015{
5016 sal_uInt32 nOldPos = mpOutStrm->Tell();
5017 bool bRetValue = SeekToPersistOffset( nKey );
5018 if ( bRetValue )
5019 {
5021 mpOutStrm->Seek( nOldPos );
5022 }
5023}
5024
5025void EscherEx::OpenContainer( sal_uInt16 nEscherContainer, int nRecInstance )
5026{
5027 mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | 0xf ).WriteUInt16( nEscherContainer ).WriteUInt32( 0 );
5028 mOffsets.push_back( mpOutStrm->Tell() - 4 );
5029 mRecTypes.push_back( nEscherContainer );
5030 switch( nEscherContainer )
5031 {
5032 case ESCHER_DggContainer :
5033 {
5034 mxGlobal->SetDggContainer();
5035 mnCurrentDg = 0;
5036 /* Remember the current position as start position of the DGG
5037 record and BSTORECONTAINER, but do not write them actually.
5038 This will be done later in Flush() when the number of drawings,
5039 the size and contents of the FIDCL cluster table, and the size
5040 of the BLIP container are known. */
5042 }
5043 break;
5044
5045 case ESCHER_DgContainer :
5046 {
5047 if ( mxGlobal->HasDggContainer() )
5048 {
5049 if ( !mbEscherDg )
5050 {
5051 mbEscherDg = true;
5052 mnCurrentDg = mxGlobal->GenerateDrawingId();
5053 AddAtom( 8, ESCHER_Dg, 0, mnCurrentDg );
5055 mpOutStrm->WriteUInt32( 0 ) // The number of shapes in this drawing
5056 .WriteUInt32( 0 ); // The last MSOSPID given to an SP in this DG
5057 }
5058 }
5059 }
5060 break;
5061
5063 {
5064 if ( mbEscherDg )
5065 {
5066 mbEscherSpgr = true;
5067 }
5068 }
5069 break;
5070
5071 case ESCHER_SpContainer :
5072 {
5073 }
5074 break;
5075
5076 default:
5077 break;
5078 }
5079}
5080
5082{
5083 sal_uInt32 nSize, nPos = mpOutStrm->Tell();
5084 nSize = ( nPos - mOffsets.back() ) - 4;
5085 mpOutStrm->Seek( mOffsets.back() );
5086 mpOutStrm->WriteUInt32( nSize );
5087
5088 switch( mRecTypes.back() )
5089 {
5090 case ESCHER_DgContainer :
5091 {
5092 if ( mbEscherDg )
5093 {
5094 mbEscherDg = false;
5096 mpOutStrm->WriteUInt32( mxGlobal->GetDrawingShapeCount( mnCurrentDg ) ).WriteUInt32( mxGlobal->GetLastShapeId( mnCurrentDg ) );
5097 }
5098 }
5099 break;
5100
5102 {
5103 if ( mbEscherSpgr )
5104 {
5105 mbEscherSpgr = false;
5106
5107 }
5108 }
5109 break;
5110
5111 default:
5112 break;
5113 }
5114 mOffsets.pop_back();
5115 mRecTypes.pop_back();
5116 mpOutStrm->Seek( nPos );
5117}
5118
5120{
5122 mpOutStrm->WriteUInt32( 0 ).WriteUInt32( 0 ); // record header will be written later
5123}
5124
5125void EscherEx::EndAtom( sal_uInt16 nRecType, int nRecVersion, int nRecInstance )
5126{
5127 sal_uInt32 nOldPos = mpOutStrm->Tell();
5129 sal_uInt32 nSize = nOldPos - mnCountOfs;
5130 mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | ( nRecVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nSize - 8 );
5131 mpOutStrm->Seek( nOldPos );
5132}
5133
5134void EscherEx::AddAtom( sal_uInt32 nAtomSize, sal_uInt16 nRecType, int nRecVersion, int nRecInstance )
5135{
5136 mpOutStrm->WriteUInt16( ( nRecInstance << 4 ) | ( nRecVersion & 0xf ) ).WriteUInt16( nRecType ).WriteUInt32( nAtomSize );
5137}
5138
5140{
5142 mpOutStrm ->WriteInt32( rRect.Left() )
5143 .WriteInt32( rRect.Top() )
5144 .WriteInt32( rRect.Right() )
5145 .WriteInt32( rRect.Bottom() );
5146}
5147
5149{
5151 mpOutStrm->WriteInt16( rRect.Top() )
5152 .WriteInt16( rRect.Left() )
5153 .WriteInt16( rRect.GetWidth() + rRect.Left() )
5154 .WriteInt16( rRect.GetHeight() + rRect.Top() );
5155}
5156
5158{
5159 return nullptr;
5160}
5161
5162sal_uInt32 EscherEx::EnterGroup( const OUString& rShapeName, const tools::Rectangle* pBoundRect )
5163{
5164 tools::Rectangle aRect;
5165 if( pBoundRect )
5166 aRect = *pBoundRect;
5167
5170 AddAtom( 16, ESCHER_Spgr, 1 );
5172 mpOutStrm->Tell() );
5173 mpOutStrm ->WriteInt32( aRect.Left() ) // Bounding box for the grouped shapes to which they will be attached
5174 .WriteInt32( aRect.Top() )
5175 .WriteInt32( aRect.IsWidthEmpty() ? aRect.Left() : aRect.Right() )
5176 .WriteInt32( aRect.IsHeightEmpty() ? aRect.Top() : aRect.Bottom() );
5177
5178 sal_uInt32 nShapeId = GenerateShapeId();
5179 if ( !mnGroupLevel )
5181 else
5182 {
5184 EscherPropertyContainer aPropOpt;
5185 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x00040004 );
5186 aPropOpt.AddOpt( ESCHER_Prop_dxWrapDistLeft, 0 );
5187 aPropOpt.AddOpt( ESCHER_Prop_dxWrapDistRight, 0 );
5188
5189 // #i51348# shape name
5190 if( rShapeName.getLength() > 0 )
5191 aPropOpt.AddOpt( ESCHER_Prop_wzName, rShapeName );
5192
5193 Commit( aPropOpt, aRect );
5194 if ( mnGroupLevel > 1 )
5195 AddChildAnchor( aRect );
5196
5197 EscherExHostAppData* pAppData = mpImplEESdrWriter->ImplGetHostData();
5198 if( pAppData )
5199 {
5200 if ( mnGroupLevel <= 1 )
5201 pAppData->WriteClientAnchor( *this, aRect );
5202 pAppData->WriteClientData( *this );
5203 }
5204 }
5205 CloseContainer(); // ESCHER_SpContainer
5206 mnGroupLevel++;
5207 return nShapeId;
5208}
5209
5210sal_uInt32 EscherEx::EnterGroup( const tools::Rectangle* pBoundRect )
5211{
5212 return EnterGroup( OUString(), pBoundRect );
5213}
5214
5215void EscherEx::SetGroupSnapRect( sal_uInt32 nGroupLevel, const tools::Rectangle& rRect )
5216{
5217 if ( nGroupLevel )
5218 {
5219 sal_uInt32 nCurrentPos = mpOutStrm->Tell();
5220 if ( DoSeek( ESCHER_Persist_Grouping_Snap | ( nGroupLevel - 1 ) ) )
5221 {
5222 mpOutStrm ->WriteInt32( rRect.Left() ) // Bounding box for the grouped shapes to which they will be attached
5223 .WriteInt32( rRect.Top() )
5224 .WriteInt32( rRect.Right() )
5225 .WriteInt32( rRect.Bottom() );
5226 mpOutStrm->Seek( nCurrentPos );
5227 }
5228 }
5229}
5230
5231void EscherEx::SetGroupLogicRect( sal_uInt32 nGroupLevel, const tools::Rectangle& rRect )
5232{
5233 if ( nGroupLevel )
5234 {
5235 sal_uInt32 nCurrentPos = mpOutStrm->Tell();
5236 if ( DoSeek( ESCHER_Persist_Grouping_Logic | ( nGroupLevel - 1 ) ) )
5237 {
5238 mpOutStrm->WriteInt16( rRect.Top() ).WriteInt16( rRect.Left() ).WriteInt16( rRect.Right() ).WriteInt16( rRect.Bottom() );
5239 mpOutStrm->Seek( nCurrentPos );
5240 }
5241 }
5242}
5243
5245{
5246 --mnGroupLevel;
5250}
5251
5252void EscherEx::AddShape( sal_uInt32 nShpInstance, ShapeFlag nFlags, sal_uInt32 nShapeID )
5253{
5254 AddAtom( 8, ESCHER_Sp, 2, nShpInstance );
5255
5256 if ( !nShapeID )
5257 nShapeID = GenerateShapeId();
5258
5259 if (nFlags ^ ShapeFlag::Group) // no pure group shape
5260 {
5261 if ( mnGroupLevel > 1 )
5262 nFlags |= ShapeFlag::Child; // this not a topmost shape
5263 }
5264 mpOutStrm->WriteUInt32( nShapeID ).WriteUInt32( static_cast<sal_uInt32>(nFlags) );
5265}
5266
5268{
5269 rProps.Commit( GetStream() );
5270}
5271
5272sal_uInt32 EscherEx::GetColor( const sal_uInt32 nSOColor )
5273{
5274 sal_uInt32 nColor = nSOColor & 0xff00; // Green
5275 nColor |= static_cast<sal_uInt8>(nSOColor) << 16; // Red
5276 nColor |= static_cast<sal_uInt8>( nSOColor >> 16 ); // Blue
5277 return nColor;
5278}
5279
5280sal_uInt32 EscherEx::GetColor( const Color& rSOColor )
5281{
5282 sal_uInt32 nColor = ( rSOColor.GetRed() << 16 );
5283 nColor |= ( rSOColor.GetGreen() << 8 );
5284 nColor |= rSOColor.GetBlue();
5285 nColor = GetColor( nColor );
5286 return nColor;
5287}
5288
5289/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SVXCORE_DLLPUBLIC sal_Int16 GetCustomShapeConnectionTypeDefault(MSO_SPT eSpType)
SVXCORE_DLLPUBLIC const mso_CustomShape * GetCustomShapeContent(MSO_SPT eSpType)
sal_Int32 nLineWidth
bool bHasShadow
GraphicFileFormat
static OutputDevice * GetDefaultDevice()
sal_uInt8 GetBlue() const
sal_uInt8 GetRed() const
sal_uInt8 GetGreen() const
sal_uInt32 mnSize
Definition: escherex.hxx:535
sal_uInt32 mnRefCount
Definition: escherex.hxx:537
MapMode maPrefMapMode
Definition: escherex.hxx:530
EscherBlibEntry(sal_uInt32 nPictureOffset, const GraphicObject &rObj, const OString &rId, const GraphicAttr *pAttr)
Definition: escherex.cxx:3896
sal_uInt32 mnPictureOffset
Definition: escherex.hxx:534
bool mbIsNativeGraphicPossible
Definition: escherex.hxx:543
sal_uInt32 mnIdentifier[4]
Definition: escherex.hxx:533
void WriteBlibEntry(SvStream &rSt, bool bWritePictureOffset, sal_uInt32 nResize=0)
Definition: escherex.cxx:3964
bool operator==(const EscherBlibEntry &) const
Definition: escherex.cxx:3994
sal_uInt32 mnSizeExtra
Definition: escherex.hxx:538
ESCHER_BlibType meBlibType
Definition: escherex.hxx:540
virtual ~EscherExClientAnchor_Base()
Definition: escherex.cxx:144
virtual ~EscherExClientRecord_Base()
Definition: escherex.cxx:140
bool mbPicStrmQueried
True = the DGGCONTAINER has been initialized.
Definition: escherex.hxx:1042
sal_uInt32 GetLastShapeId(sal_uInt32 nDrawingId) const
Returns the last shape identifier generated by the GenerateShapeId() function.
Definition: escherex.cxx:4788
void WriteDggAtom(SvStream &rStrm) const
Writes the complete DGG atom to the passed stream (overwrites existing data!).
Definition: escherex.cxx:4801
sal_uInt32 GenerateDrawingId()
Returns a new drawing ID for a new drawing container (DGCONTAINER).
Definition: escherex.cxx:4729
sal_uInt32 GetDggAtomSize() const
Returns the total size of the DGG atom (including header).
Definition: escherex.cxx:4795
virtual ~EscherExGlobal() override
Definition: escherex.cxx:4725
DrawingInfoVector maDrawingInfos
List with cluster IDs (used object IDs in drawings).
Definition: escherex.hxx:1039
SvStream * mpPicStrm
Data about all used drawings.
Definition: escherex.hxx:1040
sal_uInt32 GenerateShapeId(sal_uInt32 nDrawingId, bool bIsInSpgr)
Creates and returns a new shape identifier, updates the internal shape counters and registers the ide...
Definition: escherex.cxx:4742
sal_uInt32 GetDrawingShapeCount(sal_uInt32 nDrawingId) const
Returns the number of shapes in the current drawing, based on number of calls to the GenerateShapeId(...
Definition: escherex.cxx:4781
SvStream * QueryPictureStream()
Called if a picture shall be written and no picture stream is set at class ImplEESdrWriter.
Definition: escherex.cxx:4826
virtual SvStream * ImplQueryPictureStream()
Derived classes may implement to create a new stream used to store the picture data.
Definition: escherex.cxx:4836
std::vector< ClusterEntry > maClusterTable
Definition: escherex.hxx:1038
void WriteClientAnchor(EscherEx &rEx, const tools::Rectangle &rRect)
Definition: escherex.hxx:957
void WriteClientData(EscherEx &rEx)
Definition: escherex.hxx:959
void SetGroupLogicRect(sal_uInt32 nGroupLevel, const tools::Rectangle &rRect)
Definition: escherex.cxx:5231
sal_uInt32 mnGroupLevel
Definition: escherex.hxx:1063
sal_uInt32 GetPersistOffset(sal_uInt32 nKey)
Definition: escherex.cxx:4990
bool mbEscherSpgr
Definition: escherex.hxx:1066
sal_uInt32 mnCurrentDg
Definition: escherex.hxx:1060
virtual sal_uInt32 EnterGroup(const OUString &rShapeName, const tools::Rectangle *pBoundRect)
Definition: escherex.cxx:5162
bool SeekToPersistOffset(sal_uInt32 nKey)
Definition: escherex.cxx:5009
bool mbEscherDg
Definition: escherex.hxx:1067
sal_uInt32 mnCountOfs
Definition: escherex.hxx:1061
virtual void AddShape(sal_uInt32 nShpInstance, ShapeFlag nFlagIds, sal_uInt32 nShapeID=0)
Definition: escherex.cxx:5252
void AddAtom(sal_uInt32 nAtomSitze, sal_uInt16 nRecType, int nRecVersion=0, int nRecInstance=0)
Definition: escherex.cxx:5134
virtual EscherExHostAppData * EnterAdditionalTextGroup()
Called before an AdditionalText EnterGroup occurs.
Definition: escherex.cxx:5157
bool DoSeek(sal_uInt32 nKey)
Definition: escherex.cxx:4995
void SetGroupSnapRect(sal_uInt32 nGroupLevel, const tools::Rectangle &rRect)
Definition: escherex.cxx:5215
static sal_uInt32 GetColor(const sal_uInt32 nColor)
Definition: escherex.cxx:5272
SvStream * mpOutStrm
Definition: escherex.hxx:1055
void EndAtom(sal_uInt16 nRecType, int nRecVersion=0, int nRecInstance=0)
Definition: escherex.cxx:5125
void BeginAtom()
Definition: escherex.cxx:5119
void AddChildAnchor(const tools::Rectangle &rRectangle)
Definition: escherex.cxx:5139
virtual sal_uInt32 GenerateShapeId()
Creates and returns a new shape identifier, updates the internal shape counters and registers the ide...
Definition: escherex.hxx:1080
sal_uInt32 mnStrmStartOfs
Definition: escherex.hxx:1056
virtual ~EscherEx() override
Definition: escherex.cxx:4883
std::shared_ptr< EscherExGlobal > mxGlobal
Definition: escherex.hxx:1052
void SetEditAs(const OUString &rEditAs)
Definition: escherex.cxx:4985
virtual void OpenContainer(sal_uInt16 nEscherContainer, int nRecInstance=0)
Definition: escherex.cxx:5025
std::unique_ptr< ImplEESdrWriter > mpImplEESdrWriter
Definition: escherex.hxx:1053
void Flush(SvStream *pPicStreamMergeBSE=nullptr)
Inserts internal data into the EscherStream, this process may and has to be executed only once If pPi...
Definition: escherex.cxx:4887
void ReplacePersistOffset(sal_uInt32 nKey, sal_uInt32 nOffset)
Definition: escherex.cxx:4980
void InsertAtCurrentPos(sal_uInt32 nBytes)
Inserts the passed number of bytes at the current position of the output stream.
Definition: escherex.cxx:4922
void InsertPersistOffset(sal_uInt32 nKey, sal_uInt32 nOffset)
Definition: escherex.cxx:4975
OUString mEditAs
Definition: escherex.hxx:1069
virtual void Commit(EscherPropertyContainer &rProps, const tools::Rectangle &rRect)
Definition: escherex.cxx:5267
EscherEx(std::shared_ptr< EscherExGlobal > xGlobal, SvStream *pOutStrm, bool bOOXML=false)
Definition: escherex.cxx:4863
void InsertAtPersistOffset(sal_uInt32 nKey, sal_uInt32 nValue)
Definition: escherex.cxx:5014
SvStream & GetStream() const
Definition: escherex.hxx:1125
std::vector< sal_uInt32 > mOffsets
Definition: escherex.hxx:1057
std::unique_ptr< SvStream > mxOwnStrm
Definition: escherex.hxx:1054
std::vector< sal_uInt16 > mRecTypes
Definition: escherex.hxx:1058
virtual void LeaveGroup()
Definition: escherex.cxx:5244
void AddClientAnchor(const tools::Rectangle &rRectangle)
Definition: escherex.cxx:5148
virtual void CloseContainer()
Definition: escherex.cxx:5081
EscherGraphicProvider(EscherGraphicProviderFlags nFlags=EscherGraphicProviderFlags::NONE)
Definition: escherex.cxx:4004
bool GetPrefSize(const sal_uInt32 nBlibId, Size &rSize, MapMode &rMapMode)
Definition: escherex.cxx:4103
void WriteBlibStoreContainer(SvStream &rStrm, SvStream *pMergePicStreamBSE=nullptr)
Definition: escherex.cxx:4046
void SetNewBlipStreamOffset(sal_Int32 nOffset)
Definition: escherex.cxx:4013
sal_uInt32 ImplInsertBlib(EscherBlibEntry *p_EscherBlibEntry)
Definition: escherex.cxx:4021
const OUString & GetBaseURI() const
Definition: escherex.hxx:602
sal_uInt32 GetBlibStoreContainerSize(SvStream const *pMergePicStreamBSE=nullptr) const
Definition: escherex.cxx:4027
virtual ~EscherGraphicProvider()
Definition: escherex.cxx:4009
EscherGraphicProviderFlags mnFlags
Definition: escherex.hxx:574
std::vector< std::unique_ptr< EscherBlibEntry > > mvBlibEntrys
Definition: escherex.hxx:576
sal_uInt32 GetBlibID(SvStream &rPicOutStream, GraphicObject const &pGraphicObject, const css::awt::Rectangle *pVisArea=nullptr, const GraphicAttr *pGrafikAttr=nullptr, const bool ooxmlExport=false)
Definition: escherex.cxx:4115
void WriteBlibStoreEntry(SvStream &rStrm, sal_uInt32 nBlipId, sal_uInt32 nResize)
Definition: escherex.cxx:4038
void PtDelete(sal_uInt32 nID)
Definition: escherex.cxx:3801
bool PtIsID(sal_uInt32 nID)
Definition: escherex.cxx:3790
void PtInsert(sal_uInt32 nID, sal_uInt32 nOfs)
Definition: escherex.cxx:3796
sal_uInt32 PtGetOffsetByID(sal_uInt32 nID)
Definition: escherex.cxx:3809
::std::vector< std::unique_ptr< EscherPersistEntry > > maPersistTable
Definition: escherex.hxx:868
virtual ~EscherPersistTable()
Definition: escherex.cxx:3786
void PtReplace(sal_uInt32 nID, sal_uInt32 nOfs)
Definition: escherex.cxx:3819
void PtReplaceOrInsert(sal_uInt32 nID, sal_uInt32 nOfs)
Definition: escherex.cxx:3829
bool CreateGraphicProperties(const css::uno::Reference< css::drawing::XShape > &rXShape, const GraphicObject &rGraphicObj)
void CreateShapeProperties(const css::uno::Reference< css::drawing::XShape > &rXShape)
Definition: escherex.cxx:1307
static sal_uInt32 ImplGetColor(const sal_uInt32 rColor, bool bSwap=true)
Definition: escherex.cxx:353
bool CreateBlipPropertiesforOLEControl(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const css::uno::Reference< css::drawing::XShape > &rXShape)
Definition: escherex.cxx:3755
static void LookForPolarHandles(const MSO_SPT eShapeType, sal_Int32 &nAdjustmentsWhichNeedsToBeConverted)
Definition: escherex.cxx:2540
static MSO_SPT GetCustomShapeType(const css::uno::Reference< css::drawing::XShape > &rXShape, ShapeFlag &nMirrorFlags, OUString &rShapeType, bool bOOXML=false)
Definition: escherex.cxx:3697
void CreateShadowProperties(const css::uno::Reference< css::beans::XPropertySet > &)
Definition: escherex.cxx:2302
tools::Rectangle * pShapeBoundRect
Definition: escherex.hxx:666
bool CreateOLEGraphicProperties(const css::uno::Reference< css::drawing::XShape > &rXOleObject)
Definition: escherex.cxx:1333
bool CreateMediaGraphicProperties(const css::uno::Reference< css::drawing::XShape > &rXMediaObject)
Definition: escherex.cxx:1383
void AddOpt(sal_uInt16 nPropID, bool bBlib, sal_uInt32 nSizeReduction, SvMemoryStream &rStream)
Definition: escherex.cxx:176
void ImplCreateGraphicAttributes(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, sal_uInt32 nBlibId, bool bCreateCroppingAttributes)
Definition: escherex.cxx:1209
bool IsFontWork() const
Definition: escherex.cxx:346
std::vector< EscherPropSortStruct > pSortStruct
Definition: escherex.hxx:672
bool CreatePolygonProperties(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, sal_uInt32 nFlags, bool bBezier, css::awt::Rectangle &rGeoRect, tools::Polygon const *pPolygon=nullptr)
Definition: escherex.cxx:1850
void CreateGradientProperties(const css::awt::Gradient &rGradient)
static tools::PolyPolygon GetPolyPolygon(const css::uno::Reference< css::drawing::XShape > &rXShape)
EscherGraphicProvider * pGraphicProvider
Definition: escherex.hxx:664
static sal_uInt32 GetGradientColor(const css::awt::Gradient *pGradient, sal_uInt32 nStartColor)
Definition: escherex.cxx:366
void CreateEmbeddedHatchProperties(const css::drawing::Hatch &rHatch, const Color &rBackColor, bool bFillBackground)
Creates a complex ESCHER_Prop_fillBlip containing a hatch style (for Excel charts).
Definition: escherex.cxx:1465
bool CreateConnectorProperties(const css::uno::Reference< css::drawing::XShape > &rXShape, EscherSolverContainer &rSolver, css::awt::Rectangle &rGeoRect, sal_uInt16 &rShapeType, ShapeFlag &rShapeFlags)
Definition: escherex.cxx:2190
void CreateLineProperties(const css::uno::Reference< css::beans::XPropertySet > &, bool bEdge)
Definition: escherex.cxx:963
sal_Int32 GetValueForEnhancedCustomShapeParameter(const css::drawing::EnhancedCustomShapeParameter &rParameter, const std::vector< sal_Int32 > &rEquationOrder, bool bAdjustTrans=false)
Definition: escherex.cxx:2339
static bool GetAdjustmentValue(const css::drawing::EnhancedCustomShapeAdjustmentValue &rkProp, sal_Int32 nIndex, sal_Int32 nAdjustmentsWhichNeedsToBeConverted, sal_Int32 &nValue)
Definition: escherex.cxx:2558
bool GetOpt(sal_uInt16 nPropertyID, sal_uInt32 &rPropValue) const
Definition: escherex.cxx:271
bool ImplCreateEmbeddedBmp(GraphicObject const &rGraphicObject)
Definition: escherex.cxx:1398
void CreateTextProperties(const css::uno::Reference< css::beans::XPropertySet > &, sal_uInt32 nText, const bool bIsCustomShape=false, const bool bIsTextFrame=true)
Definition: escherex.cxx:672
void CreateFillProperties(const css::uno::Reference< css::beans::XPropertySet > &, bool bEdge, bool bTransparentGradient=false)
void CreateCustomShapeProperties(const MSO_SPT eShapeType, const css::uno::Reference< css::drawing::XShape > &)
Definition: escherex.cxx:2582
void Commit(SvStream &rSt, sal_uInt16 nVersion=3, sal_uInt16 nRecType=ESCHER_OPT)
Definition: escherex.cxx:318
const EscherProperties & GetOpts() const
Definition: escherex.cxx:296
static bool GetLineArrow(const bool bLineStart, const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, ESCHER_LineEnd &reLineEnd, sal_Int32 &rnArrowLength, sal_Int32 &rnArrowWidth)
Definition: escherex.cxx:862
void CreateEmbeddedBitmapProperties(css::uno::Reference< css::awt::XBitmap > const &rxBitmap, css::drawing::BitmapMode eBitmapMode)
Creates a complex ESCHER_Prop_fillBlip containing the BLIP directly (for Excel charts).
Definition: escherex.cxx:1414
static bool IsDefaultObject(const SdrObjCustomShape &rSdrObjCustomShape, const MSO_SPT eShapeType)
Definition: escherex.cxx:2516
sal_uInt32 GetShapeId(const css::uno::Reference< css::drawing::XShape > &rShape) const
Definition: escherex.cxx:4659
::std::vector< std::unique_ptr< EscherConnectorListEntry > > maConnectorList
Definition: escherex.hxx:616
::std::vector< std::unique_ptr< EscherShapeListEntry > > maShapeList
Definition: escherex.hxx:615
void AddShape(const css::uno::Reference< css::drawing::XShape > &, sal_uInt32 nId)
Definition: escherex.cxx:4643
void WriteSolver(SvStream &)
Definition: escherex.cxx:4669
void AddConnector(const css::uno::Reference< css::drawing::XShape > &, const css::awt::Point &rA, css::uno::Reference< css::drawing::XShape > const &, const css::awt::Point &rB, css::uno::Reference< css::drawing::XShape > const &rConB)
Definition: escherex.cxx:4648
void WindStart()
void Clear()
void SetPrefMapMode(const MapMode &rMapMode)
void Record(OutputDevice *pOutDev)
void SetPrefSize(const Size &rSize)
bool IsCropped() const
Degree10 GetRotation() const
short GetContrast() const
short GetChannelB() const
tools::Long GetTopCrop() const
double GetGamma() const
bool IsTransparent() const
bool IsSpecialDrawMode() const
tools::Long GetBottomCrop() const
tools::Long GetRightCrop() const
GraphicDrawMode GetDrawMode() const
bool IsMirrored() const
bool IsRotated() const
BmpMirrorFlags GetMirrorFlags() const
sal_uInt8 GetAlpha() const
short GetChannelG() const
short GetChannelR() const
bool IsAdjusted() const
tools::Long GetLeftCrop() const
bool IsInvert() const
short GetLuminance() const
static ErrCode Import(SvStream &rIStm, Graphic &rGraphic, ConvertDataFormat nFormat=ConvertDataFormat::Unknown)
static ErrCode Export(SvStream &rOStm, const Graphic &rGraphic, ConvertDataFormat nFormat)
sal_uInt16 GetExportFormatNumberForShortName(std::u16string_view rShortName)
static GraphicFilter & GetGraphicFilter()
ErrCode ExportGraphic(const Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat, const css::uno::Sequence< css::beans::PropertyValue > *pFilterData=nullptr)
GraphicType GetType() const
Graphic GetTransformedGraphic(const Size &rDestSize, const MapMode &rDestMap, const GraphicAttr &rAttr) const
OString GetUniqueID() const
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
OUString getOriginURL() const
GraphicType GetType() const
GfxLink GetGfxLink() const
bool IsAnimated() const
bool IsNone() const
bool IsGfxLink() const
static OUString GetRelURL(std::u16string_view rTheBaseURIRef, OUString const &rTheAbsURIRef, EncodeMechanism eEncodeMechanism=EncodeMechanism::WasEncoded, DecodeMechanism eDecodeMechanism=DecodeMechanism::ToIUri, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8, FSysStyle eStyle=FSysStyle::Detect)
MapUnit GetMapUnit() const
bool IsEffectivelyVertical() const
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
constexpr tools::Long Y() const
void setX(tools::Long nX)
void setY(tools::Long nY)
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
constexpr tools::Long X() const
css::uno::Any * GetPropertyValueByName(const OUString &rPropName)
static Graphic GetObjGraphic(const SdrObject &rSdrObject, bool bSVG=false)
sal_uInt16 GetCount() const
Point GetAbsolutePos(const SdrObject &rObj) const
bool IsDefaultGeometry(const DefaultType eDefaultType) const
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
const SfxPoolItem & GetMergedItem(const sal_uInt16 nWhich) const
const SfxItemSet & GetMergedItemSet() const
const basegfx::B2DPolyPolygon & GetPathPoly() const
virtual OutlinerParaObject * GetOutlinerParaObject() const override
constexpr tools::Long Height() const
constexpr tools::Long Width() const
const void * GetData()
sal_uInt64 GetSize()
virtual sal_uInt64 TellEnd() override
SvStream & WriteDouble(const double &rDouble)
SvStream & WriteInt32(sal_Int32 nInt32)
sal_uInt64 Tell() const
virtual sal_uInt64 TellEnd()
virtual sal_uInt64 SeekPos(sal_uInt64 nPos)
virtual void SetSize(sal_uInt64 nSize)
std::size_t WriteBytes(const void *pData, std::size_t nSize)
SvStream & WriteBool(bool b)
SvStream & WriteInt16(sal_Int16 nInt16)
SvStream & WriteUChar(unsigned char nChar)
SvStream & WriteUInt16(sal_uInt16 nUInt16)
virtual std::size_t GetData(void *pData, std::size_t nSize)
SvStream & WriteUInt32(sal_uInt32 nUInt32)
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
virtual std::size_t PutData(const void *pData, std::size_t nSize)
sal_uInt64 SeekRel(sal_Int64 nPos)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
virtual void FlushData()
sal_uInt16 GetSize() const
tools::Long EndCompression()
void BeginCompression(int nCompressLevel=ZCODEC_DEFAULT_COMPRESSION, bool gzLib=false)
void Write(SvStream &rOStm, const sal_uInt8 *pData, sal_uInt32 nSize)
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
sal_uInt32 count() const
sal_uInt32 count() const
sal_uInt16 Count() const
void Insert(const tools::Polygon &rPoly, sal_uInt16 nPos=POLYPOLY_APPEND)
const tools::Polygon & GetObject(sal_uInt16 nPos) const
tools::Rectangle GetBoundRect() const
void Insert(sal_uInt16 nPos, const Point &rPt)
PolyFlags GetFlags(sal_uInt16 nPos) const
sal_uInt16 GetSize() const
void Rotate(const Point &rCenter, double fSin, double fCos)
constexpr Point Center() const
constexpr tools::Long GetWidth() const
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr Size GetSize() const
constexpr tools::Long Right() const
constexpr bool IsWidthEmpty() const
constexpr tools::Long GetHeight() const
constexpr bool IsHeightEmpty() const
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
ColorTransparency
sal_Int32 nElements
int nCount
#define DBG_ASSERT(sCon, aError)
sal_uInt32 mnSize
float u
EmbeddedObjectRef * pObject
#define ERRCODE_NONE
static sal_Int32 lcl_GetConnectorAdjustValue(const XPolygon &rPoly, sal_uInt16 nIndex)
Definition: escherex.cxx:2081
static void ConvertEnhancedCustomShapeEquation(const SdrObjCustomShape &rSdrObjCustomShape, std::vector< EnhancedCustomShapeEquation > &rEquations, std::vector< sal_Int32 > &rEquationOrder)
Definition: escherex.cxx:2439
static bool lcl_GetAngle(tools::Polygon &rPoly, ShapeFlag &rShapeFlags, sal_Int32 &nAngle)
Definition: escherex.cxx:2145
static sal_Int32 lcl_GetAdjustValueCount(const XPolygon &rPoly)
Definition: escherex.cxx:2057
static void lcl_Rotate(Degree100 nAngle, Point center, Point &pt)
Definition: escherex.cxx:2109
static int EscherPropSortFunc(const void *p1, const void *p2)
Definition: escherex.cxx:303
static bool GetValueForEnhancedCustomShapeHandleParameter(sal_Int32 &nRetValue, const drawing::EnhancedCustomShapeParameter &rParameter)
Definition: escherex.cxx:2389
static Size lcl_SizeToEmu(Size aPrefSize, const MapMode &aPrefMapMode)
Definition: escherex.cxx:1199
#define ESCHER_Prop_cropFromRight
Definition: escherex.hxx:357
@ ESCHER_ShapeComplex
Definition: escherex.hxx:177
@ ESCHER_FillPicture
Definition: escherex.hxx:146
@ ESCHER_FillTexture
Definition: escherex.hxx:145
@ ESCHER_FillShadeShape
Definition: escherex.hxx:149
@ ESCHER_FillSolid
Definition: escherex.hxx:143
@ ESCHER_FillShadeCenter
Definition: escherex.hxx:148
@ ESCHER_FillShadeScale
Definition: escherex.hxx:150
#define ESCHER_Prop_pictureActive
Definition: escherex.hxx:364
#define ESCHER_CREATEPOLYGON_LINE
Definition: escherex.hxx:647
#define ESCHER_Prop_lineColor
Definition: escherex.hxx:393
#define ESCHER_Prop_pib
Definition: escherex.hxx:358
ESCHER_AnchorText
Definition: escherex.hxx:209
@ ESCHER_AnchorMiddleCentered
Definition: escherex.hxx:214
@ ESCHER_AnchorBottom
Definition: escherex.hxx:212
@ ESCHER_AnchorTopCentered
Definition: escherex.hxx:213
@ ESCHER_AnchorBottomCentered
Definition: escherex.hxx:215
@ ESCHER_AnchorMiddle
Definition: escherex.hxx:211
@ ESCHER_AnchorTop
Definition: escherex.hxx:210
#define ESCHER_Prop_shapePath
Definition: escherex.hxx:370
#define ESCHER_Prop_fillFocus
Definition: escherex.hxx:384
std::vector< EscherPropSortStruct > EscherProperties
Definition: escherex.hxx:660
#define ESCHER_Dgg
Definition: escherex.hxx:62
#define ESCHER_Prop_fillAngle
Definition: escherex.hxx:383
#define ESCHER_BSE
Definition: escherex.hxx:66
#define ESCHER_Prop_pibName
Definition: escherex.hxx:359
#define ESCHER_ConnectorRule
Definition: escherex.hxx:81
ESCHER_LineJoin
Definition: escherex.hxx:301
@ ESCHER_LineJoinMiter
Definition: escherex.hxx:303
@ ESCHER_LineJoinRound
Definition: escherex.hxx:304
@ ESCHER_LineJoinBevel
Definition: escherex.hxx:302
#define ESCHER_Prop_LockAgainstGrouping
Definition: escherex.hxx:337
#define ESCHER_Prop_lineStartArrowWidth
Definition: escherex.hxx:401
#define ESCHER_Prop_fNoFillHitTest
Definition: escherex.hxx:391
ESCHER_WrapMode
Definition: escherex.hxx:182
@ ESCHER_WrapNone
Definition: escherex.hxx:185
@ ESCHER_WrapSquare
Definition: escherex.hxx:183
#define ESCHER_ShpInst_StraightConnector1
Definition: escherex.hxx:112
#define ESCHER_Prop_lineJoinStyle
Definition: escherex.hxx:405
#define ESCHER_Prop_fshadowObscured
Definition: escherex.hxx:413
#define ESCHER_Prop_geoRight
Definition: escherex.hxx:368
#define ESCHER_Prop_FitTextToShape
Definition: escherex.hxx:348
#define ESCHER_Prop_fNoLineDrawDash
Definition: escherex.hxx:407
#define ESCHER_BlipFirst
Definition: escherex.hxx:67
#define ESCHER_Prop_wzName
Definition: escherex.hxx:422
#define ESCHER_Prop_lineStartArrowhead
Definition: escherex.hxx:399
#define ESCHER_ChildAnchor
Definition: escherex.hxx:77
@ ESCHER_LineEndCapSquare
Definition: escherex.hxx:311
@ ESCHER_LineEndCapFlat
Definition: escherex.hxx:312
@ ESCHER_LineEndCapRound
Definition: escherex.hxx:310
#define ESCHER_Prop_fillToTop
Definition: escherex.hxx:386
#define ESCHER_Prop_AnchorText
Definition: escherex.hxx:345
#define ESCHER_Dg
Definition: escherex.hxx:70
@ ESCHER_txflBtoT
Definition: escherex.hxx:236
@ ESCHER_txflTtoBA
Definition: escherex.hxx:235
#define ESCHER_Prop_shadowColor
Definition: escherex.hxx:409
#define ESCHER_Prop_adjust2Value
Definition: escherex.hxx:374
#define ESCHER_Prop_fillToLeft
Definition: escherex.hxx:385
#define ESCHER_Prop_WrapText
Definition: escherex.hxx:344
#define ESCHER_BstoreContainer
Definition: escherex.hxx:65
@ ESCHER_BlipFlagLinkToFile
Definition: escherex.hxx:253
@ ESCHER_BlipFlagFile
Definition: escherex.hxx:248
@ ESCHER_BlipFlagDoNotSave
Definition: escherex.hxx:252
#define ESCHER_Prop_lineStartArrowLength
Definition: escherex.hxx:402
#define ESCHER_Prop_txflTextFlow
Definition: escherex.hxx:346
#define ESCHER_Prop_gtextSize
Definition: escherex.hxx:351
#define ESCHER_Persist_CurrentPosition
Definition: escherex.hxx:438
#define ESCHER_DgContainer
Definition: escherex.hxx:69
#define ESCHER_Prop_fillToBottom
Definition: escherex.hxx:388
#define ESCHER_ShpInst_Min
Definition: escherex.hxx:105
#define ESCHER_Spgr
Definition: escherex.hxx:73
#define ESCHER_Persist_PrivateEntry
Definition: escherex.hxx:435
#define ESCHER_Prop_Rotation
Definition: escherex.hxx:335
const sal_uInt32 DFF_DGG_CLUSTER_SIZE
Definition: escherex.hxx:442
#define ESCHER_Prop_cropFromTop
Definition: escherex.hxx:354
#define ESCHER_Prop_dxWrapDistLeft
Definition: escherex.hxx:425
#define ESCHER_Sp
Definition: escherex.hxx:74
#define ESCHER_ShpInst_BentConnector2
Definition: escherex.hxx:113
#define ESCHER_Persist_Grouping_Snap
Definition: escherex.hxx:439
#define ESCHER_Prop_lineOpacity
Definition: escherex.hxx:394
@ ESCHER_cxstyleCurved
Definition: escherex.hxx:227
@ ESCHER_cxstyleStraight
Definition: escherex.hxx:225
@ ESCHER_cxstyleBent
Definition: escherex.hxx:226
#define ESCHER_Prop_pictureBrightness
Definition: escherex.hxx:362
#define ESCHER_Prop_shadowOffsetY
Definition: escherex.hxx:412
#define ESCHER_SolverContainer
Definition: escherex.hxx:80
#define ESCHER_Prop_fillToRight
Definition: escherex.hxx:387
#define ESCHER_Prop_lineEndCapStyle
Definition: escherex.hxx:406
#define ESCHER_Prop_lineBackColor
Definition: escherex.hxx:395
#define ESCHER_Prop_dxWrapDistRight
Definition: escherex.hxx:427
ESCHER_LineDashing
Definition: escherex.hxx:258
@ ESCHER_LineDashSys
Definition: escherex.hxx:260
@ ESCHER_LineLongDashDotDotGEL
Definition: escherex.hxx:269
@ ESCHER_LineDotGEL
Definition: escherex.hxx:264
@ ESCHER_LineDashGEL
Definition: escherex.hxx:265
@ ESCHER_LineDashDotSys
Definition: escherex.hxx:262
@ ESCHER_LineDashDotDotSys
Definition: escherex.hxx:263
@ ESCHER_LineDotSys
Definition: escherex.hxx:261
@ ESCHER_LineLongDashGEL
Definition: escherex.hxx:266
@ ESCHER_LineDashDotGEL
Definition: escherex.hxx:267
@ ESCHER_LineSolid
Definition: escherex.hxx:259
@ ESCHER_LineLongDashDotGEL
Definition: escherex.hxx:268
#define ESCHER_Prop_dxTextLeft
Definition: escherex.hxx:340
#define ESCHER_ClientAnchor
Definition: escherex.hxx:78
#define ESCHER_Prop_lineWidth
Definition: escherex.hxx:396
@ msopathCurveTo
Definition: escherex.hxx:318
@ msopathClose
Definition: escherex.hxx:320
@ msopathMoveTo
Definition: escherex.hxx:319
@ msopathEscape
Definition: escherex.hxx:322
@ msopathEnd
Definition: escherex.hxx:321
#define ESCHER_Prop_pibFlags
Definition: escherex.hxx:360
#define ESCHER_Persist_Grouping_Logic
Definition: escherex.hxx:440
#define ESCHER_Prop_pSegmentInfo
Definition: escherex.hxx:372
#define ESCHER_SpgrContainer
Definition: escherex.hxx:71
#define ESCHER_Prop_geoBottom
Definition: escherex.hxx:369
#define ESCHER_Prop_dyTextTop
Definition: escherex.hxx:341
#define ESCHER_Prop_cropFromLeft
Definition: escherex.hxx:356
#define ESCHER_Prop_fillBackColor
Definition: escherex.hxx:380
#define ESCHER_Prop_cxstyle
Definition: escherex.hxx:418
#define ESCHER_Prop_pVertices
Definition: escherex.hxx:371
#define ESCHER_Prop_fillBlip
Definition: escherex.hxx:382
#define ESCHER_ShpInst_BentConnector3
Definition: escherex.hxx:114
#define ESCHER_Prop_lineEndArrowLength
Definition: escherex.hxx:404
#define ESCHER_Prop_lineEndArrowWidth
Definition: escherex.hxx:403
#define ESCHER_Persist_Dgg
Definition: escherex.hxx:436
#define ESCHER_Prop_cropFromBottom
Definition: escherex.hxx:355
#define ESCHER_Prop_fFillOK
Definition: escherex.hxx:375
#define ESCHER_Prop_dyTextBottom
Definition: escherex.hxx:343
#define ESCHER_Prop_fPrint
Definition: escherex.hxx:432
EscherGraphicProviderFlags
Definition: escherex.hxx:563
#define ESCHER_Persist_Dg
Definition: escherex.hxx:437
#define ESCHER_Prop_lTxid
Definition: escherex.hxx:339
#define ESCHER_ShpInst_CurvedConnector3
Definition: escherex.hxx:115
#define ESCHER_Prop_shadowOffsetX
Definition: escherex.hxx:411
#define ESCHER_Prop_fillType
Definition: escherex.hxx:377
#define ESCHER_Prop_adjustValue
Definition: escherex.hxx:373
#define ESCHER_Prop_shadowOpacity
Definition: escherex.hxx:410
ESCHER_BlibType
Definition: escherex.hxx:127
@ EMF
Definition: escherex.hxx:130
@ PICT
Definition: escherex.hxx:132
@ WMF
Definition: escherex.hxx:131
@ UNKNOWN
Definition: escherex.hxx:129
@ PNG
Definition: escherex.hxx:134
@ PEG
Definition: escherex.hxx:133
ShapeFlag
Definition: escherex.hxx:85
@ HaveShapeProperty
#define ESCHER_Prop_fillOpacity
Definition: escherex.hxx:379
#define ESCHER_Prop_pictureContrast
Definition: escherex.hxx:361
#define ESCHER_SpContainer
Definition: escherex.hxx:72
#define ESCHER_Prop_lineEndArrowhead
Definition: escherex.hxx:400
ESCHER_LineEnd
Definition: escherex.hxx:274
@ ESCHER_LineArrowOvalEnd
Definition: escherex.hxx:279
@ ESCHER_LineArrowStealthEnd
Definition: escherex.hxx:277
@ ESCHER_LineArrowOpenEnd
Definition: escherex.hxx:280
@ ESCHER_LineArrowDiamondEnd
Definition: escherex.hxx:278
@ ESCHER_LineArrowEnd
Definition: escherex.hxx:276
#define ESCHER_Prop_dxTextRight
Definition: escherex.hxx:342
#define ESCHER_DggContainer
Definition: escherex.hxx:61
#define ESCHER_Prop_fillBackOpacity
Definition: escherex.hxx:381
#define ESCHER_Prop_fillColor
Definition: escherex.hxx:378
#define ESCHER_Prop_lineDashing
Definition: escherex.hxx:398
sal_Int16 nVersion
UNKNOWN
DocumentType eType
sal_Int16 nValue
FuncFlags mnFlags
GraphicType
sal_Int32 nIndex
uno_Any a
sal_uInt16 nPos
Sequence< sal_Int8 > aSeq
#define SAL_WARN_IF(condition, area, stream)
aBuf
std::unique_ptr< sal_Int32[]> pData
int n2
int n1
#define DFF_Prop_fc3DFillHarsh
#define DFF_Prop_pibFlags
#define DFF_Prop_cdirFont
#define DFF_Prop_c3DOriginY
#define DFF_Prop_c3DOriginX
#define DFF_Prop_pibName
#define DFF_Prop_gtextUNICODE
#define DFF_Prop_c3DExtrusionColor
#define DFF_Prop_pFormulas
#define DFF_Prop_c3DTolerance
#define DFF_Prop_pSegmentInfo
#define DFF_Prop_stretchPointX
#define DFF_Prop_c3DXViewpoint
#define DFF_Prop_c3DDiffuseAmt
#define DFF_Prop_geoTop
MSO_GeoTextAlign
mso_alignTextCenter
mso_alignTextRight
mso_alignTextLeft
mso_alignTextStretch
mso_alignTextWordJust
use_gtextFShrinkFit
gtextFShrinkFit
gtextFBestFit
gtextFStretch
use_gtextFStretch
use_gtextFBestFit
#define DFF_Prop_geoRight
#define DFF_Prop_c3DRotationCenterY
#define DFF_Prop_c3DFillZ
#define DFF_Prop_pib
#define DFF_Prop_c3DShininess
#define DFF_Prop_fFillOK
#define DFF_Prop_c3DYRotationAngle
#define DFF_Prop_connectorPoints
#define DFF_Prop_c3DExtrudeBackward
#define DFF_Prop_c3DKeyX
#define DFF_Prop_c3DRenderMode
#define DFF_Prop_gtextFont
#define DFF_Prop_c3DKeyZ
#define DFF_Prop_c3DSkewAmount
#define DFF_Prop_c3DYViewpoint
#define DFF_Prop_geoLeft
#define DFF_Prop_stretchPointY
#define DFF_Prop_c3DAmbientIntensity
#define DFF_Prop_c3DFillIntensity
#define DFF_Prop_adjustValue
#define DFF_Prop_c3DRotationCenterZ
mso_cdir90
mso_cdir180
mso_cdir270
#define DFF_Prop_connectorType
MSO_SPT
mso_sptTearDrop
mso_sptNil
#define DFF_Prop_geoBottom
#define DFF_Prop_Handles
#define DFF_Prop_fc3DLightFace
#define DFF_Prop_gtextFStrikethrough
#define DFF_Prop_c3DRotationCenterX
#define DFF_Prop_c3DXRotationAngle
#define DFF_Prop_pVertices
#define DFF_Prop_c3DFillX
#define DFF_Prop_c3DSkewAngle
#define DFF_Prop_gtextAlign
#define DFF_Prop_gtextSpacing
#define DFF_Prop_c3DKeyIntensity
#define DFF_Prop_c3DZViewpoint
#define DFF_Prop_c3DExtrudeForward
#define DFF_Prop_c3DKeyY
mso_FullRender
mso_Wireframe
#define DFF_Prop_c3DSpecularAmt
#define DFF_Prop_c3DFillY
#define DFF_Prop_textRectangles
SVXCORE_DLLPUBLIC MSO_SPT Get(const OUString &)
SVXCORE_DLLPUBLIC void FillEquationParameter(const css::drawing::EnhancedCustomShapeParameter &, const sal_Int32, EnhancedCustomShapeEquation &)
NONE
B2DPolygon UnoPointSequenceToB2DPolygon(const css::drawing::PointSequence &rPointSequenceSource)
B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon(const css::drawing::PointSequenceSequence &rPointSequenceSequenceSource)
B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon(const css::drawing::PolyPolygonBezierCoords &rPolyPolygonBezierCoordsSource)
B2IRange fround(const B2DRange &rRange)
sal_Int32 getTokenCount(std::string_view rIn, char cTok)
int i
Definition: gentoken.py:48
void SvStream & rStrm
OUString aPropName
MSO_SPT GETVMLShapeType(std::u16string_view aType)
Similar to EnhancedCustomShapeTypeNames::Get(), but returns an MSO_SPT (binary / VML type).
Definition: util.cxx:1025
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
sal_Int16 nId
#define Y
#define POLY_APPEND
QPRO_FUNC_TYPE nType
#define STREAM_SEEK_TO_BEGIN
css::awt::Point maPointB
Definition: escherex.hxx:460
css::awt::Point maPointA
Definition: escherex.hxx:458
sal_uInt32 GetConnectorRule(bool bFirst)
Definition: escherex.cxx:4405
css::uno::Reference< css::drawing::XShape > mXConnectToB
Definition: escherex.hxx:461
css::uno::Reference< css::drawing::XShape > mXConnectToA
Definition: escherex.hxx:459
static sal_uInt32 GetClosestPoint(const tools::Polygon &rPoly, const css::awt::Point &rP)
Definition: escherex.cxx:4380
SvStream & rStrm
Definition: escherex.hxx:493
EscherExAtom(SvStream &rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance=0, const sal_uInt8 nVersion=0)
Definition: escherex.cxx:122
sal_uInt32 nContPos
Definition: escherex.hxx:492
SvStream & rStrm
Definition: escherex.hxx:483
sal_uInt32 nContPos
Definition: escherex.hxx:482
EscherExContainer(SvStream &rSt, const sal_uInt16 nRecType, const sal_uInt16 nInstance=0)
Definition: escherex.cxx:104
sal_uInt32 mnNextShapeId
Identifier of drawing this cluster belongs to (one-based index into maDrawingInfos).
Definition: escherex.hxx:1025
sal_uInt32 mnShapeCount
Currently used cluster (one-based index into maClusterTable).
Definition: escherex.hxx:1032
sal_uInt32 mnLastShapeId
Current number of shapes in this drawing.
Definition: escherex.hxx:1033
sal_uInt32 nPropValue
Definition: escherex.hxx:656
static css::beans::PropertyState GetPropertyState(const css::uno::Reference< css::beans::XPropertySet > &, const OUString &rPropertyName)
Definition: escherex.cxx:3878
static bool GetPropertyValue(css::uno::Any &rAny, const css::uno::Reference< css::beans::XPropertySet > &, const OUString &rPropertyName, bool bTestPropertyAvailability=false)
Definition: escherex.cxx:3840
EscherShapeListEntry(uno::Reference< drawing::XShape > xShape, sal_uInt32 nId)
Definition: escherex.cxx:4374
sal_uInt32 n_EscherId
Definition: escherex.cxx:4372
uno::Reference< drawing::XShape > aXShape
Definition: escherex.cxx:4371
sal_uInt32 nHandles
SvxMSDffHandle * pHandles
UNDERLYING_TYPE get() const
bool hasValue()
Object Value
constexpr TypedWhichId< SdrTextFitToSizeTypeItem > SDRATTR_TEXT_FITTOSIZE(SDRATTR_MISC_FIRST+3)
constexpr TypedWhichId< SdrCustomShapeGeometryItem > SDRATTR_CUSTOMSHAPE_GEOMETRY(SDRATTR_CUSTOMSHAPE_FIRST+2)
SVXCORE_DLLPUBLIC Degree100 NormAngle36000(Degree100 a)
constexpr SdrLayerID SDRLAYER_NOTFOUND(-1)
bool bVisible
unsigned char sal_uInt8
#define SAL_MIN_INT16
#define SAL_MAX_INT16
sal_uInt16 sal_Unicode
signed char sal_Int8
SVXCORE_DLLPUBLIC OUString SvxUnogetApiNameForItem(const sal_uInt16 nWhich, const OUString &rInternalName)
HatchStyle
std::vector< ISegmentProgressBarRef > aSegments
constexpr TypedWhichId< XLineEndItem > XATTR_LINEEND(XATTR_LINE_FIRST+5)
constexpr TypedWhichId< XLineStartItem > XATTR_LINESTART(XATTR_LINE_FIRST+4)